@try-works/dsh-recursive-mode 0.1.6 → 0.1.7
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/client/contract.d.ts +16 -13
- package/lib/client/index.d.ts +1 -1
- package/lib/client/slots.d.ts +8 -2
- package/lib/client.js +32 -31
- package/package.json +1 -1
- package/src/client/contract.ts +19 -22
- package/src/client/index.ts +1 -1
- package/src/client/slots.ts +35 -22
package/lib/client/contract.d.ts
CHANGED
|
@@ -29,21 +29,24 @@ export interface SessionSummaryRow {
|
|
|
29
29
|
/** Agent preset this session was composed from; absent when the deployment has none. */
|
|
30
30
|
agentPreset?: string;
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* The session-list snapshot (mirrors the REAL SessionListState). useSessions is
|
|
34
|
+
* a SnapshotSelectorHook over this state; the identity selector `(s) => s`
|
|
35
|
+
* yields the full value, which the gate reads directly (ids/byId/current).
|
|
36
|
+
*/
|
|
33
37
|
export interface SessionListStateLike {
|
|
34
38
|
ids: string[];
|
|
35
39
|
byId: Record<string, SessionSummaryRow>;
|
|
36
40
|
current: string | undefined;
|
|
37
41
|
}
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
42
|
+
/**
|
|
43
|
+
* The REAL selector-hook shape (ui-slots store.ts):
|
|
44
|
+
* SnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?) => S
|
|
45
|
+
* The selector is REQUIRED — useSyncExternalStoreWithSelector needs it. Calling
|
|
46
|
+
* the hook with no selector passes sel=undefined and breaks the board mount.
|
|
47
|
+
* This is the run 10 live bug.
|
|
48
|
+
*/
|
|
49
|
+
export type SnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean) => S;
|
|
47
50
|
/** The slots registry surface the client injects into. */
|
|
48
51
|
export interface ClientSlots {
|
|
49
52
|
inject(seat: string, factory: (ctx: unknown) => () => void): () => void;
|
|
@@ -77,8 +80,8 @@ export interface LiveProjectionValue {
|
|
|
77
80
|
* The client-side preset gate (acceptance #3): the board/strip render ONLY when
|
|
78
81
|
* the CURRENT session's row reports agentPreset === 'recursive'. A non-recursive
|
|
79
82
|
* session (or a session whose preset is undefined) shows NOTHING — not an empty
|
|
80
|
-
* board, not a spinner.
|
|
83
|
+
* board, not a spinner. Consumes the SessionListStateLike DIRECTLY (run 10 fix).
|
|
81
84
|
*/
|
|
82
|
-
export declare function isRecursivePreset(
|
|
85
|
+
export declare function isRecursivePreset(state: SessionListStateLike): boolean;
|
|
83
86
|
/** The current session's cwd (the client passes it as a fallback hint; the host resolves the root). */
|
|
84
|
-
export declare function currentSessionCwd(
|
|
87
|
+
export declare function currentSessionCwd(state: SessionListStateLike): string;
|
package/lib/client/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type { LiveProjectionSnapshot } from './use-live.ts';
|
|
|
21
21
|
export { fetchLiveState, subscribeLiveEvents } from './host-api.ts';
|
|
22
22
|
export type { LiveRecursiveState, LiveRecursiveFrame, LiveScope } from './host-api.ts';
|
|
23
23
|
export { isRecursivePreset, currentSessionCwd } from './contract.ts';
|
|
24
|
-
export type { SessionSummaryRow, SessionListStateLike,
|
|
24
|
+
export type { SessionSummaryRow, SessionListStateLike, SnapshotSelectorHook, ClientContext } from './contract.ts';
|
|
25
25
|
/** Required services (fiber inject waiting — the runtime must be up first). */
|
|
26
26
|
export declare const inject: string[];
|
|
27
27
|
/** Browser-half plugin entry (R4 + SP2 R1). */
|
package/lib/client/slots.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import type { ClientContext,
|
|
1
|
+
import type { ClientContext, SessionListStateLike, SnapshotSelectorHook } from './contract.ts';
|
|
2
2
|
import { isRecursivePreset, currentSessionCwd } from './contract.ts';
|
|
3
3
|
export type OverlayContent = 'hidden' | 'board' | 'inspector';
|
|
4
4
|
/** Gate: hidden unless open AND recursive preset; inspector when a run is selected. */
|
|
5
5
|
export declare function overlayContent(state: {
|
|
6
6
|
open: boolean;
|
|
7
7
|
selection: unknown;
|
|
8
|
-
}, sessions:
|
|
8
|
+
}, sessions: SessionListStateLike): OverlayContent;
|
|
9
|
+
/**
|
|
10
|
+
* THE FIX (run 10): useSessions is a SELECTOR hook — always call it WITH a
|
|
11
|
+
* selector. The identity selector `(s) => s` yields the full SessionListStateLike.
|
|
12
|
+
* Exported so the spec can assert the selector is actually passed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useRecursiveSessions(useSessions: SnapshotSelectorHook<SessionListStateLike>): SessionListStateLike;
|
|
9
15
|
export declare function registerSlots(ctx: ClientContext): () => void;
|
|
10
16
|
/** Export the gate helpers for tests. */
|
|
11
17
|
export { isRecursivePreset, currentSessionCwd };
|
package/lib/client.js
CHANGED
|
@@ -10,20 +10,15 @@ window.__ModuleLoader__.load({
|
|
|
10
10
|
* The client-side preset gate (acceptance #3): the board/strip render ONLY when
|
|
11
11
|
* the CURRENT session's row reports agentPreset === 'recursive'. A non-recursive
|
|
12
12
|
* session (or a session whose preset is undefined) shows NOTHING — not an empty
|
|
13
|
-
* board, not a spinner.
|
|
13
|
+
* board, not a spinner. Consumes the SessionListStateLike DIRECTLY (run 10 fix).
|
|
14
14
|
*/
|
|
15
|
-
function isRecursivePreset(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (current === void 0) return false;
|
|
19
|
-
return snapshot.byId[current]?.agentPreset === "recursive";
|
|
15
|
+
function isRecursivePreset(state) {
|
|
16
|
+
if (state.current === void 0) return false;
|
|
17
|
+
return state.byId[state.current]?.agentPreset === "recursive";
|
|
20
18
|
}
|
|
21
19
|
/** The current session's cwd (the client passes it as a fallback hint; the host resolves the root). */
|
|
22
|
-
function currentSessionCwd(
|
|
23
|
-
|
|
24
|
-
const current = snapshot.current;
|
|
25
|
-
if (current === void 0) return "";
|
|
26
|
-
return snapshot.byId[current]?.cwd ?? "";
|
|
20
|
+
function currentSessionCwd(state) {
|
|
21
|
+
return state.current === void 0 ? "" : state.byId[state.current]?.cwd ?? "";
|
|
27
22
|
}
|
|
28
23
|
//#endregion
|
|
29
24
|
//#region src/client/derive.ts
|
|
@@ -507,11 +502,14 @@ window.__ModuleLoader__.load({
|
|
|
507
502
|
*
|
|
508
503
|
* Run 08: the launcher now OPENS the shared board store (onClick), and the
|
|
509
504
|
* 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.
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
505
|
+
* preset, swapping to the drill-down inspector when a run is selected.
|
|
506
|
+
*
|
|
507
|
+
* Run 10 (LIVE BUG FIX): useSessions is a SnapshotSelectorHook (NOT a zero-arg
|
|
508
|
+
* thunk) — it is called WITH a selector, e.g. useSessions((s) => s) for the
|
|
509
|
+
* full SessionListStateLike. The old code called useSessions() with NO selector
|
|
510
|
+
* and wrapped the garbage in a fake {list:{getSnapshot}} — so the preset gate
|
|
511
|
+
* never saw the recursive preset and the board never mounted (launcher click
|
|
512
|
+
* did nothing). The board/strip now consume the SessionListStateLike directly.
|
|
515
513
|
*
|
|
516
514
|
* READ-ONLY (R9): the client only GETs the live host route; no mutation.
|
|
517
515
|
*/
|
|
@@ -522,6 +520,14 @@ window.__ModuleLoader__.load({
|
|
|
522
520
|
if (state.selection !== null) return "inspector";
|
|
523
521
|
return "board";
|
|
524
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* THE FIX (run 10): useSessions is a SELECTOR hook — always call it WITH a
|
|
525
|
+
* selector. The identity selector `(s) => s` yields the full SessionListStateLike.
|
|
526
|
+
* Exported so the spec can assert the selector is actually passed.
|
|
527
|
+
*/
|
|
528
|
+
function useRecursiveSessions(useSessions) {
|
|
529
|
+
return useSessions((s) => s);
|
|
530
|
+
}
|
|
525
531
|
function registerSlots(ctx) {
|
|
526
532
|
const disposers = [];
|
|
527
533
|
disposers.push(ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
@@ -568,17 +574,16 @@ window.__ModuleLoader__.load({
|
|
|
568
574
|
/**
|
|
569
575
|
* Board overlay: subscribes to the shared board store, gates on open + recursive
|
|
570
576
|
* preset, and swaps board <-> inspector (run 08 R1/R3).
|
|
577
|
+
*
|
|
578
|
+
* Run 10: consumes the full SessionListStateLike through the identity selector
|
|
579
|
+
* (useSessions((s) => s)); no fake {list:{getSnapshot}} wrapper.
|
|
571
580
|
*/
|
|
572
581
|
function RecursiveBoardOverlay({ useSessions }) {
|
|
573
582
|
const board = useBoardState();
|
|
574
|
-
const list = useSessions
|
|
575
|
-
const
|
|
576
|
-
getSnapshot: () => list,
|
|
577
|
-
subscribe: () => () => {}
|
|
578
|
-
} };
|
|
579
|
-
const content = overlayContent(board, sessions);
|
|
583
|
+
const list = useRecursiveSessions(useSessions);
|
|
584
|
+
const content = overlayContent(board, list);
|
|
580
585
|
if (content === "hidden") return null;
|
|
581
|
-
const cwd = currentSessionCwd(
|
|
586
|
+
const cwd = currentSessionCwd(list);
|
|
582
587
|
const snapshot = useLiveProjection({
|
|
583
588
|
sessionId: list.current,
|
|
584
589
|
cwd
|
|
@@ -596,18 +601,14 @@ window.__ModuleLoader__.load({
|
|
|
596
601
|
}
|
|
597
602
|
/**
|
|
598
603
|
* Strip gate: same preset gate, session-scoped sessionId; the strip renders
|
|
599
|
-
* nothing for a non-recursive session.
|
|
604
|
+
* nothing for a non-recursive session. Run 10: useSessions((s) => s) selector.
|
|
600
605
|
*/
|
|
601
606
|
function RecursiveStripGate({ useSessions, sessionId }) {
|
|
602
|
-
const list = useSessions
|
|
603
|
-
|
|
604
|
-
getSnapshot: () => list,
|
|
605
|
-
subscribe: () => () => {}
|
|
606
|
-
} };
|
|
607
|
-
if (!isRecursivePreset(sessions)) return null;
|
|
607
|
+
const list = useRecursiveSessions(useSessions);
|
|
608
|
+
if (!isRecursivePreset(list)) return null;
|
|
608
609
|
const snapshot = useLiveProjection({
|
|
609
610
|
sessionId,
|
|
610
|
-
cwd: currentSessionCwd(
|
|
611
|
+
cwd: currentSessionCwd(list)
|
|
611
612
|
});
|
|
612
613
|
return (0, react.createElement)(StatusStrip, { snapshot });
|
|
613
614
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@try-works/dsh-recursive-mode",
|
|
3
3
|
"description": "recursive-mode workflow as a DeepSeek Harness bundle: RecursiveRuntime service + recursive_status tool",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
package/src/client/contract.ts
CHANGED
|
@@ -33,23 +33,25 @@ export interface SessionSummaryRow {
|
|
|
33
33
|
agentPreset?: string
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* The session-list snapshot (mirrors the REAL SessionListState). useSessions is
|
|
38
|
+
* a SnapshotSelectorHook over this state; the identity selector `(s) => s`
|
|
39
|
+
* yields the full value, which the gate reads directly (ids/byId/current).
|
|
40
|
+
*/
|
|
37
41
|
export interface SessionListStateLike {
|
|
38
42
|
ids: string[]
|
|
39
43
|
byId: Record<string, SessionSummaryRow>
|
|
40
44
|
current: string | undefined
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
export
|
|
51
|
-
list: SnapshotStoreLike<SessionListStateLike>
|
|
52
|
-
}
|
|
47
|
+
/**
|
|
48
|
+
* The REAL selector-hook shape (ui-slots store.ts):
|
|
49
|
+
* SnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?) => S
|
|
50
|
+
* The selector is REQUIRED — useSyncExternalStoreWithSelector needs it. Calling
|
|
51
|
+
* the hook with no selector passes sel=undefined and breaks the board mount.
|
|
52
|
+
* This is the run 10 live bug.
|
|
53
|
+
*/
|
|
54
|
+
export type SnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean) => S
|
|
53
55
|
|
|
54
56
|
/** The slots registry surface the client injects into. */
|
|
55
57
|
export interface ClientSlots {
|
|
@@ -88,19 +90,14 @@ export interface LiveProjectionValue {
|
|
|
88
90
|
* The client-side preset gate (acceptance #3): the board/strip render ONLY when
|
|
89
91
|
* the CURRENT session's row reports agentPreset === 'recursive'. A non-recursive
|
|
90
92
|
* session (or a session whose preset is undefined) shows NOTHING — not an empty
|
|
91
|
-
* board, not a spinner.
|
|
93
|
+
* board, not a spinner. Consumes the SessionListStateLike DIRECTLY (run 10 fix).
|
|
92
94
|
*/
|
|
93
|
-
export function isRecursivePreset(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (current === undefined) return false
|
|
97
|
-
return snapshot.byId[current]?.agentPreset === 'recursive'
|
|
95
|
+
export function isRecursivePreset(state: SessionListStateLike): boolean {
|
|
96
|
+
if (state.current === undefined) return false
|
|
97
|
+
return state.byId[state.current]?.agentPreset === 'recursive'
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** The current session's cwd (the client passes it as a fallback hint; the host resolves the root). */
|
|
101
|
-
export function currentSessionCwd(
|
|
102
|
-
|
|
103
|
-
const current = snapshot.current
|
|
104
|
-
if (current === undefined) return ''
|
|
105
|
-
return snapshot.byId[current]?.cwd ?? ''
|
|
101
|
+
export function currentSessionCwd(state: SessionListStateLike): string {
|
|
102
|
+
return state.current === undefined ? '' : (state.byId[state.current]?.cwd ?? '')
|
|
106
103
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ export type { LiveProjectionSnapshot } from './use-live.ts'
|
|
|
24
24
|
export { fetchLiveState, subscribeLiveEvents } from './host-api.ts'
|
|
25
25
|
export type { LiveRecursiveState, LiveRecursiveFrame, LiveScope } from './host-api.ts'
|
|
26
26
|
export { isRecursivePreset, currentSessionCwd } from './contract.ts'
|
|
27
|
-
export type { SessionSummaryRow, SessionListStateLike,
|
|
27
|
+
export type { SessionSummaryRow, SessionListStateLike, SnapshotSelectorHook, ClientContext } from './contract.ts'
|
|
28
28
|
|
|
29
29
|
/** Required services (fiber inject waiting — the runtime must be up first). */
|
|
30
30
|
export const inject = ['slots', 'sessions', 'workspaces', 'connection']
|
package/src/client/slots.ts
CHANGED
|
@@ -5,16 +5,19 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Run 08: the launcher now OPENS the shared board store (onClick), and the
|
|
7
7
|
* shell.overlay entry renders the board gated on that store + the recursive
|
|
8
|
-
* preset, swapping to the drill-down inspector when a run is selected.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* preset, swapping to the drill-down inspector when a run is selected.
|
|
9
|
+
*
|
|
10
|
+
* Run 10 (LIVE BUG FIX): useSessions is a SnapshotSelectorHook (NOT a zero-arg
|
|
11
|
+
* thunk) — it is called WITH a selector, e.g. useSessions((s) => s) for the
|
|
12
|
+
* full SessionListStateLike. The old code called useSessions() with NO selector
|
|
13
|
+
* and wrapped the garbage in a fake {list:{getSnapshot}} — so the preset gate
|
|
14
|
+
* never saw the recursive preset and the board never mounted (launcher click
|
|
15
|
+
* did nothing). The board/strip now consume the SessionListStateLike directly.
|
|
13
16
|
*
|
|
14
17
|
* READ-ONLY (R9): the client only GETs the live host route; no mutation.
|
|
15
18
|
*/
|
|
16
19
|
import { createElement, type ReactNode } from 'react'
|
|
17
|
-
import type { ClientContext,
|
|
20
|
+
import type { ClientContext, SessionListStateLike, SnapshotSelectorHook } from './contract.ts'
|
|
18
21
|
import { isRecursivePreset, currentSessionCwd } from './contract.ts'
|
|
19
22
|
import { Board } from './board.tsx'
|
|
20
23
|
import { Inspector } from './inspector.tsx'
|
|
@@ -23,29 +26,38 @@ import { RecursiveSettings } from './settings.tsx'
|
|
|
23
26
|
import { useLiveProjection } from './use-live.ts'
|
|
24
27
|
import { boardState, useBoardState } from './open-state.ts'
|
|
25
28
|
|
|
26
|
-
/** Structural standard-prop face for the root scope (useSessions
|
|
29
|
+
/** Structural standard-prop face for the root scope (useSessions/useWorkspaces). */
|
|
27
30
|
interface RootSlotProps {
|
|
28
|
-
useSessions?:
|
|
29
|
-
useWorkspaces?:
|
|
31
|
+
useSessions?: SnapshotSelectorHook<SessionListStateLike>
|
|
32
|
+
useWorkspaces?: SnapshotSelectorHook<unknown>
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/** Structural standard-prop face for the session scope (sessionId + useSessions). */
|
|
33
36
|
interface SessionSlotProps {
|
|
34
37
|
sessionId?: string
|
|
35
|
-
useSessions?:
|
|
38
|
+
useSessions?: SnapshotSelectorHook<SessionListStateLike>
|
|
36
39
|
useProjection?: unknown
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
export type OverlayContent = 'hidden' | 'board' | 'inspector'
|
|
40
43
|
|
|
41
44
|
/** Gate: hidden unless open AND recursive preset; inspector when a run is selected. */
|
|
42
|
-
export function overlayContent(state: { open: boolean; selection: unknown }, sessions:
|
|
45
|
+
export function overlayContent(state: { open: boolean; selection: unknown }, sessions: SessionListStateLike): OverlayContent {
|
|
43
46
|
if (!state.open) return 'hidden'
|
|
44
47
|
if (!isRecursivePreset(sessions)) return 'hidden'
|
|
45
48
|
if (state.selection !== null) return 'inspector'
|
|
46
49
|
return 'board'
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
/**
|
|
53
|
+
* THE FIX (run 10): useSessions is a SELECTOR hook — always call it WITH a
|
|
54
|
+
* selector. The identity selector `(s) => s` yields the full SessionListStateLike.
|
|
55
|
+
* Exported so the spec can assert the selector is actually passed.
|
|
56
|
+
*/
|
|
57
|
+
export function useRecursiveSessions(useSessions: SnapshotSelectorHook<SessionListStateLike>): SessionListStateLike {
|
|
58
|
+
return useSessions((s) => s)
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
export function registerSlots(ctx: ClientContext): () => void {
|
|
50
62
|
const disposers: (() => void)[] = []
|
|
51
63
|
|
|
@@ -93,14 +105,16 @@ export function registerSlots(ctx: ClientContext): () => void {
|
|
|
93
105
|
/**
|
|
94
106
|
* Board overlay: subscribes to the shared board store, gates on open + recursive
|
|
95
107
|
* preset, and swaps board <-> inspector (run 08 R1/R3).
|
|
108
|
+
*
|
|
109
|
+
* Run 10: consumes the full SessionListStateLike through the identity selector
|
|
110
|
+
* (useSessions((s) => s)); no fake {list:{getSnapshot}} wrapper.
|
|
96
111
|
*/
|
|
97
|
-
function RecursiveBoardOverlay({ useSessions }: { useSessions:
|
|
112
|
+
function RecursiveBoardOverlay({ useSessions }: { useSessions: SnapshotSelectorHook<SessionListStateLike> }): ReactNode {
|
|
98
113
|
const board = useBoardState()
|
|
99
|
-
const list = useSessions
|
|
100
|
-
const
|
|
101
|
-
const content = overlayContent(board, sessions)
|
|
114
|
+
const list = useRecursiveSessions(useSessions)
|
|
115
|
+
const content = overlayContent(board, list)
|
|
102
116
|
if (content === 'hidden') return null
|
|
103
|
-
const cwd = currentSessionCwd(
|
|
117
|
+
const cwd = currentSessionCwd(list)
|
|
104
118
|
const scope = { sessionId: list.current, cwd }
|
|
105
119
|
const snapshot = useLiveProjection(scope)
|
|
106
120
|
if (content === 'inspector' && board.selection !== null) {
|
|
@@ -116,13 +130,12 @@ function RecursiveBoardOverlay({ useSessions }: { useSessions: () => SessionList
|
|
|
116
130
|
|
|
117
131
|
/**
|
|
118
132
|
* Strip gate: same preset gate, session-scoped sessionId; the strip renders
|
|
119
|
-
* nothing for a non-recursive session.
|
|
133
|
+
* nothing for a non-recursive session. Run 10: useSessions((s) => s) selector.
|
|
120
134
|
*/
|
|
121
|
-
function RecursiveStripGate({ useSessions, sessionId }: { useSessions:
|
|
122
|
-
const list = useSessions
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const cwd = currentSessionCwd(sessions)
|
|
135
|
+
function RecursiveStripGate({ useSessions, sessionId }: { useSessions: SnapshotSelectorHook<SessionListStateLike>; sessionId?: string }): ReactNode {
|
|
136
|
+
const list = useRecursiveSessions(useSessions)
|
|
137
|
+
if (!isRecursivePreset(list)) return null
|
|
138
|
+
const cwd = currentSessionCwd(list)
|
|
126
139
|
const scope = { sessionId, cwd }
|
|
127
140
|
const snapshot = useLiveProjection(scope)
|
|
128
141
|
return createElement(StatusStrip, { snapshot })
|