@try-works/dsh-recursive-mode 0.1.3 → 0.1.4

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.
Files changed (123) hide show
  1. package/cordis.patch.yml +15 -10
  2. package/lib/bootstrap.d.ts +9 -2
  3. package/lib/client/apply-guard.d.ts +14 -0
  4. package/lib/client/board.d.ts +5 -4
  5. package/lib/client/contract.d.ts +57 -24
  6. package/lib/client/host-api.d.ts +26 -0
  7. package/lib/client/index.d.ts +16 -9
  8. package/lib/client/inspector.d.ts +3 -3
  9. package/lib/client/slots.d.ts +4 -6
  10. package/lib/client/strip.d.ts +4 -3
  11. package/lib/client/use-live.d.ts +9 -0
  12. package/lib/client.js +252 -174
  13. package/lib/index.d.ts +11 -11
  14. package/lib/index.js +972 -4504
  15. package/lib/init-templates.d.ts +41 -0
  16. package/lib/live-route.d.ts +69 -0
  17. package/lib/phase-rules.d.ts +34 -0
  18. package/lib/runtime.d.ts +24 -17
  19. package/lib/snapshot.d.ts +11 -0
  20. package/package.json +4 -3
  21. package/preset/recursive/agent.cordis.yml +7 -4
  22. package/preset/recursive/preset.yml +1 -1
  23. package/references/agents-block.md +95 -0
  24. package/references/artifact-template.md +2574 -0
  25. package/references/bodies/claude.md +7 -0
  26. package/references/bodies/codex-agents.md +95 -0
  27. package/references/bodies/copilot.md +7 -0
  28. package/references/bodies/cursorrules.md +7 -0
  29. package/references/bodies/decisions.md +5 -0
  30. package/references/bodies/delegated-verification.md +49 -0
  31. package/references/bodies/memory-router.md +45 -0
  32. package/references/bodies/phase8-skill-memory.md +48 -0
  33. package/references/bodies/plans-bridge.md +43 -0
  34. package/references/bodies/recursive-agents-router.md +64 -0
  35. package/references/bodies/skill-discovery.md +51 -0
  36. package/references/bodies/skill-memory-router.md +42 -0
  37. package/references/bodies/state.md +5 -0
  38. package/references/bootstrap/RECURSIVE.md +2362 -0
  39. package/references/scripts/__pycache__/recursive_phase_rules.cpython-314.pyc +0 -0
  40. package/references/scripts/lint-recursive-run.ps1 +25 -0
  41. package/references/scripts/lint-recursive-run.py +2870 -0
  42. package/references/scripts/recursive-closeout.ps1 +38 -0
  43. package/references/scripts/recursive-closeout.py +541 -0
  44. package/references/scripts/recursive-init.ps1 +515 -0
  45. package/references/scripts/recursive-init.py +356 -0
  46. package/references/scripts/recursive-lock.ps1 +26 -0
  47. package/references/scripts/recursive-lock.py +302 -0
  48. package/references/scripts/recursive-review-bundle.ps1 +58 -0
  49. package/references/scripts/recursive-review-bundle.py +503 -0
  50. package/references/scripts/recursive-router-cli-configure.ps1 +2 -0
  51. package/references/scripts/recursive-router-cli-configure.py +9 -0
  52. package/references/scripts/recursive-router-cli-init.ps1 +2 -0
  53. package/references/scripts/recursive-router-cli-init.py +9 -0
  54. package/references/scripts/recursive-router-cli-invoke.ps1 +2 -0
  55. package/references/scripts/recursive-router-cli-invoke.py +9 -0
  56. package/references/scripts/recursive-router-cli-probe.ps1 +2 -0
  57. package/references/scripts/recursive-router-cli-probe.py +9 -0
  58. package/references/scripts/recursive-router-cli-resolve.ps1 +2 -0
  59. package/references/scripts/recursive-router-cli-resolve.py +9 -0
  60. package/references/scripts/recursive-router-cli-validate.ps1 +2 -0
  61. package/references/scripts/recursive-router-cli-validate.py +9 -0
  62. package/references/scripts/recursive-router-configure.ps1 +27 -0
  63. package/references/scripts/recursive-router-configure.py +74 -0
  64. package/references/scripts/recursive-router-init.ps1 +17 -0
  65. package/references/scripts/recursive-router-init.py +29 -0
  66. package/references/scripts/recursive-router-invoke.ps1 +47 -0
  67. package/references/scripts/recursive-router-invoke.py +103 -0
  68. package/references/scripts/recursive-router-probe.ps1 +25 -0
  69. package/references/scripts/recursive-router-probe.py +44 -0
  70. package/references/scripts/recursive-router-resolve.ps1 +26 -0
  71. package/references/scripts/recursive-router-resolve.py +46 -0
  72. package/references/scripts/recursive-router-validate.ps1 +17 -0
  73. package/references/scripts/recursive-router-validate.py +27 -0
  74. package/references/scripts/recursive-status.ps1 +23 -0
  75. package/references/scripts/recursive-status.py +2124 -0
  76. package/references/scripts/recursive-subagent-action.ps1 +98 -0
  77. package/references/scripts/recursive-subagent-action.py +197 -0
  78. package/references/scripts/recursive-training-extract.ps1 +23 -0
  79. package/references/scripts/recursive-training-extract.py +99 -0
  80. package/references/scripts/recursive-training-grpo.ps1 +52 -0
  81. package/references/scripts/recursive-training-grpo.py +1341 -0
  82. package/references/scripts/recursive-training-loader.ps1 +78 -0
  83. package/references/scripts/recursive-training-loader.py +558 -0
  84. package/references/scripts/recursive-training-mcp.ps1 +29 -0
  85. package/references/scripts/recursive-training-mcp.py +261 -0
  86. package/references/scripts/recursive-training-phase8-trigger.ps1 +55 -0
  87. package/references/scripts/recursive-training-phase8-trigger.py +137 -0
  88. package/references/scripts/recursive-training-sync.ps1 +29 -0
  89. package/references/scripts/recursive-training-sync.py +183 -0
  90. package/references/scripts/recursive_phase_rules.py +367 -0
  91. package/references/scripts/recursive_router_cli_lib.py +2 -0
  92. package/references/scripts/recursive_router_lib.py +2282 -0
  93. package/references/scripts/verify-locks.ps1 +25 -0
  94. package/references/scripts/verify-locks.py +353 -0
  95. package/scripts/__pycache__/lint-recursive-run.cpython-314.pyc +0 -0
  96. package/scripts/__pycache__/recursive_phase_rules.cpython-314.pyc +0 -0
  97. package/scripts/install-preset.cmd +7 -0
  98. package/scripts/install-preset.js +101 -0
  99. package/scripts/lint-recursive-run.py +7 -5
  100. package/scripts/test-recursive-mode-smoke.ts +29 -28
  101. package/src/bootstrap.ts +253 -39
  102. package/src/client/apply-guard.ts +23 -0
  103. package/src/client/board.tsx +0 -0
  104. package/src/client/contract.ts +72 -24
  105. package/src/client/host-api.ts +90 -0
  106. package/src/client/index.ts +22 -11
  107. package/src/client/inspector.tsx +7 -9
  108. package/src/client/slots.ts +70 -26
  109. package/src/client/strip.tsx +9 -9
  110. package/src/client/use-live.ts +52 -0
  111. package/src/index.ts +89 -146
  112. package/src/init-templates.ts +276 -0
  113. package/src/live-route.ts +163 -0
  114. package/src/phase-rules.ts +262 -0
  115. package/src/policy.ts +28 -4
  116. package/src/runtime.ts +129 -77
  117. package/src/snapshot.ts +104 -0
  118. package/lib/client/node.d.ts +0 -71
  119. package/lib/events.d.ts +0 -173
  120. package/lib/projection.d.ts +0 -29
  121. package/src/client/node.ts +0 -156
  122. package/src/events.ts +0 -173
  123. package/src/projection.ts +0 -237
package/cordis.patch.yml CHANGED
@@ -1,12 +1,17 @@
1
- # dsh-recursive-mode bundle patch: inserts the RecursiveRuntime service realm and the
2
- # recursive_status tool over the profile root. The cordis:group realm keeps the service
3
- # out of the root realm (R2: registered exactly once, no collision on double-mount).
4
-
1
+ # dsh-recursive-mode bundle patch client-discovery shell (R4, decision 02-to-be-plan.addendum-r4-r2-mount-resolution.md).
2
+ #
3
+ # A single ENABLED bare-name row exists so the host's ClientModuleRegistry can
4
+ # discover this package's client half (dsh.client.inject -> /plugins/<id>/client.js).
5
+ # Client discovery requires an ENABLED bare-name entry (entry.fiber !== undefined &&
6
+ # !entry.disabled); preset-mounted subtrees are absent from ctx.loader.entries().
7
+ #
8
+ # The row's apply() is a NO-OP under config.shellOnly=true (see src/index.ts):
9
+ # it contributes the client bundle and registers NOTHING on the server root —
10
+ # no tools, no /recursive command, no recursive:policy, no projection. The full
11
+ # server surface is mounted ONLY by the `recursive` agent preset's isolated
12
+ # recursive-realm (preset/recursive/agent.cordis.yml).
5
13
  - insert:
6
- - id: recursive-realm
7
- name: cordis:group
8
- isolate:
9
- recursive: true
14
+ - id: recursive
15
+ name: '@try-works/dsh-recursive-mode'
10
16
  config:
11
- - id: recursive
12
- name: '@try-works/dsh-recursive-mode'
17
+ shellOnly: true
@@ -1,3 +1,7 @@
1
+ /** Package root: <package>/src/.. — references/ sits next to src/. */
2
+ export declare const PACKAGE_ROOT: string;
3
+ /** references/ root (shipped package files). */
4
+ export declare function referencesRoot(): string;
1
5
  export interface BootstrapResult {
2
6
  root: string;
3
7
  bootstrapped: boolean;
@@ -11,9 +15,12 @@ export interface StageBResult {
11
15
  runs: string[];
12
16
  activeRunId?: string;
13
17
  }
18
+ /** write_utf8_no_bom: LF newlines, no BOM. */
19
+ export declare function writeUtf8NoBom(path: string, content: string): void;
14
20
  /**
15
- * Idempotent scaffold install: creates the /.recursive/ control plane when
16
- * missing. Never overwrites existing files; preserves unrelated content.
21
+ * Idempotent scaffold install: reproduce the canonical installer's 82-file
22
+ * tree byte-for-byte. Never overwrites existing user content; marked blocks
23
+ * are re-upserted in place.
17
24
  */
18
25
  export declare function bootstrapScaffold(root: string): BootstrapResult;
19
26
  /**
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Cross-module-instance apply guard for the recursive client bundle (mirrors
3
+ * the dsh-task-board apply-guard). The client factory can run more than once in
4
+ * a single page lifetime (a stale bundle mixed with a rebuilt one); without a
5
+ * guard every factory run mounts its own board/strip. First claim wins; later
6
+ * claims no-op until the claim is released (fiber unload / hot-reload).
7
+ */
8
+ declare global {
9
+ var __dshRecursiveModeClientApplied: boolean | undefined;
10
+ }
11
+ /** Claims the client apply slot. Returns true when this call won the slot. */
12
+ export declare function claimClientApply(): boolean;
13
+ /** Releases the claim (called from the client fiber cleanup on unload/hot-reload). */
14
+ export declare function releaseClientApply(): void;
@@ -1,10 +1,11 @@
1
1
  import type { RecursiveProjection, RecursiveRunCard } from '../types.ts';
2
- import type { RecursiveProjectionReader } from './contract.ts';
2
+ import type { LiveProjectionValue } from './contract.ts';
3
3
  /** Flatten the worktree-grouped projection into a stable run list. */
4
4
  export declare function listRuns(projection: RecursiveProjection | undefined): RecursiveRunCard[];
5
5
  export interface BoardProps {
6
- useProjection: RecursiveProjectionReader;
6
+ /** The live host-route snapshot (null = not loaded / no recursive root). */
7
+ snapshot: LiveProjectionValue | null;
7
8
  }
8
- export declare function Board({ useProjection }: BoardProps): import("react").DetailedReactHTMLElement<{
9
+ export declare function Board({ snapshot }: BoardProps): import("react").DetailedReactHTMLElement<{
9
10
  className: string;
10
- }, HTMLElement>;
11
+ }, HTMLElement> | null;
@@ -1,37 +1,55 @@
1
1
  /**
2
2
  * Structural client seams (self-contained). The real @deepseek-ai/dsh-client-*
3
3
  * packages are HOST-INJECTED at bundle time via dsh.client.inject (never
4
- * installed in this package's dependency tree they depend on workspace:^
5
- * peers that resolve only inside the DSH workspace). We declare the minimal
6
- * shapes we consume so the pure client modules type-check and bundle in
7
- * isolation; the DSH loader links them to the real runtime identities at
8
- * compose time.
4
+ * installed in this package's dependency tree). We declare the minimal shapes
5
+ * we consume so the pure client modules type-check and bundle in isolation;
6
+ * the DSH loader links them to the real runtime identities at compose time.
9
7
  *
10
- * One deliberate narrowing: the client only READS (R9 read-only). It never
11
- * calls back into the host; every host fact arrives through the projection.
8
+ * SP2 R1 (live route): the client now CALLS the host route (read-only GET
9
+ * state + SSE events) instead of reading a session projection. The host serves
10
+ * the per-workspace filesystem fold; this module never mutates the host and
11
+ * never touches the filesystem (R9).
12
12
  */
13
- /** SessionEvent-like carrier (the projection/node fold reads events by shape). */
13
+ import type { RecursiveProjection } from '../types.ts';
14
+ /** SessionEvent-like carrier (kept for the pure derive surface; the live route replaces the fold). */
14
15
  export interface ClientSessionEvent {
15
16
  type: string;
16
17
  seq?: number;
17
18
  time?: number;
18
19
  data?: Record<string, unknown>;
19
20
  }
20
- /** A session header (cwd is the control-plane root). */
21
+ /** A session header (cwd is the session's canonical cwd). */
21
22
  export interface ClientSessionHeader {
22
23
  cwd?: string;
23
24
  }
24
- /** Minimal appendable session (log-only write seam). */
25
- export interface ClientSession {
26
- header: ClientSessionHeader;
27
- append(type: string, data: unknown): unknown;
25
+ /** A session-list row (mirrors SessionSummary — cwd + agentPreset are the gate inputs). */
26
+ export interface SessionSummaryRow {
27
+ id: string;
28
+ cwd?: string;
29
+ /** Agent preset this session was composed from; absent when the deployment has none. */
30
+ agentPreset?: string;
28
31
  }
29
- /** The client root context the bundle receives from the module loader. */
30
- export interface ClientContext {
31
- slots: ClientSlots;
32
- get(name: string): unknown;
32
+ /** The session-list snapshot (mirrors SessionListState). */
33
+ export interface SessionListStateLike {
34
+ ids: string[];
35
+ byId: Record<string, SessionSummaryRow>;
36
+ current: string | undefined;
37
+ }
38
+ /** A snapshot store the client runtime hands out (mirrors SnapshotStore<T>). */
39
+ export interface SnapshotStoreLike<T> {
40
+ getSnapshot(): T;
41
+ subscribe(fn: () => void): () => void;
42
+ }
43
+ /** The sessions service surface (mirrors ISessions.list). */
44
+ export interface ISessionsLike {
45
+ list: SnapshotStoreLike<SessionListStateLike>;
46
+ }
47
+ /** The slots registry surface the client injects into. */
48
+ export interface ClientSlots {
49
+ inject(seat: string, factory: (ctx: unknown) => () => void): () => void;
50
+ register(options: SlotOptions, component: unknown): () => void;
33
51
  }
34
- /** A registered slot's options (list/keyed entries carry id/order/label). */
52
+ /** A registered slot's options. */
35
53
  export interface SlotOptions {
36
54
  name: string;
37
55
  id?: string;
@@ -42,10 +60,25 @@ export interface SlotOptions {
42
60
  locale?: unknown;
43
61
  registrant?: unknown;
44
62
  }
45
- /** The slot registry surface the client injects into. */
46
- export interface ClientSlots {
47
- inject(seat: string, factory: (ctx: unknown) => () => void): () => void;
48
- register(options: SlotOptions, component: unknown): () => void;
63
+ /** The client root context the bundle receives from the module loader. */
64
+ export interface ClientContext {
65
+ slots: ClientSlots;
66
+ get(name: string): unknown;
67
+ /** Cordis effect: registers a disposer; returns a disposer. */
68
+ effect(fn: () => () => void, label?: string): () => void;
69
+ }
70
+ /** The live state payload the host route serves (mirrors host-api.ts). */
71
+ export interface LiveProjectionValue {
72
+ root: string | null;
73
+ projection: RecursiveProjection;
74
+ revision: number;
49
75
  }
50
- /** useProjection('recursive') reader — undefined = capability absent. */
51
- export type RecursiveProjectionReader = (key: 'recursive') => unknown;
76
+ /**
77
+ * The client-side preset gate (acceptance #3): the board/strip render ONLY when
78
+ * the CURRENT session's row reports agentPreset === 'recursive'. A non-recursive
79
+ * session (or a session whose preset is undefined) shows NOTHING — not an empty
80
+ * board, not a spinner.
81
+ */
82
+ export declare function isRecursivePreset(sessions: ISessionsLike): boolean;
83
+ /** The current session's cwd (the client passes it as a fallback hint; the host resolves the root). */
84
+ export declare function currentSessionCwd(sessions: ISessionsLike): string;
@@ -0,0 +1,26 @@
1
+ import type { RecursiveProjection } from '../types.ts';
2
+ /** The state payload the host serves. */
3
+ export interface LiveRecursiveState {
4
+ root: string | null;
5
+ projection: RecursiveProjection;
6
+ revision: number;
7
+ }
8
+ /** A single SSE frame. */
9
+ export interface LiveRecursiveFrame extends LiveRecursiveState {
10
+ }
11
+ /** The client scope the host keys on: sessionId PRIMARY, cwd fallback hint. */
12
+ export interface LiveScope {
13
+ sessionId?: string;
14
+ cwd?: string;
15
+ }
16
+ /** Fetch the current state for one session scope (host resolves the workspace root). */
17
+ export declare function fetchLiveState(scope: LiveScope, signal?: AbortSignal): Promise<LiveRecursiveState>;
18
+ /**
19
+ * Subscribe to the SSE events feed. Returns a disposer. The host pushes a full
20
+ * {revision, root, projection} frame on every fs change + a 15s heartbeat.
21
+ *
22
+ * @param scope - sessionId primary + cwd fallback (host resolves the root).
23
+ * @param onFrame - called per data frame.
24
+ * @param onError - called when the stream fails/ends (the caller re-subscribes).
25
+ */
26
+ export declare function subscribeLiveEvents(scope: LiveScope, onFrame: (frame: LiveRecursiveFrame) => void, onError?: () => void): () => void;
@@ -1,21 +1,28 @@
1
1
  /**
2
- * Client entry (Phase D R4): the browser half of dsh-recursive-mode. Receives
3
- * the client root context from the DSH loader and registers the board,
4
- * inspector, conversation node, status strip, and settings page (§11.8).
5
- * READ-ONLY (R9): every host fact arrives through the recursive projection;
6
- * this module never touches the filesystem.
2
+ * Client entry (SP2 R1): the browser half of dsh-recursive-mode. Receives the
3
+ * client root context from the DSH loader and registers the board, inspector,
4
+ * status strip, and settings page. The board/strip read the LIVE host route
5
+ * (per-workspace filesystem fold) not a session projection and render ONLY
6
+ * for the recursive preset (acceptance #3). READ-ONLY (R9): the client never
7
+ * mutates the host.
7
8
  *
8
9
  * The apply(ctx) surface mirrors the shipped dsh-client-ui-* packages; the
9
10
  * dsh.client.inject list in package.json names the host packages the loader
10
11
  * must provide (they are injected at compose time, never installed here).
12
+ * The apply-guard prevents a stale+rebuilt bundle from double-mounting.
11
13
  */
12
14
  import type { ClientContext } from './contract.ts';
13
- export { recursiveNodeDefinition, RECURSIVE_NODE_KIND, matchRecursiveNode, foldRecursiveNode } from './node.ts';
14
- export type { RecursiveNodeData, RecursiveNodeState } from './node.ts';
15
15
  export { Board, listRuns } from './board.tsx';
16
16
  export { Inspector } from './inspector.tsx';
17
17
  export { StatusStrip } from './strip.tsx';
18
18
  export { RecursiveSettings } from './settings.tsx';
19
- export type { RecursiveProjectionReader } from './contract.ts';
20
- /** Browser-half plugin entry (R4). */
19
+ export { useLiveProjection } from './use-live.ts';
20
+ export type { LiveProjectionSnapshot } from './use-live.ts';
21
+ export { fetchLiveState, subscribeLiveEvents } from './host-api.ts';
22
+ export type { LiveRecursiveState, LiveRecursiveFrame, LiveScope } from './host-api.ts';
23
+ export { isRecursivePreset, currentSessionCwd } from './contract.ts';
24
+ export type { SessionSummaryRow, SessionListStateLike, ISessionsLike, ClientContext } from './contract.ts';
25
+ /** Required services (fiber inject waiting — the runtime must be up first). */
26
+ export declare const inject: string[];
27
+ /** Browser-half plugin entry (R4 + SP2 R1). */
21
28
  export declare function apply(ctx: ClientContext): void;
@@ -1,10 +1,10 @@
1
- import type { RecursiveProjectionReader } from './contract.ts';
1
+ import type { LiveProjectionValue } from './contract.ts';
2
2
  export interface InspectorProps {
3
3
  runId: string;
4
4
  worktreeRoot: string;
5
- useProjection: RecursiveProjectionReader;
5
+ snapshot: LiveProjectionValue | null;
6
6
  onBackToToolDetails: () => void;
7
7
  }
8
- export declare function Inspector({ runId, worktreeRoot, useProjection, onBackToToolDetails }: InspectorProps): import("react").DetailedReactHTMLElement<{
8
+ export declare function Inspector({ runId, worktreeRoot, snapshot, onBackToToolDetails }: InspectorProps): import("react").DetailedReactHTMLElement<{
9
9
  className: string;
10
10
  }, HTMLElement>;
@@ -1,7 +1,5 @@
1
- import type { ClientContext, RecursiveProjectionReader } from './contract.ts';
2
- import type { RecursiveProjection } from '../types.ts';
3
- /** Narrow the projection whole value to the worktree-grouped run map. */
4
- declare function projectionOf(reader: RecursiveProjectionReader): RecursiveProjection | undefined;
1
+ import type { ClientContext } from './contract.ts';
2
+ import { isRecursivePreset, currentSessionCwd } from './contract.ts';
5
3
  export declare function registerSlots(ctx: ClientContext): () => void;
6
- /** Export the projection reader narrow for the board/inspector/strip. */
7
- export { projectionOf };
4
+ /** Export the gate helpers for tests. */
5
+ export { isRecursivePreset, currentSessionCwd };
@@ -1,7 +1,8 @@
1
- import type { RecursiveProjectionReader } from './contract.ts';
1
+ import type { LiveProjectionValue } from './contract.ts';
2
2
  export interface StripProps {
3
- useProjection: RecursiveProjectionReader;
3
+ /** The live host-route snapshot (null = not loaded / no recursive root). */
4
+ snapshot: LiveProjectionValue | null;
4
5
  }
5
- export declare function StatusStrip({ useProjection }: StripProps): import("react").DetailedReactHTMLElement<{
6
+ export declare function StatusStrip({ snapshot }: StripProps): import("react").DetailedReactHTMLElement<{
6
7
  className: string;
7
8
  }, HTMLElement> | null;
@@ -0,0 +1,9 @@
1
+ import { type LiveRecursiveState, type LiveScope } from './host-api.ts';
2
+ /** Snapshot shape the board/strip consume (null = not loaded / no recursive root). */
3
+ export type LiveProjectionSnapshot = LiveRecursiveState | null;
4
+ /**
5
+ * Subscribe to the live route for one scope. Returns the current state. The SSE
6
+ * feed pushes full frames on every fs change; a dropped stream (sleep/error)
7
+ * triggers one refetch so the board never serves a stale fold.
8
+ */
9
+ export declare function useLiveProjection(scope: LiveScope): LiveProjectionSnapshot;