@try-works/dsh-recursive-mode 0.1.5 → 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/index.js +3391 -906
- 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/index.ts +238 -228
- 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/src/client/board.tsx
CHANGED
|
Binary file
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared board open-state (run 08 R1): module-level store behind the launcher,
|
|
3
|
+
* the shell.overlay entry, and the board<->inspector swap. Zero session events,
|
|
4
|
+
* zero host mutation — the client remains a read-only projection (R5/R9).
|
|
5
|
+
*/
|
|
6
|
+
import { useSyncExternalStore } from 'react'
|
|
7
|
+
|
|
8
|
+
export interface BoardSelection {
|
|
9
|
+
worktreeRoot: string;
|
|
10
|
+
runId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface BoardState {
|
|
14
|
+
open: boolean;
|
|
15
|
+
selection: BoardSelection | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BoardOpenState {
|
|
19
|
+
get(): BoardState;
|
|
20
|
+
openBoard(): void;
|
|
21
|
+
close(): void;
|
|
22
|
+
openInspector(selection: BoardSelection): void;
|
|
23
|
+
backToBoard(): void;
|
|
24
|
+
subscribe(fn: () => void): () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createBoardState(initial: BoardState = { open: false, selection: null }): BoardOpenState {
|
|
28
|
+
let state: BoardState = initial;
|
|
29
|
+
const listeners = new Set<() => void>();
|
|
30
|
+
const emit = (): void => { for (const fn of listeners) fn() };
|
|
31
|
+
return {
|
|
32
|
+
get: () => state,
|
|
33
|
+
openBoard: () => { state = { ...state, open: true }; emit(); },
|
|
34
|
+
close: () => { state = { ...state, open: false, selection: null }; emit(); },
|
|
35
|
+
openInspector: (selection) => { state = { ...state, open: true, selection }; emit(); },
|
|
36
|
+
backToBoard: () => { state = { ...state, selection: null }; emit(); },
|
|
37
|
+
subscribe: (fn) => { listeners.add(fn); return () => { listeners.delete(fn) }; },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** App-wide singleton shared by the launcher, overlay, board, and inspector. */
|
|
42
|
+
export const boardState = createBoardState();
|
|
43
|
+
|
|
44
|
+
export function useBoardState(store: BoardOpenState = boardState): BoardState {
|
|
45
|
+
return useSyncExternalStore(store.subscribe, store.get, store.get);
|
|
46
|
+
}
|
package/src/client/slots.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Slot registrations (SP2 R1): the sidebar launcher, the
|
|
3
|
-
* the conversation.input.dock status strip, and the
|
|
2
|
+
* Slot registrations (SP2 R1 + run 08 R1/R3/R4): the sidebar launcher, the
|
|
3
|
+
* shell.overlay board, the conversation.input.dock status strip, and the
|
|
4
|
+
* settings.section page.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* its sessionId from the session-scope standard prop.
|
|
6
|
+
* Run 08: the launcher now OPENS the shared board store (onClick), and the
|
|
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. The
|
|
9
|
+
* board reads cwd from the ROOT-scope standard prop useSessions (the scoped-
|
|
10
|
+
* slots root branch provides ONLY useSessions/useWorkspaces — useProjection is
|
|
11
|
+
* session-scope-only). The strip reads its sessionId from the session-scope
|
|
12
|
+
* standard prop.
|
|
13
13
|
*
|
|
14
14
|
* READ-ONLY (R9): the client only GETs the live host route; no mutation.
|
|
15
15
|
*/
|
|
@@ -17,9 +17,11 @@ import { createElement, type ReactNode } from 'react'
|
|
|
17
17
|
import type { ClientContext, ISessionsLike, SnapshotStoreLike, SessionListStateLike } from './contract.ts'
|
|
18
18
|
import { isRecursivePreset, currentSessionCwd } from './contract.ts'
|
|
19
19
|
import { Board } from './board.tsx'
|
|
20
|
+
import { Inspector } from './inspector.tsx'
|
|
20
21
|
import { StatusStrip } from './strip.tsx'
|
|
21
22
|
import { RecursiveSettings } from './settings.tsx'
|
|
22
23
|
import { useLiveProjection } from './use-live.ts'
|
|
24
|
+
import { boardState, useBoardState } from './open-state.ts'
|
|
23
25
|
|
|
24
26
|
/** Structural standard-prop face for the root scope (useSessions only). */
|
|
25
27
|
interface RootSlotProps {
|
|
@@ -34,18 +36,28 @@ interface SessionSlotProps {
|
|
|
34
36
|
useProjection?: unknown
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
export type OverlayContent = 'hidden' | 'board' | 'inspector'
|
|
40
|
+
|
|
41
|
+
/** Gate: hidden unless open AND recursive preset; inspector when a run is selected. */
|
|
42
|
+
export function overlayContent(state: { open: boolean; selection: unknown }, sessions: ISessionsLike): OverlayContent {
|
|
43
|
+
if (!state.open) return 'hidden'
|
|
44
|
+
if (!isRecursivePreset(sessions)) return 'hidden'
|
|
45
|
+
if (state.selection !== null) return 'inspector'
|
|
46
|
+
return 'board'
|
|
47
|
+
}
|
|
48
|
+
|
|
37
49
|
export function registerSlots(ctx: ClientContext): () => void {
|
|
38
50
|
const disposers: (() => void)[] = []
|
|
39
51
|
|
|
40
|
-
// Board launcher in the sidebar footer action list
|
|
52
|
+
// Board launcher in the sidebar footer action list — OPENS the shared board store (run 08 R1).
|
|
41
53
|
disposers.push(ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({
|
|
42
54
|
name: 'sidebar.footer.action',
|
|
43
55
|
id: 'recursive',
|
|
44
56
|
order: 50,
|
|
45
57
|
label: 'Recursive runs',
|
|
46
|
-
}, () => createElement('button', { className: 'rec-launcher', title: 'Recursive runs' }, '⧉'))))
|
|
58
|
+
}, () => createElement('button', { className: 'rec-launcher', title: 'Recursive runs', onClick: () => boardState.openBoard() }, '⧉'))))
|
|
47
59
|
|
|
48
|
-
// Board panel overlay (root scope, cross-session read) — gated on the recursive preset.
|
|
60
|
+
// Board panel overlay (root scope, cross-session read) — gated on the recursive preset + shared store.
|
|
49
61
|
disposers.push(ctx.slots.inject('shell.overlay', () => ctx.slots.register({
|
|
50
62
|
name: 'shell.overlay',
|
|
51
63
|
id: 'recursive-board',
|
|
@@ -53,7 +65,7 @@ export function registerSlots(ctx: ClientContext): () => void {
|
|
|
53
65
|
}, (props: RootSlotProps) => {
|
|
54
66
|
const useSessions = props?.useSessions
|
|
55
67
|
if (useSessions === undefined) return null
|
|
56
|
-
return createElement(
|
|
68
|
+
return createElement(RecursiveBoardOverlay, { useSessions })
|
|
57
69
|
})))
|
|
58
70
|
|
|
59
71
|
// Status strip in the composer input dock (session scope) — gated the same way.
|
|
@@ -79,18 +91,27 @@ export function registerSlots(ctx: ClientContext): () => void {
|
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
/**
|
|
82
|
-
* Board
|
|
83
|
-
*
|
|
84
|
-
* standard useSessions hook and re-renders on change.
|
|
94
|
+
* Board overlay: subscribes to the shared board store, gates on open + recursive
|
|
95
|
+
* preset, and swaps board <-> inspector (run 08 R1/R3).
|
|
85
96
|
*/
|
|
86
|
-
function
|
|
97
|
+
function RecursiveBoardOverlay({ useSessions }: { useSessions: () => SessionListStateLike }): ReactNode {
|
|
98
|
+
const board = useBoardState()
|
|
87
99
|
const list = useSessions()
|
|
88
100
|
const sessions: ISessionsLike = { list: { getSnapshot: () => list, subscribe: () => () => {} } as SnapshotStoreLike<SessionListStateLike> }
|
|
89
|
-
|
|
101
|
+
const content = overlayContent(board, sessions)
|
|
102
|
+
if (content === 'hidden') return null
|
|
90
103
|
const cwd = currentSessionCwd(sessions)
|
|
91
104
|
const scope = { sessionId: list.current, cwd }
|
|
92
105
|
const snapshot = useLiveProjection(scope)
|
|
93
|
-
|
|
106
|
+
if (content === 'inspector' && board.selection !== null) {
|
|
107
|
+
return createElement(Inspector, {
|
|
108
|
+
runId: board.selection.runId,
|
|
109
|
+
worktreeRoot: board.selection.worktreeRoot,
|
|
110
|
+
snapshot,
|
|
111
|
+
onBackToToolDetails: () => boardState.backToBoard(),
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
return createElement(Board, { snapshot, onOpenInspector: (sel) => boardState.openInspector(sel) })
|
|
94
115
|
}
|
|
95
116
|
|
|
96
117
|
/**
|
package/src/commands.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { existsSync, readdirSync, statSync } from 'node:fs'
|
|
|
13
13
|
import { join } from 'node:path'
|
|
14
14
|
import type { RecursiveRuntime } from './runtime.ts'
|
|
15
15
|
import { resolveControlPlaneRoot } from './workspace.ts'
|
|
16
|
+
import { bootstrapScaffold } from './bootstrap.ts'
|
|
16
17
|
|
|
17
18
|
export type RecursiveVerb = 'status' | 'spec' | 'worktree' | 'init' | 'lock' | 'qa' | 'closeout' | 'addendum' | 'review' | 'scratch' | 'bootstrap' | 'list' | 'help'
|
|
18
19
|
|
|
@@ -65,6 +66,16 @@ export function executeRecursiveCommand(root: string, rawInput: string): Recursi
|
|
|
65
66
|
case 'help': {
|
|
66
67
|
return { kind: 'success', text: HELP_TEXT + ' — see /.recursive/RECURSIVE.md' }
|
|
67
68
|
}
|
|
69
|
+
case 'bootstrap': {
|
|
70
|
+
// R6 (run 09): manual repair path — idempotent upsert scaffold repair.
|
|
71
|
+
// Adds missing control-plane files/dirs + re-upserts marked blocks;
|
|
72
|
+
// never overwrites user content or touches run/ artifacts.
|
|
73
|
+
const result = bootstrapScaffold(root)
|
|
74
|
+
const summary = result.created.length === 0
|
|
75
|
+
? 'scaffold already complete (no changes)'
|
|
76
|
+
: 'created ' + result.created.length + ' item(s), ' + result.existing.length + ' existing'
|
|
77
|
+
return { kind: 'success', text: 'recursive-mode scaffold repair: ' + summary + ' — root ' + root }
|
|
78
|
+
}
|
|
68
79
|
case 'closeout': {
|
|
69
80
|
const phaseMatch = arg.match(/--phase\s+(\d{2})/)
|
|
70
81
|
const phase = phaseMatch?.[1] ?? ''
|