greprag 5.45.0 → 5.47.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 (48) hide show
  1. package/dist/commands/arm-reminder.d.ts +25 -0
  2. package/dist/commands/arm-reminder.js +65 -0
  3. package/dist/commands/arm-reminder.js.map +1 -0
  4. package/dist/commands/email.js +20 -2
  5. package/dist/commands/email.js.map +1 -1
  6. package/dist/commands/fix.d.ts +20 -2
  7. package/dist/commands/fix.js +21 -4
  8. package/dist/commands/fix.js.map +1 -1
  9. package/dist/commands/friction-reminder.d.ts +92 -0
  10. package/dist/commands/friction-reminder.js +147 -0
  11. package/dist/commands/friction-reminder.js.map +1 -0
  12. package/dist/commands/init.js +20 -0
  13. package/dist/commands/init.js.map +1 -1
  14. package/dist/commands/mechanic.d.ts +18 -0
  15. package/dist/commands/mechanic.js +77 -9
  16. package/dist/commands/mechanic.js.map +1 -1
  17. package/dist/commands/memory-format.d.ts +11 -2
  18. package/dist/commands/memory-format.js +22 -8
  19. package/dist/commands/memory-format.js.map +1 -1
  20. package/dist/commands/memory.d.ts +44 -0
  21. package/dist/commands/memory.js +73 -9
  22. package/dist/commands/memory.js.map +1 -1
  23. package/dist/commands/poll-registry.d.ts +9 -52
  24. package/dist/commands/poll-registry.js +9 -176
  25. package/dist/commands/poll-registry.js.map +1 -1
  26. package/dist/commands/reminder-registry.d.ts +20 -0
  27. package/dist/commands/reminder-registry.js +59 -0
  28. package/dist/commands/reminder-registry.js.map +1 -0
  29. package/dist/commands/reminder-types.d.ts +49 -0
  30. package/dist/commands/reminder-types.js +8 -0
  31. package/dist/commands/reminder-types.js.map +1 -0
  32. package/dist/hook.js +174 -77
  33. package/dist/hook.js.map +1 -1
  34. package/dist/inbox-attachments.d.ts +37 -0
  35. package/dist/inbox-attachments.js +64 -0
  36. package/dist/inbox-attachments.js.map +1 -0
  37. package/dist/index.js +16 -70
  38. package/dist/index.js.map +1 -1
  39. package/dist/session-id.d.ts +2 -2
  40. package/dist/session-id.js +2 -2
  41. package/dist/session-id.js.map +1 -1
  42. package/dist/worktree-state.d.ts +14 -0
  43. package/dist/worktree-state.js +61 -0
  44. package/dist/worktree-state.js.map +1 -0
  45. package/package.json +1 -1
  46. package/skill/mechanic/SKILL.md +22 -10
  47. package/skill/templates/chip-spawn.md +1 -1
  48. package/skill/templates/reflex-chip.md +58 -0
@@ -1,56 +1,13 @@
1
- /** Poll registrylocal pidfile tracking for the asyncRewake idle-liveness
2
- * polls (`greprag inbox poll`), kept in its OWN namespace `~/.greprag/polls/`
3
- * so it NEVER touches the Monitor watcher's `~/.greprag/watchers/` registry.
1
+ /** Inbox cursor store the per-session `~/.greprag/polls/<short>.cursor` file.
4
2
  *
5
- * WHY SEPARATE: `notify`'s `isLocallyArmed` reads the watcher registry to decide
6
- * whether to inject the Monitor arm directive. If a poll registered there, the
7
- * Monitor arm would go silent and the poll would REPLACE Monitor instead of
8
- * running ALONGSIDE it. The two liveness mechanisms must be independent until a
9
- * deliberate cutover. adr: adr/monitor-resilience.md
10
- *
11
- * The cleanup model mirrors the SHIPPED watcher count-cap (and reuses its pure
12
- * `capSurplusVerdict`): per session, keep the K freshest LIVE polls, reap only
13
- * the surplus, never below K. No death-judgment — a count + a floor — so it can
14
- * never false-kill the live poll. Reload-orphans (if asyncRewake does not adopt
15
- * a process across reload) are bounded here AND self-clean via the poll's own
16
- * max-lifetime ceiling. */
17
- /** Default per-session poll floor: keep this many freshest live polls, reap the
18
- * surplus, never below it. K=2 = the live one + one margin (a reload overlap). */
19
- export declare const DEFAULT_POLL_CAP = 2;
20
- export interface PollRecord {
21
- short: string;
22
- pid: number;
23
- startedAt: number;
24
- }
25
- /** APPEND this poll's entry (pruning dead entries as it goes). Best-effort. */
26
- export declare function registerPoll(short: string, pid: number): void;
27
- /** Remove THIS poll's entry (on the poll's own exit — message-wake or ceiling). */
28
- export declare function deregisterPoll(short: string, pid: number): void;
29
- /** Does this session have ANY live poll right now? The re-arm gate: a gated arm
30
- * (PostToolUse / UserPromptSubmit) skips when true so per-tool fires don't pile
31
- * up; SessionStart never gates (it always arms a fresh, reload-adopted poll).
32
- * Sweeps dead entries as it reads. */
33
- export declare function isPollArmed(short: string): boolean;
34
- /** Every live poll on this machine, freshest first. */
35
- export declare function listLivePolls(): PollRecord[];
36
- /** Last message id this session's polls have seen, or null (first poll → live
37
- * tail only; no replay of pre-existing history). */
3
+ * HISTORY: this module WAS the asyncRewake idle-liveness POLL registry (pidfiles,
4
+ * count-cap, liveness probes). The poll was REMOVED it cost ~1 long-lived node
5
+ * process per session (~1.1 GB across the operator's concurrent sessions); the
6
+ * Monitor watcher + the SessionStart drain are the delivery path. See
7
+ * adr/monitor-resilience.md. Only the cursor helpers survive, still used by the
8
+ * `drain` hook to track a stable last-seen id. */
9
+ /** Last message id this session has seen, or null (first read live tail only). */
38
10
  export declare function readPollCursor(short: string): string | null;
39
11
  export declare function writePollCursor(short: string, id: string): void;
40
- /** Drop the cursor (→ next poll live-tails from now). Called when the server
41
- * rejects the stored `since` (the message it points to was pruned/deleted): a
42
- * stale cursor would otherwise 4xx forever, permanently wedging delivery for
43
- * this session. Clearing it trades replay of the gap for restored liveness. */
12
+ /** Drop the cursor (→ next read resumes from the live tail). */
44
13
  export declare function clearPollCursor(short: string): void;
45
- export interface PollCapResult {
46
- scanned: number;
47
- surplus: number;
48
- killed: number[];
49
- }
50
- /** Count-cap every session's polls: keep the K freshest LIVE polls, kill only the
51
- * surplus, never below K. Snapshot-free (per-session file reads + pidAlive); a
52
- * `taskkill` only on genuine surplus. Run at SessionStart (recap hook) and via
53
- * `greprag inbox poll-reap`. Reuses the watcher's pure `capSurplusVerdict` — the
54
- * same liveness-safety guarantee, applied to the poll namespace.
55
- * adr: adr/monitor-resilience.md */
56
- export declare function reapSurplusPolls(K?: number): PollCapResult;
@@ -1,20 +1,12 @@
1
1
  "use strict";
2
- /** Poll registrylocal pidfile tracking for the asyncRewake idle-liveness
3
- * polls (`greprag inbox poll`), kept in its OWN namespace `~/.greprag/polls/`
4
- * so it NEVER touches the Monitor watcher's `~/.greprag/watchers/` registry.
2
+ /** Inbox cursor store the per-session `~/.greprag/polls/<short>.cursor` file.
5
3
  *
6
- * WHY SEPARATE: `notify`'s `isLocallyArmed` reads the watcher registry to decide
7
- * whether to inject the Monitor arm directive. If a poll registered there, the
8
- * Monitor arm would go silent and the poll would REPLACE Monitor instead of
9
- * running ALONGSIDE it. The two liveness mechanisms must be independent until a
10
- * deliberate cutover. adr: adr/monitor-resilience.md
11
- *
12
- * The cleanup model mirrors the SHIPPED watcher count-cap (and reuses its pure
13
- * `capSurplusVerdict`): per session, keep the K freshest LIVE polls, reap only
14
- * the surplus, never below K. No death-judgment — a count + a floor — so it can
15
- * never false-kill the live poll. Reload-orphans (if asyncRewake does not adopt
16
- * a process across reload) are bounded here AND self-clean via the poll's own
17
- * max-lifetime ceiling. */
4
+ * HISTORY: this module WAS the asyncRewake idle-liveness POLL registry (pidfiles,
5
+ * count-cap, liveness probes). The poll was REMOVED it cost ~1 long-lived node
6
+ * process per session (~1.1 GB across the operator's concurrent sessions); the
7
+ * Monitor watcher + the SessionStart drain are the delivery path. See
8
+ * adr/monitor-resilience.md. Only the cursor helpers survive, still used by the
9
+ * `drain` hook to track a stable last-seen id. */
18
10
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
11
  if (k2 === undefined) k2 = k;
20
12
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -49,23 +41,12 @@ var __importStar = (this && this.__importStar) || (function () {
49
41
  };
50
42
  })();
51
43
  Object.defineProperty(exports, "__esModule", { value: true });
52
- exports.DEFAULT_POLL_CAP = void 0;
53
- exports.registerPoll = registerPoll;
54
- exports.deregisterPoll = deregisterPoll;
55
- exports.isPollArmed = isPollArmed;
56
- exports.listLivePolls = listLivePolls;
57
44
  exports.readPollCursor = readPollCursor;
58
45
  exports.writePollCursor = writePollCursor;
59
46
  exports.clearPollCursor = clearPollCursor;
60
- exports.reapSurplusPolls = reapSurplusPolls;
61
47
  const fs = __importStar(require("fs"));
62
48
  const path = __importStar(require("path"));
63
- const child_process_1 = require("child_process");
64
- const watcher_registry_1 = require("./watcher-registry");
65
49
  const POLL_DIRNAME = 'polls';
66
- /** Default per-session poll floor: keep this many freshest live polls, reap the
67
- * surplus, never below it. K=2 = the live one + one margin (a reload overlap). */
68
- exports.DEFAULT_POLL_CAP = 2;
69
50
  function grepragHome() {
70
51
  const home = process.env.HOME || process.env.USERPROFILE || '';
71
52
  return home ? path.join(home, '.greprag') : null;
@@ -74,105 +55,11 @@ function pollsDir() {
74
55
  const h = grepragHome();
75
56
  return h ? path.join(h, POLL_DIRNAME) : null;
76
57
  }
77
- function pollfilePath(short) {
78
- const dir = pollsDir();
79
- return dir ? path.join(dir, `${short}.json`) : null;
80
- }
81
- /** True iff `pid` is a live process. `process.kill(pid, 0)` probes existence
82
- * without signalling; EPERM = exists (another user), ESRCH = gone. */
83
- function pidAlive(pid) {
84
- if (!Number.isFinite(pid) || pid <= 0)
85
- return false;
86
- try {
87
- process.kill(pid, 0);
88
- return true;
89
- }
90
- catch (e) {
91
- return e?.code === 'EPERM';
92
- }
93
- }
94
- function readPollEntries(short) {
95
- try {
96
- const p = pollfilePath(short);
97
- if (!p)
98
- return [];
99
- const parsed = JSON.parse(fs.readFileSync(p, 'utf-8'));
100
- const arr = Array.isArray(parsed) ? parsed : [parsed];
101
- return arr.filter((r) => !!r && typeof r.pid === 'number');
102
- }
103
- catch {
104
- return [];
105
- }
106
- }
107
- function writePollEntries(short, entries) {
108
- try {
109
- const dir = pollsDir();
110
- if (!dir)
111
- return;
112
- fs.mkdirSync(dir, { recursive: true });
113
- const p = path.join(dir, `${short}.json`);
114
- if (entries.length === 0) {
115
- fs.rmSync(p, { force: true });
116
- return;
117
- }
118
- fs.writeFileSync(p, JSON.stringify(entries));
119
- }
120
- catch { /* best-effort — a failed write only means a re-arm, never a crash */ }
121
- }
122
- function allShorts() {
123
- try {
124
- const dir = pollsDir();
125
- if (!dir || !fs.existsSync(dir))
126
- return [];
127
- return fs.readdirSync(dir).filter(f => f.endsWith('.json')).map(f => f.slice(0, -5));
128
- }
129
- catch {
130
- return [];
131
- }
132
- }
133
- /** APPEND this poll's entry (pruning dead entries as it goes). Best-effort. */
134
- function registerPoll(short, pid) {
135
- const entries = readPollEntries(short).filter(r => r.pid !== pid && pidAlive(r.pid));
136
- entries.push({ short, pid, startedAt: Date.now() });
137
- writePollEntries(short, entries);
138
- }
139
- /** Remove THIS poll's entry (on the poll's own exit — message-wake or ceiling). */
140
- function deregisterPoll(short, pid) {
141
- writePollEntries(short, readPollEntries(short).filter(r => r.pid !== pid));
142
- }
143
- /** Does this session have ANY live poll right now? The re-arm gate: a gated arm
144
- * (PostToolUse / UserPromptSubmit) skips when true so per-tool fires don't pile
145
- * up; SessionStart never gates (it always arms a fresh, reload-adopted poll).
146
- * Sweeps dead entries as it reads. */
147
- function isPollArmed(short) {
148
- const entries = readPollEntries(short);
149
- const alive = entries.filter(r => pidAlive(r.pid));
150
- if (alive.length !== entries.length)
151
- writePollEntries(short, alive);
152
- return alive.length > 0;
153
- }
154
- /** Every live poll on this machine, freshest first. */
155
- function listLivePolls() {
156
- const out = [];
157
- for (const short of allShorts()) {
158
- const entries = readPollEntries(short);
159
- const alive = entries.filter(r => pidAlive(r.pid));
160
- if (alive.length !== entries.length)
161
- writePollEntries(short, alive);
162
- out.push(...alive);
163
- }
164
- return out.sort((a, b) => (b.startedAt || 0) - (a.startedAt || 0));
165
- }
166
- // ---- Cursor (gap-recovery so the long-poll never loses a message) ----------
167
- // Each poll resumes the SSE stream from the last id it persisted (`?since=`),
168
- // so a message that arrives between one poll exiting and the next arming is
169
- // REPLAYED, not lost. The cursor is per-session, shared across poll invocations.
170
58
  function cursorPath(short) {
171
59
  const dir = pollsDir();
172
60
  return dir ? path.join(dir, `${short}.cursor`) : null;
173
61
  }
174
- /** Last message id this session's polls have seen, or null (first poll → live
175
- * tail only; no replay of pre-existing history). */
62
+ /** Last message id this session has seen, or null (first read → live tail only). */
176
63
  function readPollCursor(short) {
177
64
  try {
178
65
  const p = cursorPath(short);
@@ -195,10 +82,7 @@ function writePollCursor(short, id) {
195
82
  }
196
83
  catch { /* best-effort — at worst one message is re-delivered */ }
197
84
  }
198
- /** Drop the cursor (→ next poll live-tails from now). Called when the server
199
- * rejects the stored `since` (the message it points to was pruned/deleted): a
200
- * stale cursor would otherwise 4xx forever, permanently wedging delivery for
201
- * this session. Clearing it trades replay of the gap for restored liveness. */
85
+ /** Drop the cursor (→ next read resumes from the live tail). */
202
86
  function clearPollCursor(short) {
203
87
  try {
204
88
  const p = cursorPath(short);
@@ -207,55 +91,4 @@ function clearPollCursor(short) {
207
91
  }
208
92
  catch { /* best-effort */ }
209
93
  }
210
- /** Count-cap every session's polls: keep the K freshest LIVE polls, kill only the
211
- * surplus, never below K. Snapshot-free (per-session file reads + pidAlive); a
212
- * `taskkill` only on genuine surplus. Run at SessionStart (recap hook) and via
213
- * `greprag inbox poll-reap`. Reuses the watcher's pure `capSurplusVerdict` — the
214
- * same liveness-safety guarantee, applied to the poll namespace.
215
- * adr: adr/monitor-resilience.md */
216
- function reapSurplusPolls(K = exports.DEFAULT_POLL_CAP) {
217
- let scanned = 0;
218
- let surplus = 0;
219
- const killed = [];
220
- for (const short of allShorts()) {
221
- const alive = readPollEntries(short).filter(r => pidAlive(r.pid));
222
- scanned += alive.length;
223
- const { keep, kill } = (0, watcher_registry_1.capSurplusVerdict)(alive, K);
224
- if (kill.length === 0) {
225
- writePollEntries(short, alive);
226
- continue;
227
- }
228
- surplus += kill.length;
229
- const survivors = keep.slice();
230
- for (const w of kill) {
231
- if (killProcess(w.pid))
232
- killed.push(w.pid);
233
- else
234
- survivors.push(w); // kill failed → keep tracking, retry next pass
235
- }
236
- writePollEntries(short, survivors);
237
- }
238
- return { scanned, surplus, killed };
239
- }
240
- /** Force-kill a poll process. A poll has no children (single SSE process), so a
241
- * plain kill suffices — but `taskkill /T` is used on Windows for symmetry with
242
- * the watcher and to catch any incidental child. */
243
- function killProcess(pid) {
244
- try {
245
- if (process.platform === 'win32') {
246
- (0, child_process_1.execFileSync)('taskkill.exe', ['/PID', String(pid), '/T', '/F'], // proc-allow: poll count-cap surplus kill, mirrors watcher-registry
247
- { timeout: 5_000, stdio: 'ignore', windowsHide: true });
248
- }
249
- else {
250
- try {
251
- process.kill(pid, 'SIGKILL');
252
- }
253
- catch { /* already gone */ }
254
- }
255
- return true;
256
- }
257
- catch {
258
- return false;
259
- }
260
- }
261
94
  //# sourceMappingURL=poll-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"poll-registry.js","sourceRoot":"","sources":["../../src/commands/poll-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"poll-registry.js","sourceRoot":"","sources":["../../src/commands/poll-registry.ts"],"names":[],"mappings":";AAAA;;;;;;;mDAOmD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBnD,wCAOC;AAED,0CAOC;AAGD,0CAKC;AA7CD,uCAAyB;AACzB,2CAA6B;AAE7B,MAAM,YAAY,GAAG,OAAO,CAAC;AAE7B,SAAS,WAAW;IAClB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IAC/D,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED,SAAS,QAAQ;IACf,MAAM,CAAC,GAAG,WAAW,EAAE,CAAC;IACxB,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,oFAAoF;AACpF,SAAgB,cAAc,CAAC,KAAa;IAC1C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACpB,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,OAAO,CAAC,IAAI,IAAI,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AAC1B,CAAC;AAED,SAAgB,eAAe,CAAC,KAAa,EAAE,EAAU;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE;YAAE,OAAO;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC,CAAC,wDAAwD,CAAC,CAAC;AACtE,CAAC;AAED,gEAAgE;AAChE,SAAgB,eAAe,CAAC,KAAa;IAC3C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,20 @@
1
+ /** The reminder-interrupt registry CONTAINER (docs/reminder-interrupt.md §Registry
2
+ * spec). One loop over all modules: per turn, fire each module's thin reminder while
3
+ * its detector says deficient; at SessionStart, emit each announce. Stacking welcome.
4
+ * PURE over ReminderEnv — the hook assembles env (i/o) and emits the returned lines;
5
+ * a broken module never blocks a turn (fail-open per module). */
6
+ import { ReminderEnv, ReminderModule, Detection } from './reminder-types';
7
+ /** Registry order = display order. Detector-gated modules first (watcher-arm is the
8
+ * reference), graded/ambient after. Add a module here to wire it everywhere. */
9
+ export declare const REGISTRY: ReminderModule[];
10
+ export interface FiredReminder {
11
+ id: string;
12
+ tier: Detection['tier'];
13
+ line: string;
14
+ }
15
+ /** Per-turn: every module's live reminder line (skipping silent), in registry order.
16
+ * Stacking — a turn may carry several. A detector or reminder that throws drops that
17
+ * module for the turn; it never blocks the others or the turn. */
18
+ export declare function collectReminders(env: ReminderEnv, registry?: ReminderModule[]): FiredReminder[];
19
+ /** SessionStart: every module's announce (skipping null), in registry order. */
20
+ export declare function collectAnnounces(env: ReminderEnv, registry?: ReminderModule[]): string[];
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ /** The reminder-interrupt registry CONTAINER (docs/reminder-interrupt.md §Registry
3
+ * spec). One loop over all modules: per turn, fire each module's thin reminder while
4
+ * its detector says deficient; at SessionStart, emit each announce. Stacking welcome.
5
+ * PURE over ReminderEnv — the hook assembles env (i/o) and emits the returned lines;
6
+ * a broken module never blocks a turn (fail-open per module). */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.REGISTRY = void 0;
9
+ exports.collectReminders = collectReminders;
10
+ exports.collectAnnounces = collectAnnounces;
11
+ const arm_reminder_1 = require("./arm-reminder");
12
+ const friction_reminder_1 = require("./friction-reminder");
13
+ /** Registry order = display order. Detector-gated modules first (watcher-arm is the
14
+ * reference), graded/ambient after. Add a module here to wire it everywhere. */
15
+ exports.REGISTRY = [arm_reminder_1.watcherArmModule, friction_reminder_1.mechanicFrictionModule];
16
+ /** Per-turn: every module's live reminder line (skipping silent), in registry order.
17
+ * Stacking — a turn may carry several. A detector or reminder that throws drops that
18
+ * module for the turn; it never blocks the others or the turn. */
19
+ function collectReminders(env, registry = exports.REGISTRY) {
20
+ const out = [];
21
+ for (const m of registry) {
22
+ let d;
23
+ try {
24
+ d = m.detect(env);
25
+ }
26
+ catch {
27
+ continue;
28
+ }
29
+ if (!d || d.tier === 'silent')
30
+ continue;
31
+ let line = null;
32
+ try {
33
+ line = m.reminder(d, env);
34
+ }
35
+ catch {
36
+ continue;
37
+ }
38
+ if (line)
39
+ out.push({ id: m.id, tier: d.tier, line });
40
+ }
41
+ return out;
42
+ }
43
+ /** SessionStart: every module's announce (skipping null), in registry order. */
44
+ function collectAnnounces(env, registry = exports.REGISTRY) {
45
+ const out = [];
46
+ for (const m of registry) {
47
+ let a = null;
48
+ try {
49
+ a = m.announce(env);
50
+ }
51
+ catch {
52
+ continue;
53
+ }
54
+ if (a)
55
+ out.push(a);
56
+ }
57
+ return out;
58
+ }
59
+ //# sourceMappingURL=reminder-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminder-registry.js","sourceRoot":"","sources":["../../src/commands/reminder-registry.ts"],"names":[],"mappings":";AAAA;;;;kEAIkE;;;AAmBlE,4CAaC;AAGD,4CAUC;AA1CD,iDAAkD;AAClD,2DAA6D;AAE7D;iFACiF;AACpE,QAAA,QAAQ,GAAqB,CAAC,+BAAgB,EAAE,0CAAsB,CAAC,CAAC;AAQrF;;mEAEmE;AACnE,SAAgB,gBAAgB,CAC9B,GAAgB,EAAE,WAA6B,gBAAQ;IAEvD,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAY,CAAC;QACjB,IAAI,CAAC;YAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QAC9C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACxC,IAAI,IAAI,GAAkB,IAAI,CAAC;QAC/B,IAAI,CAAC;YAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QACtD,IAAI,IAAI;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,SAAgB,gBAAgB,CAC9B,GAAgB,EAAE,WAA6B,gBAAQ;IAEvD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,GAAkB,IAAI,CAAC;QAC5B,IAAI,CAAC;YAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QAChD,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,49 @@
1
+ /** Shared types for the reminder-interrupt registry (docs/reminder-interrupt.md
2
+ * §Registry spec — the detector model). Modeled on the WORKING arm-check loop:
3
+ * detect a live external deficiency → fire while it holds → auto-silence the
4
+ * instant it resolves. `detect(env)` is the primitive (the arm-check's
5
+ * `isLocallyArmed`, generalized); a turn counter is not. */
6
+ /** Firing-tier ladder. `silent` = the deficiency is resolved (the auto-stop); the
7
+ * rest escalate wording intensity with the cost of inaction (ambient = soft
8
+ * pointer, nudge = imperative + reason, nag = LOUD forced-decision). */
9
+ export type Tier = 'silent' | 'ambient' | 'nudge' | 'nag';
10
+ /** The live-state bag the hook assembles ONCE per turn — ALL i/o lives in the hook
11
+ * so modules stay pure (and their detect→silent transition stays unit-testable).
12
+ * Grows as modules need new signals. */
13
+ export interface ReminderEnv {
14
+ /** 8-hex session id. */
15
+ short: string;
16
+ /** Turns elapsed this session (for any ambient-cadence module). */
17
+ turnCount: number;
18
+ /** Live behavioral stress (docs/stress-trigger.md): 0 calm / 1 elevated / 2 high. */
19
+ stress: number;
20
+ /** Live local watcher present? (isLocallyArmed) — the arm-check's signal. */
21
+ armed: boolean;
22
+ /** Unread messages addressed to THIS session (own mail — NOT the project-wide
23
+ * v5.6.1 eavesdrop count). */
24
+ sessionUnread: number;
25
+ /** Owning claude.exe PID — baked into the arm command. */
26
+ ownerPid?: number | null;
27
+ /** Identity handle (alias before @) for reply-address templating. */
28
+ alias?: string | null;
29
+ /** Assistant project → elevated watcher arm. */
30
+ assistant?: boolean;
31
+ }
32
+ /** A module's per-turn read of its deficiency. `tier:'silent'` = resolved → no fire. */
33
+ export interface Detection {
34
+ tier: Tier;
35
+ /** Optional grounding data the reminder line interpolates (e.g. unread count). */
36
+ detail?: Record<string, unknown>;
37
+ }
38
+ /** A reminder-interrupt registry module (docs/reminder-interrupt.md §Registry spec).
39
+ * PURE over ReminderEnv — the container/hook owns all i/o, so detect→silent is the
40
+ * unit-testable regression-lock. */
41
+ export interface ReminderModule {
42
+ id: string;
43
+ /** Read the live deficiency. The gate: `silent` ⇒ the module is quiet this turn. */
44
+ detect: (env: ReminderEnv) => Detection;
45
+ /** SessionStart schema, loaded once (teach method + why). null = nothing to announce. */
46
+ announce: (env: ReminderEnv) => string | null;
47
+ /** Per-turn thin line for a live detection; null when silent. */
48
+ reminder: (d: Detection, env: ReminderEnv) => string | null;
49
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /** Shared types for the reminder-interrupt registry (docs/reminder-interrupt.md
3
+ * §Registry spec — the detector model). Modeled on the WORKING arm-check loop:
4
+ * detect a live external deficiency → fire while it holds → auto-silence the
5
+ * instant it resolves. `detect(env)` is the primitive (the arm-check's
6
+ * `isLocallyArmed`, generalized); a turn counter is not. */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ //# sourceMappingURL=reminder-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reminder-types.js","sourceRoot":"","sources":["../../src/commands/reminder-types.ts"],"names":[],"mappings":";AAAA;;;;6DAI6D"}