@try-works/dsh-recursive-mode 0.1.4 → 0.1.6
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/lib/bootstrap.d.ts +6 -3
- package/lib/client/board.d.ts +4 -1
- package/lib/client/open-state.d.ts +20 -0
- package/lib/client/slots.d.ts +7 -1
- package/lib/client.js +135 -47
- package/lib/fs-intent.d.ts +34 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3429 -911
- package/lib/policy.d.ts +1 -1
- package/lib/runtime.d.ts +12 -5
- package/lib/ts-lint.d.ts +205 -0
- package/package.json +1 -1
- package/src/bootstrap.ts +338 -331
- package/src/client/board.tsx +0 -0
- package/src/client/open-state.ts +46 -0
- package/src/client/slots.ts +41 -20
- package/src/commands.ts +11 -0
- package/src/fs-intent.ts +84 -0
- package/src/index.ts +238 -226
- package/src/policy.ts +1 -1
- package/src/runtime.ts +19 -23
- package/src/ts-lint.ts +2110 -0
- package/references/scripts/__pycache__/recursive_phase_rules.cpython-314.pyc +0 -0
- package/references/scripts/lint-recursive-run.ps1 +0 -25
- package/references/scripts/lint-recursive-run.py +0 -2870
- package/references/scripts/recursive-closeout.ps1 +0 -38
- package/references/scripts/recursive-closeout.py +0 -541
- package/references/scripts/recursive-init.ps1 +0 -515
- package/references/scripts/recursive-init.py +0 -356
- package/references/scripts/recursive-lock.ps1 +0 -26
- package/references/scripts/recursive-lock.py +0 -302
- package/references/scripts/recursive-review-bundle.ps1 +0 -58
- package/references/scripts/recursive-review-bundle.py +0 -503
- package/references/scripts/recursive-router-cli-configure.ps1 +0 -2
- package/references/scripts/recursive-router-cli-configure.py +0 -9
- package/references/scripts/recursive-router-cli-init.ps1 +0 -2
- package/references/scripts/recursive-router-cli-init.py +0 -9
- package/references/scripts/recursive-router-cli-invoke.ps1 +0 -2
- package/references/scripts/recursive-router-cli-invoke.py +0 -9
- package/references/scripts/recursive-router-cli-probe.ps1 +0 -2
- package/references/scripts/recursive-router-cli-probe.py +0 -9
- package/references/scripts/recursive-router-cli-resolve.ps1 +0 -2
- package/references/scripts/recursive-router-cli-resolve.py +0 -9
- package/references/scripts/recursive-router-cli-validate.ps1 +0 -2
- package/references/scripts/recursive-router-cli-validate.py +0 -9
- package/references/scripts/recursive-router-configure.ps1 +0 -27
- package/references/scripts/recursive-router-configure.py +0 -74
- package/references/scripts/recursive-router-init.ps1 +0 -17
- package/references/scripts/recursive-router-init.py +0 -29
- package/references/scripts/recursive-router-invoke.ps1 +0 -47
- package/references/scripts/recursive-router-invoke.py +0 -103
- package/references/scripts/recursive-router-probe.ps1 +0 -25
- package/references/scripts/recursive-router-probe.py +0 -44
- package/references/scripts/recursive-router-resolve.ps1 +0 -26
- package/references/scripts/recursive-router-resolve.py +0 -46
- package/references/scripts/recursive-router-validate.ps1 +0 -17
- package/references/scripts/recursive-router-validate.py +0 -27
- package/references/scripts/recursive-status.ps1 +0 -23
- package/references/scripts/recursive-status.py +0 -2124
- package/references/scripts/recursive-subagent-action.ps1 +0 -98
- package/references/scripts/recursive-subagent-action.py +0 -197
- package/references/scripts/recursive-training-extract.ps1 +0 -23
- package/references/scripts/recursive-training-extract.py +0 -99
- package/references/scripts/recursive-training-grpo.ps1 +0 -52
- package/references/scripts/recursive-training-grpo.py +0 -1341
- package/references/scripts/recursive-training-loader.ps1 +0 -78
- package/references/scripts/recursive-training-loader.py +0 -558
- package/references/scripts/recursive-training-mcp.ps1 +0 -29
- package/references/scripts/recursive-training-mcp.py +0 -261
- package/references/scripts/recursive-training-phase8-trigger.ps1 +0 -55
- package/references/scripts/recursive-training-phase8-trigger.py +0 -137
- package/references/scripts/recursive-training-sync.ps1 +0 -29
- package/references/scripts/recursive-training-sync.py +0 -183
- package/references/scripts/recursive_phase_rules.py +0 -367
- package/references/scripts/recursive_router_cli_lib.py +0 -2
- package/references/scripts/recursive_router_lib.py +0 -2282
- package/references/scripts/verify-locks.ps1 +0 -25
- package/references/scripts/verify-locks.py +0 -353
- package/scripts/__pycache__/lint-recursive-run.cpython-314.pyc +0 -0
- package/scripts/__pycache__/recursive_phase_rules.cpython-314.pyc +0 -0
- package/scripts/install-recursive-mode.ps1 +0 -956
- package/scripts/install-recursive-mode.py +0 -750
- package/scripts/lint-recursive-run.py +0 -2870
- package/scripts/recursive-closeout.py +0 -541
- package/scripts/recursive-init.py +0 -356
- package/scripts/recursive-lock.py +0 -302
- package/scripts/recursive-status.py +0 -2124
- package/scripts/recursive_phase_rules.py +0 -367
- package/scripts/recursive_router_lib.py +0 -2282
- package/scripts/verify-locks.py +0 -353
package/lib/bootstrap.d.ts
CHANGED
|
@@ -35,8 +35,11 @@ export interface StageBInput {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Stage B workflow init at agent/session-start. New: bootstrap if missing +
|
|
38
|
-
* enumerate runs. Resume:
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* enumerate runs. Resume: idempotent REPAIR (not a full re-bootstrap) — the
|
|
39
|
+
* upsert-only bootstrapScaffold adds missing control-plane files/dirs and
|
|
40
|
+
* re-upserts marked blocks WITHOUT overwriting user content or touching run/
|
|
41
|
+
* artifacts, then enumerates + notes the active run. The repair is safe on
|
|
42
|
+
* fresh, partial, AND complete scaffolds (run 09 R3/R6). Always scoped to the
|
|
43
|
+
* given control-plane root.
|
|
41
44
|
*/
|
|
42
45
|
export declare function stageBWorkflowInit(input: StageBInput): StageBResult;
|
package/lib/client/board.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { RecursiveProjection, RecursiveRunCard } from '../types.ts';
|
|
2
2
|
import type { LiveProjectionValue } from './contract.ts';
|
|
3
|
+
import type { BoardSelection } from './open-state.ts';
|
|
3
4
|
/** Flatten the worktree-grouped projection into a stable run list. */
|
|
4
5
|
export declare function listRuns(projection: RecursiveProjection | undefined): RecursiveRunCard[];
|
|
5
6
|
export interface BoardProps {
|
|
6
7
|
/** The live host-route snapshot (null = not loaded / no recursive root). */
|
|
7
8
|
snapshot: LiveProjectionValue | null;
|
|
9
|
+
/** Opens the drill-down inspector for a run (R3). */
|
|
10
|
+
onOpenInspector?: (selection: BoardSelection) => void;
|
|
8
11
|
}
|
|
9
|
-
export declare function Board({ snapshot }: BoardProps): import("react").DetailedReactHTMLElement<{
|
|
12
|
+
export declare function Board({ snapshot, onOpenInspector }: BoardProps): import("react").DetailedReactHTMLElement<{
|
|
10
13
|
className: string;
|
|
11
14
|
}, HTMLElement> | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface BoardSelection {
|
|
2
|
+
worktreeRoot: string;
|
|
3
|
+
runId: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BoardState {
|
|
6
|
+
open: boolean;
|
|
7
|
+
selection: BoardSelection | null;
|
|
8
|
+
}
|
|
9
|
+
export interface BoardOpenState {
|
|
10
|
+
get(): BoardState;
|
|
11
|
+
openBoard(): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
openInspector(selection: BoardSelection): void;
|
|
14
|
+
backToBoard(): void;
|
|
15
|
+
subscribe(fn: () => void): () => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function createBoardState(initial?: BoardState): BoardOpenState;
|
|
18
|
+
/** App-wide singleton shared by the launcher, overlay, board, and inspector. */
|
|
19
|
+
export declare const boardState: BoardOpenState;
|
|
20
|
+
export declare function useBoardState(store?: BoardOpenState): BoardState;
|
package/lib/client/slots.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import type { ClientContext } from './contract.ts';
|
|
1
|
+
import type { ClientContext, ISessionsLike } from './contract.ts';
|
|
2
2
|
import { isRecursivePreset, currentSessionCwd } from './contract.ts';
|
|
3
|
+
export type OverlayContent = 'hidden' | 'board' | 'inspector';
|
|
4
|
+
/** Gate: hidden unless open AND recursive preset; inspector when a run is selected. */
|
|
5
|
+
export declare function overlayContent(state: {
|
|
6
|
+
open: boolean;
|
|
7
|
+
selection: unknown;
|
|
8
|
+
}, sessions: ISessionsLike): OverlayContent;
|
|
3
9
|
export declare function registerSlots(ctx: ClientContext): () => void;
|
|
4
10
|
/** Export the gate helpers for tests. */
|
|
5
11
|
export { isRecursivePreset, currentSessionCwd };
|
package/lib/client.js
CHANGED
|
@@ -224,13 +224,17 @@ window.__ModuleLoader__.load({
|
|
|
224
224
|
//#endregion
|
|
225
225
|
//#region src/client/board.tsx
|
|
226
226
|
/**
|
|
227
|
-
* Board overlay (SP2 R1): the kanban view over the live host-route
|
|
228
|
-
* Pure read-only renderer — no filesystem, no run-file scraping.
|
|
229
|
-
* grouped by worktree root (the projection's outer key) and mapped to
|
|
230
|
-
* current-phase lane via derive.columnForRun. Renders NOTHING when the
|
|
231
|
-
* is null (no recursive root / not loaded) or the current session is
|
|
232
|
-
* recursive preset (the gate lives in slots.ts — here an empty
|
|
233
|
-
* a null root is a no-op, not an "empty board").
|
|
227
|
+
* Board overlay (SP2 R1 + run 08 R3): the kanban view over the live host-route
|
|
228
|
+
* projection. Pure read-only renderer — no filesystem, no run-file scraping.
|
|
229
|
+
* Cards are grouped by worktree root (the projection's outer key) and mapped to
|
|
230
|
+
* their current-phase lane via derive.columnForRun. Renders NOTHING when the
|
|
231
|
+
* snapshot is null (no recursive root / not loaded) or the current session is
|
|
232
|
+
* not on the recursive preset (the gate lives in slots.ts — here an empty
|
|
233
|
+
* projection with a null root is a no-op, not an "empty board").
|
|
234
|
+
*
|
|
235
|
+
* Run 08 R3: a card click opens the drill-down inspector via onOpenInspector
|
|
236
|
+
* (the overlay swaps board <-> inspector in slots.ts). Read-only still: the
|
|
237
|
+
* callback only selects a run for display; no mutation.
|
|
234
238
|
*/
|
|
235
239
|
/** Flatten the worktree-grouped projection into a stable run list. */
|
|
236
240
|
function listRuns(projection) {
|
|
@@ -239,13 +243,17 @@ window.__ModuleLoader__.load({
|
|
|
239
243
|
for (const worktreeRoot of Object.keys(projection)) for (const runId of Object.keys(projection[worktreeRoot])) runs.push(projection[worktreeRoot][runId]);
|
|
240
244
|
return runs;
|
|
241
245
|
}
|
|
242
|
-
function Board({ snapshot }) {
|
|
246
|
+
function Board({ snapshot, onOpenInspector }) {
|
|
243
247
|
if (snapshot === null || snapshot.root === null) return null;
|
|
244
248
|
const runs = listRuns(snapshot.projection);
|
|
245
249
|
if (runs.length === 0) return (0, react.createElement)("div", {
|
|
246
250
|
className: "rec-board",
|
|
247
251
|
"data-empty": true
|
|
248
252
|
}, (0, react.createElement)("p", { className: "rec-board-empty" }, "No recursive runs in this workspace yet."));
|
|
253
|
+
const open = (run) => () => onOpenInspector?.({
|
|
254
|
+
worktreeRoot: run.worktreeRoot,
|
|
255
|
+
runId: run.runId
|
|
256
|
+
});
|
|
249
257
|
return (0, react.createElement)("div", { className: "rec-board" }, KANBAN_LANES.map((lane) => {
|
|
250
258
|
const laneRuns = runs.filter((r) => columnForRun(r) === lane.id);
|
|
251
259
|
return (0, react.createElement)("section", {
|
|
@@ -255,7 +263,8 @@ window.__ModuleLoader__.load({
|
|
|
255
263
|
const facts = cardFacts(run);
|
|
256
264
|
return (0, react.createElement)("article", {
|
|
257
265
|
key: run.worktreeRoot + "\0" + run.runId,
|
|
258
|
-
className: "rec-card"
|
|
266
|
+
className: "rec-card",
|
|
267
|
+
onClick: open(run)
|
|
259
268
|
}, (0, react.createElement)("div", { className: "rec-card-head" }, (0, react.createElement)("strong", {}, run.runId), facts.tampered && (0, react.createElement)("span", {
|
|
260
269
|
className: "rec-badge rec-badge-tamper",
|
|
261
270
|
title: "tampered"
|
|
@@ -267,6 +276,26 @@ window.__ModuleLoader__.load({
|
|
|
267
276
|
}));
|
|
268
277
|
}
|
|
269
278
|
//#endregion
|
|
279
|
+
//#region src/client/inspector.tsx
|
|
280
|
+
/**
|
|
281
|
+
* Drill-down inspector (SP2 R1): the details-seat swap rendering one run's
|
|
282
|
+
* phase chain (with the always-shown 3.5 row + full 6/7/8 rows), lock badges,
|
|
283
|
+
* and tamper/gate facts — all from the live host-route snapshot, never disk.
|
|
284
|
+
*/
|
|
285
|
+
function Inspector({ runId, worktreeRoot, snapshot, onBackToToolDetails }) {
|
|
286
|
+
const card = snapshot?.projection?.[worktreeRoot]?.[runId];
|
|
287
|
+
if (card === void 0) return (0, react.createElement)("div", { className: "rec-inspector" }, (0, react.createElement)("p", {}, "Run not found: " + runId));
|
|
288
|
+
const facts = cardFacts(card);
|
|
289
|
+
const rows = expandPhaseRows(card);
|
|
290
|
+
return (0, react.createElement)("div", { className: "rec-inspector" }, (0, react.createElement)("div", { className: "rec-inspector-head" }, (0, react.createElement)("button", {
|
|
291
|
+
onClick: onBackToToolDetails,
|
|
292
|
+
className: "rec-back"
|
|
293
|
+
}, "← back to tool details"), (0, react.createElement)("h2", {}, runId), (0, react.createElement)("span", { className: "rec-badge" }, facts.state), facts.tampered && (0, react.createElement)("span", { className: "rec-badge rec-badge-tamper" }, "tampered")), (0, react.createElement)("section", { className: "rec-inspector-section" }, (0, react.createElement)("h3", {}, "Phases"), rows.map((row) => (0, react.createElement)("div", {
|
|
294
|
+
key: row.phase,
|
|
295
|
+
className: "rec-phase-row"
|
|
296
|
+
}, (0, react.createElement)("span", { className: "rec-phase-id" }, row.phase), (0, react.createElement)("span", { className: "rec-phase-name" }, row.fileName ?? "—"), (0, react.createElement)("span", { className: "rec-badge" }, row.status), row.lockHash !== void 0 && (0, react.createElement)("code", { className: "rec-lockhash" }, "#" + row.lockHash.slice(0, 8))))), facts.gateBlocked && (0, react.createElement)("section", { className: "rec-inspector-section" }, (0, react.createElement)("h3", {}, "Gate"), (0, react.createElement)("p", {}, "Blocked (" + (facts.gateKind ?? "") + ")")));
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
270
299
|
//#region src/client/strip.tsx
|
|
271
300
|
/**
|
|
272
301
|
* Status strip (SP2 R1): a thin glance at the active run's phase, gate state,
|
|
@@ -409,22 +438,90 @@ window.__ModuleLoader__.load({
|
|
|
409
438
|
return state;
|
|
410
439
|
}
|
|
411
440
|
//#endregion
|
|
441
|
+
//#region src/client/open-state.ts
|
|
442
|
+
/**
|
|
443
|
+
* Shared board open-state (run 08 R1): module-level store behind the launcher,
|
|
444
|
+
* the shell.overlay entry, and the board<->inspector swap. Zero session events,
|
|
445
|
+
* zero host mutation — the client remains a read-only projection (R5/R9).
|
|
446
|
+
*/
|
|
447
|
+
function createBoardState(initial = {
|
|
448
|
+
open: false,
|
|
449
|
+
selection: null
|
|
450
|
+
}) {
|
|
451
|
+
let state = initial;
|
|
452
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
453
|
+
const emit = () => {
|
|
454
|
+
for (const fn of listeners) fn();
|
|
455
|
+
};
|
|
456
|
+
return {
|
|
457
|
+
get: () => state,
|
|
458
|
+
openBoard: () => {
|
|
459
|
+
state = {
|
|
460
|
+
...state,
|
|
461
|
+
open: true
|
|
462
|
+
};
|
|
463
|
+
emit();
|
|
464
|
+
},
|
|
465
|
+
close: () => {
|
|
466
|
+
state = {
|
|
467
|
+
...state,
|
|
468
|
+
open: false,
|
|
469
|
+
selection: null
|
|
470
|
+
};
|
|
471
|
+
emit();
|
|
472
|
+
},
|
|
473
|
+
openInspector: (selection) => {
|
|
474
|
+
state = {
|
|
475
|
+
...state,
|
|
476
|
+
open: true,
|
|
477
|
+
selection
|
|
478
|
+
};
|
|
479
|
+
emit();
|
|
480
|
+
},
|
|
481
|
+
backToBoard: () => {
|
|
482
|
+
state = {
|
|
483
|
+
...state,
|
|
484
|
+
selection: null
|
|
485
|
+
};
|
|
486
|
+
emit();
|
|
487
|
+
},
|
|
488
|
+
subscribe: (fn) => {
|
|
489
|
+
listeners.add(fn);
|
|
490
|
+
return () => {
|
|
491
|
+
listeners.delete(fn);
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/** App-wide singleton shared by the launcher, overlay, board, and inspector. */
|
|
497
|
+
const boardState = createBoardState();
|
|
498
|
+
function useBoardState(store = boardState) {
|
|
499
|
+
return (0, react.useSyncExternalStore)(store.subscribe, store.get, store.get);
|
|
500
|
+
}
|
|
501
|
+
//#endregion
|
|
412
502
|
//#region src/client/slots.ts
|
|
413
503
|
/**
|
|
414
|
-
* Slot registrations (SP2 R1): the sidebar launcher, the
|
|
415
|
-
* the conversation.input.dock status strip, and the
|
|
416
|
-
*
|
|
417
|
-
* The board (root scope) and strip (session scope) render ONLY for the
|
|
418
|
-
* recursive preset — the gate reads the CURRENT session's agentPreset from the
|
|
419
|
-
* sessions list snapshot (acceptance #3: a non-recursive session shows NOTHING).
|
|
504
|
+
* Slot registrations (SP2 R1 + run 08 R1/R3/R4): the sidebar launcher, the
|
|
505
|
+
* shell.overlay board, the conversation.input.dock status strip, and the
|
|
506
|
+
* settings.section page.
|
|
420
507
|
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
508
|
+
* Run 08: the launcher now OPENS the shared board store (onClick), and the
|
|
509
|
+
* shell.overlay entry renders the board gated on that store + the recursive
|
|
510
|
+
* preset, swapping to the drill-down inspector when a run is selected. The
|
|
511
|
+
* board reads cwd from the ROOT-scope standard prop useSessions (the scoped-
|
|
512
|
+
* slots root branch provides ONLY useSessions/useWorkspaces — useProjection is
|
|
513
|
+
* session-scope-only). The strip reads its sessionId from the session-scope
|
|
514
|
+
* standard prop.
|
|
425
515
|
*
|
|
426
516
|
* READ-ONLY (R9): the client only GETs the live host route; no mutation.
|
|
427
517
|
*/
|
|
518
|
+
/** Gate: hidden unless open AND recursive preset; inspector when a run is selected. */
|
|
519
|
+
function overlayContent(state, sessions) {
|
|
520
|
+
if (!state.open) return "hidden";
|
|
521
|
+
if (!isRecursivePreset(sessions)) return "hidden";
|
|
522
|
+
if (state.selection !== null) return "inspector";
|
|
523
|
+
return "board";
|
|
524
|
+
}
|
|
428
525
|
function registerSlots(ctx) {
|
|
429
526
|
const disposers = [];
|
|
430
527
|
disposers.push(ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
@@ -434,7 +531,8 @@ window.__ModuleLoader__.load({
|
|
|
434
531
|
label: "Recursive runs"
|
|
435
532
|
}, () => (0, react.createElement)("button", {
|
|
436
533
|
className: "rec-launcher",
|
|
437
|
-
title: "Recursive runs"
|
|
534
|
+
title: "Recursive runs",
|
|
535
|
+
onClick: () => boardState.openBoard()
|
|
438
536
|
}, "⧉"))));
|
|
439
537
|
disposers.push(ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
440
538
|
name: "shell.overlay",
|
|
@@ -443,7 +541,7 @@ window.__ModuleLoader__.load({
|
|
|
443
541
|
}, (props) => {
|
|
444
542
|
const useSessions = props?.useSessions;
|
|
445
543
|
if (useSessions === void 0) return null;
|
|
446
|
-
return (0, react.createElement)(
|
|
544
|
+
return (0, react.createElement)(RecursiveBoardOverlay, { useSessions });
|
|
447
545
|
})));
|
|
448
546
|
disposers.push(ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
449
547
|
name: "conversation.input.dock",
|
|
@@ -468,23 +566,33 @@ window.__ModuleLoader__.load({
|
|
|
468
566
|
};
|
|
469
567
|
}
|
|
470
568
|
/**
|
|
471
|
-
* Board
|
|
472
|
-
*
|
|
473
|
-
* standard useSessions hook and re-renders on change.
|
|
569
|
+
* Board overlay: subscribes to the shared board store, gates on open + recursive
|
|
570
|
+
* preset, and swaps board <-> inspector (run 08 R1/R3).
|
|
474
571
|
*/
|
|
475
|
-
function
|
|
572
|
+
function RecursiveBoardOverlay({ useSessions }) {
|
|
573
|
+
const board = useBoardState();
|
|
476
574
|
const list = useSessions();
|
|
477
575
|
const sessions = { list: {
|
|
478
576
|
getSnapshot: () => list,
|
|
479
577
|
subscribe: () => () => {}
|
|
480
578
|
} };
|
|
481
|
-
|
|
579
|
+
const content = overlayContent(board, sessions);
|
|
580
|
+
if (content === "hidden") return null;
|
|
482
581
|
const cwd = currentSessionCwd(sessions);
|
|
483
582
|
const snapshot = useLiveProjection({
|
|
484
583
|
sessionId: list.current,
|
|
485
584
|
cwd
|
|
486
585
|
});
|
|
487
|
-
return (0, react.createElement)(
|
|
586
|
+
if (content === "inspector" && board.selection !== null) return (0, react.createElement)(Inspector, {
|
|
587
|
+
runId: board.selection.runId,
|
|
588
|
+
worktreeRoot: board.selection.worktreeRoot,
|
|
589
|
+
snapshot,
|
|
590
|
+
onBackToToolDetails: () => boardState.backToBoard()
|
|
591
|
+
});
|
|
592
|
+
return (0, react.createElement)(Board, {
|
|
593
|
+
snapshot,
|
|
594
|
+
onOpenInspector: (sel) => boardState.openInspector(sel)
|
|
595
|
+
});
|
|
488
596
|
}
|
|
489
597
|
/**
|
|
490
598
|
* Strip gate: same preset gate, session-scoped sessionId; the strip renders
|
|
@@ -516,26 +624,6 @@ window.__ModuleLoader__.load({
|
|
|
516
624
|
globalThis.__dshRecursiveModeClientApplied = void 0;
|
|
517
625
|
}
|
|
518
626
|
//#endregion
|
|
519
|
-
//#region src/client/inspector.tsx
|
|
520
|
-
/**
|
|
521
|
-
* Drill-down inspector (SP2 R1): the details-seat swap rendering one run's
|
|
522
|
-
* phase chain (with the always-shown 3.5 row + full 6/7/8 rows), lock badges,
|
|
523
|
-
* and tamper/gate facts — all from the live host-route snapshot, never disk.
|
|
524
|
-
*/
|
|
525
|
-
function Inspector({ runId, worktreeRoot, snapshot, onBackToToolDetails }) {
|
|
526
|
-
const card = snapshot?.projection?.[worktreeRoot]?.[runId];
|
|
527
|
-
if (card === void 0) return (0, react.createElement)("div", { className: "rec-inspector" }, (0, react.createElement)("p", {}, "Run not found: " + runId));
|
|
528
|
-
const facts = cardFacts(card);
|
|
529
|
-
const rows = expandPhaseRows(card);
|
|
530
|
-
return (0, react.createElement)("div", { className: "rec-inspector" }, (0, react.createElement)("div", { className: "rec-inspector-head" }, (0, react.createElement)("button", {
|
|
531
|
-
onClick: onBackToToolDetails,
|
|
532
|
-
className: "rec-back"
|
|
533
|
-
}, "← back to tool details"), (0, react.createElement)("h2", {}, runId), (0, react.createElement)("span", { className: "rec-badge" }, facts.state), facts.tampered && (0, react.createElement)("span", { className: "rec-badge rec-badge-tamper" }, "tampered")), (0, react.createElement)("section", { className: "rec-inspector-section" }, (0, react.createElement)("h3", {}, "Phases"), rows.map((row) => (0, react.createElement)("div", {
|
|
534
|
-
key: row.phase,
|
|
535
|
-
className: "rec-phase-row"
|
|
536
|
-
}, (0, react.createElement)("span", { className: "rec-phase-id" }, row.phase), (0, react.createElement)("span", { className: "rec-phase-name" }, row.fileName ?? "—"), (0, react.createElement)("span", { className: "rec-badge" }, row.status), row.lockHash !== void 0 && (0, react.createElement)("code", { className: "rec-lockhash" }, "#" + row.lockHash.slice(0, 8))))), facts.gateBlocked && (0, react.createElement)("section", { className: "rec-inspector-section" }, (0, react.createElement)("h3", {}, "Gate"), (0, react.createElement)("p", {}, "Blocked (" + (facts.gateKind ?? "") + ")")));
|
|
537
|
-
}
|
|
538
|
-
//#endregion
|
|
539
627
|
//#region src/client/index.ts
|
|
540
628
|
/** Required services (fiber inject waiting — the runtime must be up first). */
|
|
541
629
|
const inject = [
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { WorkspaceRegistryLike } from './workspace.ts';
|
|
2
|
+
export interface FsPolicyIntent {
|
|
3
|
+
worktreeRoot: string;
|
|
4
|
+
runId: string;
|
|
5
|
+
/** The current phase doc file name (e.g. 03-implementation-summary.md), when determinable. */
|
|
6
|
+
currentPhaseFile: string | null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the recursive policy intent for one agent from the FILESYSTEM.
|
|
10
|
+
* Returns null when no control-plane root or run is present (callers defer,
|
|
11
|
+
* never fail hard). The registry path is async-only in the harness, so when a
|
|
12
|
+
* registry is present this resolves the session cwd directly (B4: the session
|
|
13
|
+
* cwd IS the workspace root when unregistered; a registered workspace resolves
|
|
14
|
+
* to the same cwd via resolveControlPlaneRoot's sync fallback).
|
|
15
|
+
*/
|
|
16
|
+
export declare function fsPolicyIntent(agent: {
|
|
17
|
+
session?: {
|
|
18
|
+
header?: {
|
|
19
|
+
cwd?: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
} | null | undefined, registry?: WorkspaceRegistryLike | null, cwdFallback?: string): FsPolicyIntent | null;
|
|
23
|
+
/**
|
|
24
|
+
* Async variant for callers that CAN await (pre-step listener, routes): uses
|
|
25
|
+
* resolveControlPlaneRoot for registry canonicalization when a registry is
|
|
26
|
+
* present, falling back to the session cwd (B4).
|
|
27
|
+
*/
|
|
28
|
+
export declare function fsPolicyIntentAsync(agent: {
|
|
29
|
+
session?: {
|
|
30
|
+
header?: {
|
|
31
|
+
cwd?: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
} | null | undefined, registry?: WorkspaceRegistryLike | null, cwdFallback?: string): Promise<FsPolicyIntent | null>;
|