@try-works/dsh-recursive-mode 0.3.0 → 0.4.0

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 (120) hide show
  1. package/README.md +959 -0
  2. package/lib/client.js +9 -2
  3. package/lib/closeout-report.d.ts +113 -0
  4. package/lib/closeout-standards.d.ts +35 -0
  5. package/lib/closeout.d.ts +12 -0
  6. package/lib/commands.d.ts +1 -1
  7. package/lib/config.d.ts +202 -0
  8. package/lib/delegation.d.ts +123 -3
  9. package/lib/enforcement.d.ts +90 -1
  10. package/lib/errors.d.ts +168 -0
  11. package/lib/git-context.d.ts +17 -0
  12. package/lib/guard-log.d.ts +39 -0
  13. package/lib/handoff.d.ts +29 -0
  14. package/lib/hooks.d.ts +103 -0
  15. package/lib/identity.d.ts +61 -0
  16. package/lib/index.d.ts +33 -12
  17. package/lib/index.js +10017 -3969
  18. package/lib/job-log.d.ts +34 -0
  19. package/lib/jobs-runner.d.ts +105 -0
  20. package/lib/json-safe.d.ts +33 -0
  21. package/lib/lock.d.ts +42 -0
  22. package/lib/memory-feedback.d.ts +52 -0
  23. package/lib/memory-select.d.ts +78 -0
  24. package/lib/memory.d.ts +137 -0
  25. package/lib/model-inventory.d.ts +106 -0
  26. package/lib/phase-graph.d.ts +111 -0
  27. package/lib/phase-rules.d.ts +67 -8
  28. package/lib/plan-gate.d.ts +68 -0
  29. package/lib/policy-globs.d.ts +222 -0
  30. package/lib/policy-write.d.ts +42 -0
  31. package/lib/policy.d.ts +39 -0
  32. package/lib/recursive_ask.tool.d.ts +88 -0
  33. package/lib/recursive_closeout.tool.d.ts +1 -1
  34. package/lib/recursive_delegate.tool.d.ts +22 -0
  35. package/lib/recursive_preview.tool.d.ts +48 -0
  36. package/lib/recursive_review.tool.d.ts +28 -0
  37. package/lib/result-cap.d.ts +70 -0
  38. package/lib/review-round.d.ts +82 -0
  39. package/lib/review.d.ts +9 -0
  40. package/lib/role-route.d.ts +122 -0
  41. package/lib/router.d.ts +90 -5
  42. package/lib/runtime.d.ts +252 -12
  43. package/lib/settlement.d.ts +132 -0
  44. package/lib/skills-phase.d.ts +71 -0
  45. package/lib/skills.d.ts +70 -0
  46. package/lib/status.d.ts +53 -1
  47. package/lib/teams-loop.d.ts +91 -2
  48. package/lib/training.d.ts +211 -0
  49. package/lib/ts-lint.d.ts +15 -0
  50. package/lib/types.d.ts +48 -0
  51. package/lib/workflow-audit.d.ts +207 -0
  52. package/package.json +31 -31
  53. package/preset/recursive.patch.yml +312 -0
  54. package/scripts/e2e-run.mjs +51 -0
  55. package/scripts/link-dsh.mjs +233 -0
  56. package/scripts/live/fake-llm.mjs +150 -0
  57. package/scripts/live-session-plugin.mjs +179 -0
  58. package/scripts/live-session-stock.mjs +106 -0
  59. package/scripts/live-session.mjs +139 -0
  60. package/skills/recursive-mode/SKILL.md +66 -0
  61. package/src/client/derive.ts +18 -2
  62. package/src/closeout-report.ts +274 -0
  63. package/src/closeout-standards.ts +102 -0
  64. package/src/closeout.ts +39 -2
  65. package/src/commands.ts +116 -4
  66. package/src/config.ts +113 -0
  67. package/src/delegation.ts +336 -18
  68. package/src/enforcement.ts +262 -72
  69. package/src/errors.ts +197 -0
  70. package/src/git-context.ts +33 -2
  71. package/src/guard-log.ts +134 -0
  72. package/src/handoff.ts +62 -0
  73. package/src/hooks.ts +316 -0
  74. package/src/identity.ts +230 -0
  75. package/src/index.ts +394 -20
  76. package/src/job-log.ts +112 -0
  77. package/src/jobs-runner.ts +222 -0
  78. package/src/json-safe.ts +75 -0
  79. package/src/lock.ts +153 -16
  80. package/src/memory-feedback.ts +185 -0
  81. package/src/memory-select.ts +187 -0
  82. package/src/memory.ts +309 -0
  83. package/src/model-inventory.ts +196 -0
  84. package/src/phase-graph.ts +191 -0
  85. package/src/phase-rules.ts +236 -0
  86. package/src/plan-gate.ts +111 -0
  87. package/src/policy-globs.ts +636 -0
  88. package/src/policy-write.ts +210 -0
  89. package/src/policy.ts +70 -5
  90. package/src/recursive_ask.tool.ts +276 -0
  91. package/src/recursive_audit_team.tool.ts +7 -3
  92. package/src/recursive_closeout.tool.ts +36 -35
  93. package/src/recursive_delegate.tool.ts +194 -0
  94. package/src/recursive_init.tool.ts +4 -3
  95. package/src/recursive_lint.tool.ts +81 -6
  96. package/src/recursive_lock.tool.ts +21 -4
  97. package/src/recursive_phase.tool.ts +3 -2
  98. package/src/recursive_preview.tool.ts +142 -0
  99. package/src/recursive_review.tool.ts +190 -0
  100. package/src/recursive_scratch.tool.ts +5 -4
  101. package/src/recursive_status.tool.ts +3 -2
  102. package/src/recursive_worktree.tool.ts +6 -5
  103. package/src/result-cap.ts +130 -0
  104. package/src/review-round.ts +335 -0
  105. package/src/review.ts +17 -3
  106. package/src/role-route.ts +230 -0
  107. package/src/router.ts +128 -2
  108. package/src/runtime.ts +968 -39
  109. package/src/settlement.ts +355 -0
  110. package/src/skills-phase.ts +143 -0
  111. package/src/skills.ts +151 -0
  112. package/src/snapshot.ts +39 -8
  113. package/src/status.ts +209 -4
  114. package/src/teams-loop.ts +223 -9
  115. package/src/training.ts +565 -0
  116. package/src/ts-lint.ts +38 -4
  117. package/src/types.ts +51 -0
  118. package/src/workflow-audit.ts +288 -0
  119. package/scripts/install-preset.cmd +0 -7
  120. package/scripts/install-preset.js +0 -101
@@ -0,0 +1,111 @@
1
+ /**
2
+ * T13 — planMode for the discovery phases, and the gate out of them.
3
+ *
4
+ * WHY. Requirements / AS-IS / TO-BE-Plan are NON-MUTATING discovery. Running them under the
5
+ * harness's planMode enforces "plan before implement" at the harness level instead of by
6
+ * convention: a phase that cannot write cannot quietly start implementing while it is still
7
+ * deciding what to implement. Convention is what fails at 2am; a mode is what holds.
8
+ *
9
+ * ⚠ THE PHASE-FORM TRAP, which is why this module exists rather than a one-line comparison.
10
+ * This codebase names a phase THREE ways — `'2'`, `'02'`, and the artifact filename
11
+ * `'02-to-be-plan.md'` — and a mapping that understood only one of them would return `false`
12
+ * for the others. That failure is SILENT and in the dangerous direction: it turns the
13
+ * non-mutating guarantee OFF for exactly the phases that need it. So the index is parsed from
14
+ * the leading numeric run, and every form lands on the same answer.
15
+ *
16
+ * ⚠ AN UNRECOGNISED PHASE ANSWERS `false`, deliberately. Claiming plan mode for a phase we
17
+ * cannot identify would be guessing about the one property this module exists to guarantee;
18
+ * the safe reading of "I do not know what this is" is "do not assert a mode about it". The
19
+ * caller that needs certainty has {@link phaseIndexOf} and can refuse instead.
20
+ */
21
+
22
+ /**
23
+ * The numeric index of a phase, from any of the forms this codebase uses, or `null` when the
24
+ * input names no phase at all.
25
+ *
26
+ * Takes the leading numeric run, so `'2'`, `'02'`, `' 2 '` and `'02-to-be-plan.md'` all give
27
+ * `2`, and `'01.5-root-cause.md'` gives `1.5` — the fractional sub-phase keeps its position
28
+ * between 01 and 02, which is what makes `phaseUsesPlanMode` include it.
29
+ */
30
+ export function phaseIndexOf(phase: string): number | null {
31
+ if (typeof phase !== 'string') return null
32
+ const match = /^\s*(\d+(?:\.\d+)?)/.exec(phase)
33
+ if (match === null) return null
34
+ const value = Number(match[1])
35
+ return Number.isFinite(value) ? value : null
36
+ }
37
+
38
+ /**
39
+ * The exclusive upper bound of the discovery block: phases below this are non-mutating.
40
+ *
41
+ * 3 = implementation. Everything strictly below it (0 requirements, 1 AS-IS, 1.5 root cause,
42
+ * 2 TO-BE plan) is discovery, which is the item's "00-02" plus the sub-phase that sits inside
43
+ * that range.
44
+ */
45
+ export const IMPLEMENTATION_PHASE_INDEX = 3
46
+
47
+ /** True when the phase is discovery and must run non-mutating. */
48
+ export function phaseUsesPlanMode(phase: string): boolean {
49
+ const index = phaseIndexOf(phase)
50
+ if (index === null) return false
51
+ return index >= 0 && index < IMPLEMENTATION_PHASE_INDEX
52
+ }
53
+
54
+ /**
55
+ * True when a transition LEAVES the discovery block — the plan gate.
56
+ *
57
+ * The gate is on the DESTINATION, not the distance: `02 -> 03` and `02 -> 04` both need an
58
+ * approved plan, because skipping ahead does not make the plan less necessary. A transition
59
+ * that stays inside discovery (0 -> 1) is not gated, and one that starts after the boundary
60
+ * (3 -> 4) is not either — the plan was already required to get there.
61
+ */
62
+ export function planGateRequired(from: string, to: string): boolean {
63
+ const target = phaseIndexOf(to)
64
+ const source = phaseIndexOf(from)
65
+ if (target === null) return false
66
+ if (target < IMPLEMENTATION_PHASE_INDEX) return false
67
+ // From inside discovery (or from an unknown point) out to implementation or beyond.
68
+ return source === null || source < IMPLEMENTATION_PHASE_INDEX
69
+ }
70
+
71
+ /** A one-line, board-facing statement of what the phase owes, for a phase rules section. */
72
+ export function describePlanMode(phase: string): string {
73
+ if (phaseUsesPlanMode(phase)) {
74
+ return 'phase ' + phase + ' runs NON-MUTATING (planMode): discovery must not write, and the plan gate out of discovery is 02 -> 03.'
75
+ }
76
+ const index = phaseIndexOf(phase)
77
+ if (index === null) return 'phase ' + phase + ' is not a recognised phase, so no plan-mode claim is made for it.'
78
+ return 'phase ' + phase + ' is past discovery, so it may write and is no longer plan-gated.'
79
+ }
80
+
81
+ /**
82
+ * T13 — should `exit_plan_mode` be allowed, given the phase the run is WAITING on?
83
+ *
84
+ * The run's "next legal phase" is exactly the right input: while it is still a discovery
85
+ * phase, the plan is not finished and leaving plan mode would start implementing on an
86
+ * unfinished plan; once it is an implementation phase, discovery is done and the gate is
87
+ * open. So the gate needs no separate state — it reads the state the run already keeps, and
88
+ * that is why it cannot drift from the workflow.
89
+ *
90
+ * ⚠ A NULL next phase means "nothing is pending", which is NOT the same as "discovery is
91
+ * done". It allows the exit, because refusing forever on a completed or unrecognised run
92
+ * would make plan mode a trap rather than a gate — and the reason is stated so a reader can
93
+ * tell the two cases apart.
94
+ */
95
+ export function planGateForExit(nextPhase: string | null): { allow: boolean; reason: string } {
96
+ if (nextPhase === null) {
97
+ return { allow: true, reason: 'no phase is pending, so nothing is held back by the plan gate.' }
98
+ }
99
+ if (phaseUsesPlanMode(nextPhase)) {
100
+ return {
101
+ allow: false,
102
+ reason: 'plan gate: phase ' + nextPhase + ' is still discovery, so the plan is not finished. '
103
+ + 'Complete it (and lock its artifact) before leaving plan mode; the gate opens at 02 -> 03.',
104
+ }
105
+ }
106
+ const index = phaseIndexOf(nextPhase)
107
+ if (index === null) {
108
+ return { allow: true, reason: 'phase ' + nextPhase + ' is not a recognised phase, so the plan gate makes no claim about it.' }
109
+ }
110
+ return { allow: true, reason: 'discovery is complete (next phase is ' + nextPhase + '), so the plan gate is open.' }
111
+ }