rhachet-roles-bhrain 0.31.0 → 0.31.2

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 (104) hide show
  1. package/dist/contract/cli/learn.d.ts +9 -0
  2. package/dist/contract/cli/learn.js +342 -0
  3. package/dist/contract/cli/learn.js.map +1 -0
  4. package/dist/contract/cli/route.js +42 -33
  5. package/dist/contract/cli/route.js.map +1 -1
  6. package/dist/domain.objects/Driver/PassageReport.d.ts +13 -2
  7. package/dist/domain.objects/Driver/PassageReport.js.map +1 -1
  8. package/dist/domain.objects/Driver/RouteStoneDisposition.d.ts +19 -0
  9. package/dist/domain.objects/Driver/RouteStoneDisposition.js +3 -0
  10. package/dist/domain.objects/Driver/RouteStoneDisposition.js.map +1 -0
  11. package/dist/domain.objects/Driver/RouteStoneGuardBlockerReport.d.ts +10 -3
  12. package/dist/domain.objects/Driver/RouteStoneGuardBlockerReport.js.map +1 -1
  13. package/dist/domain.operations/cli/getInvocationArgs.d.ts +8 -0
  14. package/dist/domain.operations/cli/getInvocationArgs.js +17 -0
  15. package/dist/domain.operations/cli/getInvocationArgs.js.map +1 -0
  16. package/dist/domain.operations/cli/isNodeEvalMode.d.ts +13 -0
  17. package/dist/domain.operations/cli/isNodeEvalMode.js +27 -0
  18. package/dist/domain.operations/cli/isNodeEvalMode.js.map +1 -0
  19. package/dist/domain.operations/learn/genDomainTermsScaffold.d.ts +18 -0
  20. package/dist/domain.operations/learn/genDomainTermsScaffold.js +90 -0
  21. package/dist/domain.operations/learn/genDomainTermsScaffold.js.map +1 -0
  22. package/dist/domain.operations/learn/genFile.d.ts +25 -0
  23. package/dist/domain.operations/learn/genFile.js +72 -0
  24. package/dist/domain.operations/learn/genFile.js.map +1 -0
  25. package/dist/domain.operations/learn/genSymlink.d.ts +26 -0
  26. package/dist/domain.operations/learn/genSymlink.js +78 -0
  27. package/dist/domain.operations/learn/genSymlink.js.map +1 -0
  28. package/dist/domain.operations/learn/getDomainTermsPaths.d.ts +25 -0
  29. package/dist/domain.operations/learn/getDomainTermsPaths.js +65 -0
  30. package/dist/domain.operations/learn/getDomainTermsPaths.js.map +1 -0
  31. package/dist/domain.operations/learn/getFsErrorCode.d.ts +9 -0
  32. package/dist/domain.operations/learn/getFsErrorCode.js +20 -0
  33. package/dist/domain.operations/learn/getFsErrorCode.js.map +1 -0
  34. package/dist/domain.operations/learn/getSweepProgress.d.ts +13 -0
  35. package/dist/domain.operations/learn/getSweepProgress.js +61 -0
  36. package/dist/domain.operations/learn/getSweepProgress.js.map +1 -0
  37. package/dist/domain.operations/learn/isProgressArticulated.d.ts +23 -0
  38. package/dist/domain.operations/learn/isProgressArticulated.js +33 -0
  39. package/dist/domain.operations/learn/isProgressArticulated.js.map +1 -0
  40. package/dist/domain.operations/learn/isSweepStale.d.ts +20 -0
  41. package/dist/domain.operations/learn/isSweepStale.js +32 -0
  42. package/dist/domain.operations/learn/isSweepStale.js.map +1 -0
  43. package/dist/domain.operations/route/drive/asRouteDisplayPath.d.ts +11 -0
  44. package/dist/domain.operations/route/drive/asRouteDisplayPath.js +38 -0
  45. package/dist/domain.operations/route/drive/asRouteDisplayPath.js.map +1 -0
  46. package/dist/domain.operations/route/drive/asRouteStoneDisposition.d.ts +16 -0
  47. package/dist/domain.operations/route/drive/asRouteStoneDisposition.js +52 -0
  48. package/dist/domain.operations/route/drive/asRouteStoneDisposition.js.map +1 -0
  49. package/dist/domain.operations/route/drive/formatRouteDriveBudgetExhausted.d.ts +14 -0
  50. package/dist/domain.operations/route/drive/formatRouteDriveBudgetExhausted.js +60 -0
  51. package/dist/domain.operations/route/drive/formatRouteDriveBudgetExhausted.js.map +1 -0
  52. package/dist/domain.operations/route/drive/getCurrentExhaustedSlugs.d.ts +16 -0
  53. package/dist/domain.operations/route/drive/getCurrentExhaustedSlugs.js +36 -0
  54. package/dist/domain.operations/route/drive/getCurrentExhaustedSlugs.js.map +1 -0
  55. package/dist/domain.operations/route/drive/getRouteDriveBlockerMessage.js +6 -106
  56. package/dist/domain.operations/route/drive/getRouteDriveBlockerMessage.js.map +1 -1
  57. package/dist/domain.operations/route/drive/getRouteDriveExhaustedMessage.d.ts +13 -0
  58. package/dist/domain.operations/route/drive/getRouteDriveExhaustedMessage.js +30 -0
  59. package/dist/domain.operations/route/drive/getRouteDriveExhaustedMessage.js.map +1 -0
  60. package/dist/domain.operations/route/drive/getStoneGuardBlockerReport.js +12 -10
  61. package/dist/domain.operations/route/drive/getStoneGuardBlockerReport.js.map +1 -1
  62. package/dist/domain.operations/route/drive/setStoneGuardBlockerReport.d.ts +7 -2
  63. package/dist/domain.operations/route/drive/setStoneGuardBlockerReport.js +5 -0
  64. package/dist/domain.operations/route/drive/setStoneGuardBlockerReport.js.map +1 -1
  65. package/dist/domain.operations/route/passage/getAllLatestPassageByStone.d.ts +18 -0
  66. package/dist/domain.operations/route/passage/getAllLatestPassageByStone.js +29 -0
  67. package/dist/domain.operations/route/passage/getAllLatestPassageByStone.js.map +1 -0
  68. package/dist/domain.operations/route/passage/getAllPassageReports.d.ts +1 -1
  69. package/dist/domain.operations/route/passage/getAllPassageReports.js +3 -40
  70. package/dist/domain.operations/route/passage/getAllPassageReports.js.map +1 -1
  71. package/dist/domain.operations/route/passage/getAllPassageReportsRaw.d.ts +18 -0
  72. package/dist/domain.operations/route/passage/getAllPassageReportsRaw.js +61 -0
  73. package/dist/domain.operations/route/passage/getAllPassageReportsRaw.js.map +1 -0
  74. package/dist/domain.operations/route/passage/getLatestPassageForStone.d.ts +23 -0
  75. package/dist/domain.operations/route/passage/getLatestPassageForStone.js +31 -0
  76. package/dist/domain.operations/route/passage/getLatestPassageForStone.js.map +1 -0
  77. package/dist/domain.operations/route/statusLine/asStatusLine.d.ts +36 -5
  78. package/dist/domain.operations/route/statusLine/asStatusLine.js +86 -10
  79. package/dist/domain.operations/route/statusLine/asStatusLine.js.map +1 -1
  80. package/dist/domain.operations/route/stepRouteDrive.js +131 -45
  81. package/dist/domain.operations/route/stepRouteDrive.js.map +1 -1
  82. package/dist/domain.operations/route/stepRouteStatusLine.d.ts +8 -9
  83. package/dist/domain.operations/route/stepRouteStatusLine.js +250 -16
  84. package/dist/domain.operations/route/stepRouteStatusLine.js.map +1 -1
  85. package/dist/domain.operations/route/stones/genStoneGuardBlockedEmit.d.ts +2 -2
  86. package/dist/domain.operations/route/stones/setStoneAsContemplated.js +15 -0
  87. package/dist/domain.operations/route/stones/setStoneAsContemplated.js.map +1 -1
  88. package/dist/domain.operations/route/stones/setStoneAsPassed.js +34 -7
  89. package/dist/domain.operations/route/stones/setStoneAsPassed.js.map +1 -1
  90. package/dist/domain.operations/route/stones/setStoneAsPromised.d.ts +4 -2
  91. package/dist/domain.operations/route/stones/setStoneAsPromised.js +18 -2
  92. package/dist/domain.operations/route/stones/setStoneAsPromised.js.map +1 -1
  93. package/dist/domain.roles/learner/boot.yml +10 -0
  94. package/dist/domain.roles/learner/briefs/howto.domain-term-disputes.[guide].md +75 -0
  95. package/dist/domain.roles/learner/briefs/im_an.obsessive_learner.for.domain.terms.md +86 -0
  96. package/dist/domain.roles/learner/briefs/im_an.obsessive_learner.md +2 -0
  97. package/dist/domain.roles/learner/briefs/readme.domain-terms.md +39 -0
  98. package/dist/domain.roles/learner/briefs/rule.forbid.domain-term-synonyms.md +50 -0
  99. package/dist/domain.roles/learner/briefs/rule.require.domain-term-itemization.md +61 -0
  100. package/dist/domain.roles/learner/briefs/template.domain-term.md +106 -0
  101. package/dist/domain.roles/learner/getLearnerRole.js +10 -0
  102. package/dist/domain.roles/learner/getLearnerRole.js.map +1 -1
  103. package/dist/domain.roles/learner/skills/learn.domain.terms.sh +27 -0
  104. package/package.json +5 -4
@@ -0,0 +1,9 @@
1
+ /**
2
+ * .what = cli entrypoint for the learn.domain.terms skill (both faces)
3
+ * .why = the onStop hook nudges when the distillation is stale; the clone runs it
4
+ * to reflect + distill
5
+ *
6
+ * exits 0 when fresh (hook), after the guide (clone), or after --help
7
+ * exits 2 when stale (hook) to hold the stop open (never a write)
8
+ */
9
+ export declare const learnDomainTerms: () => Promise<void>;
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.learnDomainTerms = void 0;
4
+ /**
5
+ * .what = cli entrypoint for the learner learn.domain.terms skill
6
+ * .why = enables shell invocation via package-level import, isolated on its own
7
+ * cli subpath so the onStop hook loads minimal modules (see
8
+ * rule.require.isolated-cli-subpath-exports)
9
+ *
10
+ * two faces, one skill (mirrors the driver's route.drive):
11
+ * --when hook.onStop → staleness check; exit 2 to hold the stop when the
12
+ * distillation is stale, else exit 0 (read-only, never writes)
13
+ * (no --when) → the clone's reflect-and-distill guide; findserts the
14
+ * glossary scaffold, then prints how to distill
15
+ */
16
+ const helpful_errors_1 = require("helpful-errors");
17
+ const getInvocationArgs_1 = require("../../domain.operations/cli/getInvocationArgs");
18
+ const genDomainTermsScaffold_1 = require("../../domain.operations/learn/genDomainTermsScaffold");
19
+ const getDomainTermsPaths_1 = require("../../domain.operations/learn/getDomainTermsPaths");
20
+ const getSweepProgress_1 = require("../../domain.operations/learn/getSweepProgress");
21
+ const isProgressArticulated_1 = require("../../domain.operations/learn/isProgressArticulated");
22
+ const isSweepStale_1 = require("../../domain.operations/learn/isSweepStale");
23
+ /**
24
+ * .what = emit the established two-line header — mascot + slogan, then scroll + command
25
+ * .why = all three faces (clone guide, onStop nudge, --help) open the SAME way; render
26
+ * from ONE place so the headers can never drift out of sync
27
+ * (rule.require.single-source-of-truth-for-render). the slogan varies by face
28
+ * (the nudge is a staleness reminder, the others a plain invocation) but the
29
+ * shape — `🦉 <slogan>` / blank / `📜 <command>` — is identical for all
30
+ */
31
+ const emitHeader = (emit, input) => {
32
+ emit(`🦉 ${input.slogan}`);
33
+ emit('');
34
+ emit(`📜 ${input.command}`);
35
+ };
36
+ /**
37
+ * .what = the flag portion of a token — the part before any `=` (e.g. `--help=x` → `--help`)
38
+ * .why = one splitter so both the help check and the allowlist parse the combined
39
+ * `--flag=value` form the same way (rule.require.ubiqlang — one parse of a token)
40
+ */
41
+ const asFlagName = (arg) => arg.split('=')[0];
42
+ /**
43
+ * .what = the flags the rhachet harness always injects to identify the invocation
44
+ * .why = `rhx <skill>` prepends --skill/--role/--repo (each with a value) to the argv it
45
+ * hands the wrapper; they name WHICH skill ran, they are NOT part of this skill's
46
+ * own surface. they must be stripped before the strict allowlist runs, else
47
+ * assertKnownFlags rejects the harness's own flags and the onStop hook can never fire
48
+ */
49
+ const RHACHET_INJECTED_FLAGS = ['--skill', '--role', '--repo'];
50
+ /**
51
+ * .what = the caller's own args — the invocation args minus the rhachet-injected flags
52
+ * .why = leaves only this skill's surface (--when / --help) for strict validation, so a
53
+ * genuine typo or stray positional is still caught while the harness flags pass
54
+ * through. handles both the space form (`--skill x`) and the combined (`--skill=x`)
55
+ */
56
+ const getOwnArgs = (argv) => {
57
+ const args = (0, getInvocationArgs_1.getInvocationArgs)(argv);
58
+ // mark each injected flag token, plus the value token after a space-form one
59
+ const dropped = new Set();
60
+ args.forEach((arg, index) => {
61
+ if (!RHACHET_INJECTED_FLAGS.includes(asFlagName(arg)))
62
+ return;
63
+ dropped.add(index);
64
+ // `--skill=x` carries its value inline; `--skill x` puts it in the next token
65
+ if (!arg.includes('='))
66
+ dropped.add(index + 1);
67
+ });
68
+ return args.filter((_, index) => !dropped.has(index));
69
+ };
70
+ /**
71
+ * .what = detect a --help / -h request in argv (both bare and `--help=` combined forms)
72
+ * .why = a help request must short-circuit BEFORE either face runs, so the clone face
73
+ * never writes on a --help (rule.require.help-on-demand). the combined `--help=x`
74
+ * form must also count, else it silently falls through to the clone face that writes
75
+ */
76
+ const isHelpRequested = (argv) => {
77
+ const args = getOwnArgs(argv);
78
+ return args.some((arg) => ['--help', '-h'].includes(asFlagName(arg)));
79
+ };
80
+ /**
81
+ * .what = the flags this skill recognizes (its whole surface)
82
+ * .why = one allowlist so assertKnownFlags can reject all else — a typo like
83
+ * --wen must fail loud, never silently fall through to the clone face
84
+ */
85
+ const KNOWN_FLAGS = ['--when', '--help', '-h'];
86
+ /**
87
+ * .what = is this token one the skill recognizes?
88
+ * .why = accepts the conventional combined `--flag=value` form a human expects
89
+ * (rule.forbid.friction-hazards), via asFlagName. the posix `--` marker is
90
+ * already filtered by getInvocationArgs, so it never reaches here
91
+ */
92
+ const isKnownToken = (arg) => KNOWN_FLAGS.includes(asFlagName(arg));
93
+ /**
94
+ * .what = reject any token the skill does not recognize (unknown flags AND stray positionals)
95
+ * .why = an unrecognized token — a typo `--wen`, a `--verbose`, or a bare positional `foo` —
96
+ * must NOT be silently ignored, else the clone face runs and writes when the caller
97
+ * intended the hook face or a no-op. this skill has ZERO positional args, so any token
98
+ * that is not a known flag (nor a --when value) is a fault. fail-loud
99
+ * (rule.forbid.friction-hazards, safe-by-default)
100
+ */
101
+ const assertKnownFlags = (argv) => {
102
+ const args = getOwnArgs(argv);
103
+ // the token right after a space-form `--when` is its VALUE, not a flag — skip it so
104
+ // a value that starts with `-` (e.g. `--when -x`) reads as the value and parseWhen
105
+ // gives the precise `invalid --when: -x` error, not a generic unknown-token one
106
+ const whenIndex = args.indexOf('--when');
107
+ const whenValueIndex = whenIndex === -1 ? -1 : whenIndex + 1;
108
+ const unknown = args.filter((arg, index) => index !== whenValueIndex && !isKnownToken(arg));
109
+ if (unknown.length === 0)
110
+ return;
111
+ throw new helpful_errors_1.BadRequestError(`unexpected arg(s): ${unknown.join(', ')}. this skill accepts only: --when hook.onStop | --help | -h`, { unknown });
112
+ };
113
+ /**
114
+ * .what = validate a --when value into the one supported hook context
115
+ * .why = an absent or wrong value is a caller error, never a silent fall-through to
116
+ * the clone face (which writes). fail-loud on both (rule.forbid.failhide)
117
+ */
118
+ const asWhenValue = (value) => {
119
+ if (value === 'hook.onStop')
120
+ return 'hook.onStop';
121
+ // render the fault legibly: an absent token reads '(absent)', an empty value
122
+ // (e.g. the combined `--when=` form) reads '(empty)' — never a blank before the
123
+ // period, which would read as a cryptic error (rule.forbid.friction-hazards)
124
+ const shown = value === undefined ? '(absent)' : value === '' ? '(empty)' : value;
125
+ throw new helpful_errors_1.BadRequestError(`invalid --when: ${shown}. only 'hook.onStop' is supported`, { when: value ?? null });
126
+ };
127
+ /**
128
+ * .what = parse the --when hook context from argv
129
+ * .why = selects the hook face vs the clone face; only hook.onStop is a hook
130
+ * context here (this skill has no onBoot face). accepts both the combined
131
+ * `--when=value` and the space-separated `--when value` forms
132
+ */
133
+ const parseWhen = (argv) => {
134
+ const args = getOwnArgs(argv);
135
+ // combined form `--when=value` → validate its inline value
136
+ const combined = args.find((arg) => arg.startsWith('--when='));
137
+ if (combined)
138
+ return asWhenValue(combined.slice('--when='.length));
139
+ // no --when at all → clone face
140
+ const whenIndex = args.indexOf('--when');
141
+ if (whenIndex === -1)
142
+ return undefined;
143
+ // space-separated form `--when value` → validate the next token
144
+ return asWhenValue(args[whenIndex + 1]);
145
+ };
146
+ /**
147
+ * .what = the shared distill guidance body — the how (reflect + act) + the canon
148
+ * .why = both faces teach the SAME moves and cite the SAME canon; render them from
149
+ * ONE place, into a caller-supplied sink (stdout for the clone guide, stderr
150
+ * for the onStop nudge), so the two renders can never drift
151
+ * (rule.require.single-source-of-truth-for-render,
152
+ * rule.forbid.duplicate-format-tree-operations). every line is a mid-branch
153
+ * (`├─`), so each face wraps it with its own opener and closer
154
+ */
155
+ const emitDistillMoves = (emit, input) => {
156
+ emit(' ├─ do this now — review + redistill the terms this round touched');
157
+ emit(' │ ├─ 1. recall — which domain objects & operations did you declare or engage?');
158
+ emit(' │ │ split each name into its terms (getStone → verb `get` + noun `stone`)');
159
+ emit(' │ ├─ 2. conform-or-dispute each EXTANT term (already in the glossary):');
160
+ emit(' │ │ ├─ your contract uses the canonical word → conform, you are done');
161
+ emit(' │ │ └─ you reached for a synonym → rename to the canonical word,');
162
+ emit(' │ │ or open a dispute in its `.reason` (adhere, or argue — never drift)');
163
+ emit(' │ ├─ 3. pave the path for each NEW term (born this round, not yet in the glossary):');
164
+ emit(' │ │ ├─ write its `term=<x>._.choice.*` cluster:');
165
+ emit(' │ │ │ ├─ term=<x>._.choice._.md (say: chosen word, kind, forbidden synonyms)');
166
+ emit(' │ │ │ ├─ term=<x>._.choice.reason.md (ref: etymology, disputes, evidence — required)');
167
+ emit(' │ │ │ └─ term=<x>._.choice.example=<abc>.md (ref: one per notable example — optional)');
168
+ emit(' │ │ └─ or cite it — point to the extant declaration you reused');
169
+ emit(' │ └─ 4. articulate progress.md — REQUIRED, the last step every round:');
170
+ emit(' │ ├─ what you conformed, disputed, and paved this round — and why');
171
+ emit(' │ ├─ a term the round SETTLED (declared dobj/dop, judged synonym) → capture it NOW');
172
+ emit(' │ ├─ defer ONLY a term you truly cannot finish (needs discovery, dispute still open)');
173
+ emit(` │ └─ sentinel = ${input.progressPath}`);
174
+ emit(' │');
175
+ // the canon — the booted briefs + rules that DEFINE a domain-term lesson + its rules,
176
+ // so the reader recalls exactly what a term is + why it is kept
177
+ emit(' ├─ the canon — what a term is + why it is kept');
178
+ emit(' │ ├─ why · im_an.obsessive_learner.for.domain.terms.md (the trait)');
179
+ emit(' │ ├─ rule · rule.require.domain-term-itemization (itemize each declared term)');
180
+ emit(' │ ├─ rule · rule.forbid.domain-term-synonyms (canonical term, or dispute)');
181
+ emit(' │ ├─ how · template.domain-term.md + howto.domain-term-disputes.[guide].md');
182
+ emit(` │ └─ glos · ${input.glossaryReadmePath}`);
183
+ };
184
+ /**
185
+ * .what = emit the onStop staleness nudge to stderr
186
+ * .why = stderr (not stdout) per rule.forbid.stdout-on-exit-errors; cli hooks
187
+ * surface stderr on non-zero exit
188
+ *
189
+ * structure: ask → why → [shared how + canon] → the-time-is-now → close, so the ask is
190
+ * never abstract — the reader learns WHAT to do, WHY it matters, HOW to do it, WHICH
191
+ * booted briefs/rules define the concepts, and that the moment to act is now
192
+ */
193
+ const emitStaleNudge = (input) => {
194
+ const emit = (line) => console.error(line);
195
+ emitHeader(emit, {
196
+ slogan: 'time again, to tend the terms',
197
+ command: 'learn.domain.terms --when hook.onStop',
198
+ });
199
+ emit(' │');
200
+ emit(' ├─ the ask — now, before you rest');
201
+ emit(' │ └─ review the terms this round touched, then redistill: conform-or-dispute');
202
+ emit(' │ the extant ones, and pave the path for any new ones. the steps are below');
203
+ emit(' │');
204
+ emit(' ├─ the why');
205
+ emit(' │ └─ the repo vocabulary compiles hour by hour; a term touched but not tended');
206
+ emit(' │ is a lesson lost — the next traveler re-derives it, or drifts to a synonym.');
207
+ emit(' │ an hour has passed, so the moment to tend it is now');
208
+ emit(' │');
209
+ emitDistillMoves(emit, input);
210
+ emit(' │');
211
+ emit(' ├─ the time to capture is now');
212
+ emit(' │ └─ your distillation went stale (> 1 hour) — tend it before you rest');
213
+ emit(' │');
214
+ emit(' └─ 🪷 distill, then rest — the glossary grows, the floor rises for all who follow');
215
+ };
216
+ /**
217
+ * .what = emit the scaffold-status line(s) of the clone guide
218
+ * .why = split out so the guide stays flat — a guard clause + early return keeps
219
+ * the two cases (no-op run vs written) linear, no else branch
220
+ * (rule.forbid.else-branches). a no-op pass is silent: the scaffold already
221
+ * converged, so there is no news to report — silence keeps the guide on the
222
+ * one thing that matters, the distillation (rule.require.status-feedback:
223
+ * report what CHANGED; an unchanged scaffold is not a change)
224
+ */
225
+ const emitScaffoldStatus = (input) => {
226
+ // a no-op run wrote no path this pass (every piece already converged) — stay silent
227
+ if (input.created.length === 0)
228
+ return;
229
+ // otherwise, name each artifact written this pass (findsert create or upsert reconcile)
230
+ console.log(' ├─ scaffold written');
231
+ input.created.forEach((path, index) => {
232
+ const isLast = index === input.created.length - 1;
233
+ console.log(` │ ${isLast ? '└─' : '├─'} ${path}`);
234
+ });
235
+ };
236
+ /**
237
+ * .what = emit the clone-face reflect-and-distill guide to stdout
238
+ * .why = the sweep does no work on its own — the learner decides what the round
239
+ * was worth. this guide names the glossary + scaffold status, then renders
240
+ * the SAME shared how + canon body the onStop nudge does (emitDistillMoves),
241
+ * so the clone face and the hook face can never teach a divergent guide
242
+ */
243
+ const emitReflectionGuide = (input) => {
244
+ const emit = (line) => console.log(line);
245
+ emitHeader(emit, { slogan: 'tend the terms', command: 'learn.domain.terms' });
246
+ emit(` ├─ glossary = ${input.glossaryDir}`);
247
+ emitScaffoldStatus({ created: input.created });
248
+ emit(' │');
249
+ emitDistillMoves(emit, {
250
+ progressPath: input.progressPath,
251
+ glossaryReadmePath: input.glossaryReadmePath,
252
+ });
253
+ emit(' │');
254
+ emit(' └─ 🪷 distill, then rest — the glossary grows, the floor rises for all who follow');
255
+ };
256
+ /**
257
+ * .what = emit the --help usage to stdout (both faces, args, exit codes)
258
+ * .why = every user-faced op must explain itself on demand; help is not an error,
259
+ * so it goes to stdout + exits 0 (rule.require.help-on-demand)
260
+ */
261
+ const emitHelp = () => {
262
+ const emit = (line) => console.log(line);
263
+ emitHeader(emit, { slogan: 'tend the terms', command: 'learn.domain.terms' });
264
+ emit('');
265
+ emit(' usage:');
266
+ console.log(' learn.domain.terms # clone face: write the scaffold,');
267
+ console.log(' # then guide the reflect-and-distill');
268
+ console.log(' learn.domain.terms --when hook.onStop');
269
+ console.log(' # hook face: staleness check');
270
+ console.log(' learn.domain.terms --help | -h # this help');
271
+ console.log('');
272
+ console.log(' faces:');
273
+ console.log(' ├─ clone (no --when) → writes the scaffold, prints the guide; exit 0');
274
+ console.log(' └─ hook (--when hook.onStop) → read-only staleness check');
275
+ console.log(' ├─ fresh distillation (< 1 hour) → exit 0 (session rests)');
276
+ console.log(' └─ stale (> 1 hour) → exit 2 (holds the stop, never a write)');
277
+ console.log('');
278
+ console.log(' --when values: hook.onStop (only)');
279
+ };
280
+ /**
281
+ * .what = cli entrypoint for the learn.domain.terms skill (both faces)
282
+ * .why = the onStop hook nudges when the distillation is stale; the clone runs it
283
+ * to reflect + distill
284
+ *
285
+ * exits 0 when fresh (hook), after the guide (clone), or after --help
286
+ * exits 2 when stale (hook) to hold the stop open (never a write)
287
+ */
288
+ const learnDomainTerms = async () => {
289
+ // --help: print usage, exit 0, never mutate. a help request must not run the
290
+ // clone face (which writes the scaffold) — safe-by-default (rule.require.help-on-demand)
291
+ if (isHelpRequested(process.argv)) {
292
+ emitHelp();
293
+ return;
294
+ }
295
+ // a bad --when is a caller-constraint, not a malfunction — exit 2, not 1
296
+ // (rule.require.exit-code-semantics). allowlist BadRequestError only; any other
297
+ // throw propagates to the wrapper's exit-1 backstop (no failhide)
298
+ const when = (() => {
299
+ try {
300
+ assertKnownFlags(process.argv);
301
+ return parseWhen(process.argv);
302
+ }
303
+ catch (error) {
304
+ if (!(error instanceof helpful_errors_1.BadRequestError))
305
+ throw error;
306
+ console.error(error.message);
307
+ return process.exit(2);
308
+ }
309
+ })();
310
+ const paths = (0, getDomainTermsPaths_1.getDomainTermsPaths)();
311
+ // hook face: read-only staleness check
312
+ if (when === 'hook.onStop') {
313
+ // freshness turns on BOTH a recent mtime AND a real articulation in the content,
314
+ // so a bare `touch` cannot silence the nudge (guards the one hard requirement)
315
+ const progress = await (0, getSweepProgress_1.getSweepProgress)({ path: paths.progressPath });
316
+ const articulated = (0, isProgressArticulated_1.isProgressArticulated)({ content: progress.content });
317
+ const stale = (0, isSweepStale_1.isSweepStale)({
318
+ mtime: progress.mtime,
319
+ articulated,
320
+ now: new Date(),
321
+ });
322
+ // fresh, articulated distillation → let the session rest
323
+ if (!stale)
324
+ return;
325
+ // stale → hold the stop open with a gentle nudge (never blocks a write)
326
+ emitStaleNudge({
327
+ progressPath: paths.progressPath,
328
+ glossaryReadmePath: paths.readmePath,
329
+ });
330
+ process.exit(2);
331
+ }
332
+ // clone face: findsert the scaffold, then guide the reflection
333
+ const scaffold = await (0, genDomainTermsScaffold_1.genDomainTermsScaffold)();
334
+ emitReflectionGuide({
335
+ glossaryDir: scaffold.glossaryDir,
336
+ glossaryReadmePath: paths.readmePath,
337
+ created: scaffold.created,
338
+ progressPath: paths.progressPath,
339
+ });
340
+ };
341
+ exports.learnDomainTerms = learnDomainTerms;
342
+ //# sourceMappingURL=learn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learn.js","sourceRoot":"","sources":["../../../src/contract/cli/learn.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,7 @@ const fs = __importStar(require("fs/promises"));
29
29
  const helpful_errors_1 = require("helpful-errors");
30
30
  const path = __importStar(require("path"));
31
31
  const RouteStoneGuard_1 = require("../../domain.objects/Driver/RouteStoneGuard");
32
+ const getInvocationArgs_1 = require("../../domain.operations/cli/getInvocationArgs");
32
33
  const delRouteBind_1 = require("../../domain.operations/route/bind/delRouteBind");
33
34
  const getRouteBind_1 = require("../../domain.operations/route/bind/getRouteBind");
34
35
  const getRouteBindByBranch_1 = require("../../domain.operations/route/bind/getRouteBindByBranch");
@@ -61,26 +62,6 @@ const findStoneByName_1 = require("../../domain.operations/route/stones/findSton
61
62
  const getAllStones_1 = require("../../domain.operations/route/stones/getAllStones");
62
63
  const isPromisedActionSlugAbsent_1 = require("../../domain.operations/route/stones/isPromisedActionSlugAbsent");
63
64
  const enumFilesFromGlob_1 = require("../../utils/enumFilesFromGlob");
64
- /**
65
- * .what = detects if node was invoked via `node -e "code"` (eval mode)
66
- * .why = in eval mode, argv has no entrypoint path and args come after --
67
- *
68
- * argv patterns:
69
- * normal: ['node', '/path/to/entry.js', '--arg', 'val']
70
- * eval: ['node', 'arg1', 'arg2'] (node strips -e and code from argv!)
71
- *
72
- * detection: if argv[1] doesn't look like a file path, assume eval mode
73
- */
74
- const isNodeEvalMode = (argv) => {
75
- const secondArg = argv[1];
76
- if (!secondArg)
77
- return false;
78
- // entrypoint path (ends with js/ts extension) = normal mode
79
- if (/\.(js|ts|mjs|cjs)$/.test(secondArg))
80
- return false;
81
- // otherwise assume eval mode (node strips -e and code from argv)
82
- return true;
83
- };
84
65
  /**
85
66
  * .what = copies bytes read from a buffer into a new buffer
86
67
  * .why = encapsulates buffer slice for readability in stdin read loops
@@ -167,13 +148,11 @@ const isValidStonePassageAction = (input) => {
167
148
  return !!input.action && VALID_STONE_PASSAGE_ACTIONS.has(input.action);
168
149
  };
169
150
  /**
170
- * .what = extracts clean args from argv, skipping node/entrypoint args and separators
171
- * .why = encapsulates argv preprocessing for readability
151
+ * .what = extracts clean args from argv, skips node/entrypoint args and the `--` separator
152
+ * .why = the canonical eval-mode slice now lives in one place (domain.operations/cli/
153
+ * getInvocationArgs), so route + learn share it instead of divergent copies
172
154
  */
173
- const getCleanArgsFromArgv = (input) => {
174
- const skipCount = isNodeEvalMode(input.argv) ? 1 : 2;
175
- return input.argv.slice(skipCount).filter((arg) => arg !== '--');
176
- };
155
+ const getCleanArgsFromArgv = (input) => (0, getInvocationArgs_1.getInvocationArgs)(input.argv);
177
156
  /**
178
157
  * .what = parses cli args into options object
179
158
  * .why = simple arg parser without external dependencies
@@ -447,6 +426,16 @@ options:
447
426
  onStop: show guidance, exit 2 (block premature stop)
448
427
  --help show this help message
449
428
 
429
+ output:
430
+ when the stone can self-drive, route.drive echoes the current stone + guidance.
431
+ when it has halted and needs a human, it switches to a halt message instead:
432
+ ✋ halted, stone marked blocked a driver wall (--as blocked) — clear it
433
+ 👋 halted, peer reviewer budget exhausted approve as-is, or extend the budget
434
+ 💥 halted, guard malfunction a reviewer or judge broke — a human must fix
435
+ onStop honors the same halt: exit 2 keeps the route in motion, exit 0 allows a
436
+ clean stop, exit 1 escalates a malfunction (per rule.require.exit-code-semantics).
437
+ onBoot always exits 0 (it never blocks session start).
438
+
450
439
  examples:
451
440
  route.drive # echo current stone
452
441
  route.drive --when hook.onBoot # show stone, exit 0 (for onBoot hooks)
@@ -467,10 +456,20 @@ options:
467
456
  --help show this help message
468
457
 
469
458
  output:
470
- bound, stone unpassed 🗿 <stone>
471
- bound, all stones passed 🗿 route complete 🎉
459
+ bound, stone + phase 🗿 <stone>, <phase> <emoji>
460
+ bound, all stones passed 🗿 route complete 🌴🤙
472
461
  unbound / no stones (empty line)
473
462
 
463
+ the phase suffix names where inside the stone the driver is, tipped with an
464
+ attention-color emoji at the end of the line (read the color, then the words):
465
+ yield 🌾 the stone yields its artifact — calm, no attention
466
+ review.self, r7/r10 🔍 self-reviews, r{done}/r{total} — machine's turn
467
+ review.peer, l3@i002 🔍 peer review, l{level}@i{rounds} — machine's turn
468
+ judge, approved? 👋 a human must approve — attention needed
469
+ ..., exhausted 👋 peer budget spent, a human must approve or extend
470
+ ..., blocked ✋ blocked, act now — attention needed
471
+ ..., malfunction 💥 a reviewer or judge broke, a human must fix
472
+
474
473
  errors:
475
474
  a genuine fault is logged to stderr and exits non-zero; the harness then renders
476
475
  a blank line (the fault is surfaced on stderr, never silently hidden)
@@ -1469,7 +1468,9 @@ const routeMutateGrant = async () => {
1469
1468
  grantOption: options.grant,
1470
1469
  });
1471
1470
  if (!action || !['allow', 'block', 'get'].includes(action)) {
1472
- console.log(`
1471
+ // usage on an invalid/absent action is an error path → stderr, not stdout
1472
+ // (rule.forbid.stdout-on-exit-errors: stdout may be hidden on non-zero exit)
1473
+ console.error(`
1473
1474
  route.mutate grant - manage route protection privilege
1474
1475
 
1475
1476
  usage:
@@ -1480,7 +1481,9 @@ usage:
1480
1481
  options:
1481
1482
  --route <path> route path (default: auto-detect from branch)
1482
1483
  `);
1483
- process.exit(1);
1484
+ // exit 2 = constraint: the caller gave a bad action and must fix the invocation
1485
+ // (rule.require.exit-code-semantics: 0 ok, 1 malfunction, 2 constraint)
1486
+ process.exit(2);
1484
1487
  }
1485
1488
  try {
1486
1489
  // get route from option or auto-detect
@@ -1679,7 +1682,9 @@ const routeGuardBudget = async () => {
1679
1682
  // validate --add option
1680
1683
  const addStr = options.add;
1681
1684
  if (!addStr) {
1682
- console.log(`
1685
+ // usage on an absent required flag is an error path → stderr, not stdout
1686
+ // (rule.forbid.stdout-on-exit-errors: stdout may be hidden on non-zero exit)
1687
+ console.error(`
1683
1688
  route.guard.budget - extend peer reviewer budget
1684
1689
 
1685
1690
  usage:
@@ -1694,12 +1699,16 @@ options:
1694
1699
  --peer peer reviewer slug to extend (default: all peers)
1695
1700
  --route path to route directory (default: auto-detect from branch)
1696
1701
  `);
1697
- process.exit(1);
1702
+ // exit 2 = constraint: the caller omitted a required flag and must fix the invocation
1703
+ // (rule.require.exit-code-semantics: 0 ok, 1 malfunction, 2 constraint)
1704
+ process.exit(2);
1698
1705
  }
1699
1706
  const addAmount = asPositiveIntegerOrNull({ value: addStr });
1700
1707
  if (addAmount === null) {
1701
1708
  console.error('error: --add must be a positive integer');
1702
- process.exit(1);
1709
+ // exit 2 = constraint: the caller passed a malformed value and must fix the
1710
+ // invocation (rule.require.exit-code-semantics: 0 ok, 1 malfunction, 2 constraint)
1711
+ process.exit(2);
1703
1712
  }
1704
1713
  const peerSlug = options.peer;
1705
1714
  const stoneName = options.stone;