@try-works/dsh-recursive-mode 0.1.14 → 0.1.16

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.
@@ -5,10 +5,12 @@ import type { BoardSelection } from './open-state.ts';
5
5
  export declare function listRuns(projection: RecursiveProjection | undefined): RecursiveRunCard[];
6
6
  export interface BoardProps {
7
7
  snapshot: LiveProjectionValue | null;
8
+ /** The authoritative current-workspace path (synchronous). snapshot.root is async/stale. */
9
+ workspacePath?: string;
8
10
  onOpenInspector?: (selection: BoardSelection) => void;
9
11
  onClose?: () => void;
10
12
  }
11
- export declare function Board({ snapshot, onOpenInspector, onClose }: BoardProps): import("react").DetailedReactHTMLElement<{
13
+ export declare function Board({ snapshot, workspacePath, onOpenInspector, onClose }: BoardProps): import("react").DetailedReactHTMLElement<{
12
14
  className: string;
13
15
  'data-theme': import("./theme.ts").BoardTheme;
14
16
  }, HTMLElement> | null;
package/lib/client.js CHANGED
@@ -351,11 +351,11 @@ window.__ModuleLoader__.load({
351
351
  "data-pill": kind
352
352
  }, PILL_LABELS[kind]);
353
353
  }
354
- function Board({ snapshot, onOpenInspector, onClose }) {
354
+ function Board({ snapshot, workspacePath, onOpenInspector, onClose }) {
355
355
  const { theme, toggle } = useBoardTheme();
356
356
  if (snapshot === null || snapshot.root === null) return null;
357
357
  const runs = listRuns(snapshot.projection);
358
- const workspacePath = snapshot.root;
358
+ const headerPath = workspacePath ?? snapshot.root;
359
359
  const open = (run) => () => onOpenInspector?.({
360
360
  worktreeRoot: run.worktreeRoot,
361
361
  runId: run.runId
@@ -364,14 +364,14 @@ window.__ModuleLoader__.load({
364
364
  className: "rec-board",
365
365
  "data-theme": theme,
366
366
  "data-empty": true
367
- }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-path" }, workspacePath), (0, react.createElement)("span", { className: "rec-board-count" }, "0 runs"), (0, react.createElement)(ThemeToggle, {
367
+ }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-path" }, headerPath), (0, react.createElement)("span", { className: "rec-board-count" }, "0 runs"), (0, react.createElement)(ThemeToggle, {
368
368
  theme,
369
369
  toggle
370
370
  }), closeButton$1(onClose)), (0, react.createElement)("p", { className: "rec-board-empty" }, "No recursive runs in this workspace yet."));
371
371
  return (0, react.createElement)("div", {
372
372
  className: "rec-board",
373
373
  "data-theme": theme
374
- }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-path" }, workspacePath), (0, react.createElement)("span", { className: "rec-board-count" }, runs.length + " runs"), (0, react.createElement)(ThemeToggle, {
374
+ }, (0, react.createElement)("header", { className: "rec-board-header" }, (0, react.createElement)("h2", { className: "rec-board-title" }, "Recursive runs"), (0, react.createElement)("span", { className: "rec-board-path" }, headerPath), (0, react.createElement)("span", { className: "rec-board-count" }, runs.length + " runs"), (0, react.createElement)(ThemeToggle, {
375
375
  theme,
376
376
  toggle
377
377
  }), closeButton$1(onClose)), (0, react.createElement)("div", { className: "rec-columns" }, KANBAN_LANES.map((lane) => {
@@ -572,7 +572,11 @@ window.__ModuleLoader__.load({
572
572
  function useLiveProjection(scope) {
573
573
  const [state, setState] = (0, react.useState)(null);
574
574
  (0, react.useEffect)(() => {
575
- if (isEmpty(scope)) return;
575
+ if (isEmpty(scope)) {
576
+ setState(null);
577
+ return;
578
+ }
579
+ setState(null);
576
580
  let disposed = false;
577
581
  const apply = (frame) => {
578
582
  if (!disposed) setState(frame);
@@ -1326,7 +1330,8 @@ window.__ModuleLoader__.load({
1326
1330
  recentWorkspaceId: void 0
1327
1331
  };
1328
1332
  const content = overlayContent(board, sessions);
1329
- const snapshot = useLiveProjection({ cwd: currentWorkspacePath(workspaces, sessions) });
1333
+ const wsPath = currentWorkspacePath(workspaces, sessions);
1334
+ const snapshot = useLiveProjection({ cwd: wsPath });
1330
1335
  if (content === "hidden") return null;
1331
1336
  if (content === "inspector" && board.selection !== null) return (0, react.createElement)(Inspector, {
1332
1337
  runId: board.selection.runId,
@@ -1337,6 +1342,7 @@ window.__ModuleLoader__.load({
1337
1342
  });
1338
1343
  return (0, react.createElement)(Board, {
1339
1344
  snapshot,
1345
+ workspacePath: wsPath,
1340
1346
  onOpenInspector: (sel) => boardState.openInspector(sel),
1341
1347
  onClose: () => boardState.close()
1342
1348
  });
package/lib/index.js CHANGED
@@ -6116,10 +6116,11 @@ function makeRecursiveRoutes(host) {
6116
6116
  "cache-control": "no-cache",
6117
6117
  connection: "keep-alive"
6118
6118
  });
6119
- const push = () => {
6119
+ const push = async () => {
6120
+ const projection = await host.snapshot(root);
6120
6121
  const payload = {
6121
6122
  root,
6122
- projection: host.snapshot(root),
6123
+ projection,
6123
6124
  revision: host.revision(root)
6124
6125
  };
6125
6126
  res.write("data: " + JSON.stringify(payload) + "\n\n");
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.14",
4
+ "version": "0.1.16",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -28,6 +28,8 @@ export function listRuns(projection: RecursiveProjection | undefined): Recursive
28
28
 
29
29
  export interface BoardProps {
30
30
  snapshot: LiveProjectionValue | null
31
+ /** The authoritative current-workspace path (synchronous). snapshot.root is async/stale. */
32
+ workspacePath?: string
31
33
  onOpenInspector?: (selection: BoardSelection) => void
32
34
  onClose?: () => void
33
35
  }
@@ -41,17 +43,17 @@ function solidPill(kind: ReturnType<typeof cardPill>) {
41
43
  return createElement('span', { className: 'rec-pill', 'data-pill': kind }, PILL_LABELS[kind])
42
44
  }
43
45
 
44
- export function Board({ snapshot, onOpenInspector, onClose }: BoardProps) {
46
+ export function Board({ snapshot, workspacePath, onOpenInspector, onClose }: BoardProps) {
45
47
  const { theme, toggle } = useBoardTheme()
46
48
  if (snapshot === null || snapshot.root === null) return null
47
49
  const runs = listRuns(snapshot.projection)
48
- const workspacePath = snapshot.root
50
+ const headerPath = workspacePath ?? snapshot.root
49
51
  const open = (run: RecursiveRunCard) => () => onOpenInspector?.({ worktreeRoot: run.worktreeRoot, runId: run.runId })
50
52
  if (runs.length === 0) {
51
53
  return createElement('div', { className: 'rec-board', 'data-theme': theme, 'data-empty': true },
52
54
  createElement('header', { className: 'rec-board-header' },
53
55
  createElement('h2', { className: 'rec-board-title' }, 'Recursive runs'),
54
- createElement('span', { className: 'rec-board-path' }, workspacePath),
56
+ createElement('span', { className: 'rec-board-path' }, headerPath),
55
57
  createElement('span', { className: 'rec-board-count' }, '0 runs'),
56
58
  createElement(ThemeToggle, { theme, toggle }),
57
59
  closeButton(onClose),
@@ -62,7 +64,7 @@ export function Board({ snapshot, onOpenInspector, onClose }: BoardProps) {
62
64
  return createElement('div', { className: 'rec-board', 'data-theme': theme },
63
65
  createElement('header', { className: 'rec-board-header' },
64
66
  createElement('h2', { className: 'rec-board-title' }, 'Recursive runs'),
65
- createElement('span', { className: 'rec-board-path' }, workspacePath),
67
+ createElement('span', { className: 'rec-board-path' }, headerPath),
66
68
  createElement('span', { className: 'rec-board-count' }, runs.length + ' runs'),
67
69
  createElement(ThemeToggle, { theme, toggle }),
68
70
  closeButton(onClose),
@@ -157,7 +157,7 @@ export function RecursiveBoardOverlay({ useSessions, useWorkspaces }: { useSessi
157
157
  onClose: () => boardState.close(),
158
158
  })
159
159
  }
160
- return createElement(Board, { snapshot, onOpenInspector: (sel) => boardState.openInspector(sel), onClose: () => boardState.close() })
160
+ return createElement(Board, { snapshot, workspacePath: wsPath, onOpenInspector: (sel) => boardState.openInspector(sel), onClose: () => boardState.close() })
161
161
  }
162
162
 
163
163
  /**
@@ -33,7 +33,11 @@ export function useLiveProjection(scope: LiveScope): LiveProjectionSnapshot {
33
33
 
34
34
  useEffect(() => {
35
35
  // Empty scope = no resolvable session row yet — render nothing, never fetch.
36
- if (isEmpty(scope)) return
36
+ if (isEmpty(scope)) { setState(null); return }
37
+ // 0.1.16 (LIVE BUG 3): RESET the snapshot synchronously on scope change so
38
+ // the board never renders the PREVIOUS workspace's {root, projection} during
39
+ // a switch. The fresh fetch below re-populates state only when it resolves.
40
+ setState(null)
37
41
  let disposed = false
38
42
  const apply = (frame: LiveRecursiveFrame) => { if (!disposed) setState(frame) }
39
43
 
package/src/live-route.ts CHANGED
@@ -97,8 +97,9 @@ export function makeRecursiveRoutes(host: RecursiveRouteHost): readonly { kind:
97
97
  const root = sessionId === undefined && cwd === '' ? null : await host.resolveRoot(sessionId, cwd)
98
98
  if (root === null) { res.writeHead(200, { 'content-type': 'text/event-stream; charset=utf-8', 'cache-control': 'no-cache', connection: 'keep-alive' }); res.write('data: {"root":null,"projection":{},"revision":0}\n\n'); res.end(); return }
99
99
  res.writeHead(200, { 'content-type': 'text/event-stream; charset=utf-8', 'cache-control': 'no-cache', connection: 'keep-alive' })
100
- const push = (): void => {
101
- const payload = { root, projection: host.snapshot(root), revision: host.revision(root) }
100
+ const push = async (): Promise<void> => {
101
+ const projection = await host.snapshot(root)
102
+ const payload = { root, projection, revision: host.revision(root) }
102
103
  res.write('data: ' + JSON.stringify(payload) + '\n\n')
103
104
  }
104
105
  const heartbeat = setInterval(() => { res.write(': ping\n\n') }, HEARTBEAT_MS)