greprag 5.49.16 → 5.51.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 (55) hide show
  1. package/dist/commands/doc-pointer-reminder.d.ts +18 -0
  2. package/dist/commands/doc-pointer-reminder.js +41 -0
  3. package/dist/commands/doc-pointer-reminder.js.map +1 -0
  4. package/dist/commands/enrichment-health-reminder.d.ts +23 -0
  5. package/dist/commands/enrichment-health-reminder.js +39 -0
  6. package/dist/commands/enrichment-health-reminder.js.map +1 -0
  7. package/dist/commands/init.js +20 -0
  8. package/dist/commands/init.js.map +1 -1
  9. package/dist/commands/load.d.ts +8 -5
  10. package/dist/commands/load.js +89 -10
  11. package/dist/commands/load.js.map +1 -1
  12. package/dist/commands/memory.js +40 -12
  13. package/dist/commands/memory.js.map +1 -1
  14. package/dist/commands/opencode-interrupt.d.ts +5 -0
  15. package/dist/commands/opencode-interrupt.js +8 -2
  16. package/dist/commands/opencode-interrupt.js.map +1 -1
  17. package/dist/commands/opencode-relay.js +1 -1
  18. package/dist/commands/opencode-relay.js.map +1 -1
  19. package/dist/commands/procedure.d.ts +15 -0
  20. package/dist/commands/procedure.js +167 -0
  21. package/dist/commands/procedure.js.map +1 -0
  22. package/dist/commands/reminder-registry.js +8 -0
  23. package/dist/commands/reminder-registry.js.map +1 -1
  24. package/dist/commands/reminder-types.d.ts +35 -0
  25. package/dist/commands/skill-gain-reminder.d.ts +17 -0
  26. package/dist/commands/skill-gain-reminder.js +32 -0
  27. package/dist/commands/skill-gain-reminder.js.map +1 -0
  28. package/dist/commands/skill-mirror-reminder.d.ts +15 -0
  29. package/dist/commands/skill-mirror-reminder.js +33 -0
  30. package/dist/commands/skill-mirror-reminder.js.map +1 -0
  31. package/dist/commands/skillgain.d.ts +12 -0
  32. package/dist/commands/skillgain.js +109 -0
  33. package/dist/commands/skillgain.js.map +1 -0
  34. package/dist/hook.js +386 -2
  35. package/dist/hook.js.map +1 -1
  36. package/dist/index.js +4 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/opencode-plugin.bundle.js +92 -1
  39. package/dist/procedure-watch.d.ts +153 -0
  40. package/dist/procedure-watch.js +349 -0
  41. package/dist/procedure-watch.js.map +1 -0
  42. package/dist/procedure.d.ts +88 -0
  43. package/dist/procedure.js +269 -0
  44. package/dist/procedure.js.map +1 -0
  45. package/dist/skill-landing.d.ts +88 -0
  46. package/dist/skill-landing.js +220 -0
  47. package/dist/skill-landing.js.map +1 -0
  48. package/dist/skill-mirror-client.d.ts +37 -0
  49. package/dist/skill-mirror-client.js +172 -0
  50. package/dist/skill-mirror-client.js.map +1 -0
  51. package/package.json +1 -1
  52. package/skill/commander/SKILL.md +2 -2
  53. package/skill/greprag/SKILL.md +1 -1
  54. package/skill/greprag/docs/inbox-watch.md +5 -5
  55. package/skill/templates/chip-leader-opencode.md +98 -0
@@ -0,0 +1,88 @@
1
+ /** Procedure System — pure core + local store (docs/procedure-system.md).
2
+ *
3
+ * A *procedure* is the repo-specific recipe behind an operational intent
4
+ * (deploy / push / release / commit / merge). The system's job: when the user
5
+ * asks for one, inject the known recipe + its gate BEFORE the agent moves, so
6
+ * the operational verb runs cleanly instead of by trial-and-error.
7
+ *
8
+ * This module is the PROOF slice — Tier 1 (deterministic keyword trigger) +
9
+ * REPLAY (inject a seeded/learned recipe). It is intentionally local-file
10
+ * backed, mirroring guard.ts's matchset cache: the UserPromptSubmit hook reads
11
+ * it on the hot path, so there is NO network here (server persistence + the
12
+ * LEARN/Stop-hook capture leg land later — docs/procedure-system.md phases).
13
+ *
14
+ * Pure (matchProcedure / buildProcedureInjection / GIT_SEED_SET) is split from
15
+ * the I/O (read/writeProcedureStore) so the matcher + injection text are
16
+ * testable without touching disk — the coordinate-gate.ts shape.
17
+ */
18
+ /** The status ladder IS the silent-reflex safety structure (docs/procedure-system.md):
19
+ * a recipe is a hypothesis until reuse confirms it, and self-heals when it fails.
20
+ * seeded — hand-authored before any failure; injects with confidence.
21
+ * discovered — Tier-2 only: a new procedure the judge proposed; below learned.
22
+ * learned — captured from one cold-start floundering→success span.
23
+ * confirmed — a clean injected REPLAY proved the recipe.
24
+ * stale — injection floundered → re-enter LEARN (overwrite). */
25
+ export type ProcedureStatus = 'seeded' | 'discovered' | 'learned' | 'confirmed' | 'stale';
26
+ export interface Procedure {
27
+ /** Normalized intent key (one per repo). */
28
+ verb: string;
29
+ /** Phrases in the user message that fire this procedure. Lowercased; matched
30
+ * whole-word for single tokens, substring for multi-word phrases. */
31
+ triggers: string[];
32
+ /** The recipe — the winning command path. */
33
+ steps: string;
34
+ /** The gate / guardrail surfaced alongside the steps (load-bearing for
35
+ * destructive verbs — a procedure carries gates, not just steps). */
36
+ caveats?: string;
37
+ /** The linked exit condition — how we know the procedure is done. */
38
+ endpoint?: string;
39
+ status: ProcedureStatus;
40
+ /** Destructive verbs (push → prod) MUST stay seeded and are never overwritten
41
+ * by the LEARN leg — the one failure you can't afford even once. */
42
+ destructive?: boolean;
43
+ updatedAt?: string;
44
+ }
45
+ export interface ProcedureStore {
46
+ version: string;
47
+ procedures: Procedure[];
48
+ }
49
+ export interface ProcedureMatch {
50
+ procedure: Procedure;
51
+ /** Which trigger phrase fired — for diagnostics / the dry-run `match` command. */
52
+ trigger: string;
53
+ }
54
+ export declare const PROCEDURE_STORE_VERSION = "1";
55
+ /** Beside the matchset cache (guard.ts), keyed by project_id so it survives
56
+ * renames/worktrees and stays per-project. */
57
+ export declare function procedureStorePath(projectId: string): string;
58
+ /** Read the project's procedure store. Returns an empty store on any miss —
59
+ * fail-open, so a read error never blocks the hot path. */
60
+ export declare function readProcedureStore(projectId: string): ProcedureStore;
61
+ export declare function writeProcedureStore(projectId: string, store: ProcedureStore): void;
62
+ /** Insert-or-replace by verb. Destructive existing procedures are NOT silently
63
+ * downgraded: a learned/auto write can't overwrite a destructive=true seed
64
+ * (callers pass `force` for an explicit operator re-seed). Returns the store. */
65
+ export declare function upsertProcedure(store: ProcedureStore, proc: Procedure, force?: boolean): ProcedureStore;
66
+ export declare function removeProcedure(store: ProcedureStore, verb: string): ProcedureStore;
67
+ /** True if a raw trigger hit should be SUPPRESSED — it reads as a mention, not
68
+ * a request. PURE. (1) the trigger only appears inside a collision phrase;
69
+ * (2) a negation sits within 3 tokens before the trigger. */
70
+ export declare function intentSuppressed(promptLower: string, triggerLower: string): boolean;
71
+ /** Match a user prompt against the store. Returns the procedure whose
72
+ * LONGEST trigger phrase hits (most-specific wins — `git push` beats `push`,
73
+ * `ship a release` beats `ship`), or null. PURE — no I/O. The Tier-1 intent
74
+ * guard filters mention-not-request hits unless `ignoreIntentGuard` is set
75
+ * (the `match` dry-run uses it to explain a suppression). */
76
+ export declare function matchProcedure(prompt: string, store: ProcedureStore, opts?: {
77
+ ignoreIntentGuard?: boolean;
78
+ }): ProcedureMatch | null;
79
+ /** The additionalContext block injected at UserPromptSubmit when a procedure
80
+ * matches. Leads with the gate for destructive verbs (the guardrail is the
81
+ * point); otherwise leads with the steps. Bounded + labeled so the agent reads
82
+ * it as a known recipe, not a new instruction to reason about. */
83
+ export declare function buildProcedureInjection(proc: Procedure): string;
84
+ /** The five operational verbs Travis conflates, encoded with their real recipes
85
+ * + gates (docs/procedure-system.md). The deliberate contradiction —
86
+ * deploy = don't-ask, push = always-ask — is exactly what trips a learning
87
+ * dev; both gates ship on day one. `push` is destructive → seed-only. */
88
+ export declare const GIT_SEED_SET: Procedure[];
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ /** Procedure System — pure core + local store (docs/procedure-system.md).
3
+ *
4
+ * A *procedure* is the repo-specific recipe behind an operational intent
5
+ * (deploy / push / release / commit / merge). The system's job: when the user
6
+ * asks for one, inject the known recipe + its gate BEFORE the agent moves, so
7
+ * the operational verb runs cleanly instead of by trial-and-error.
8
+ *
9
+ * This module is the PROOF slice — Tier 1 (deterministic keyword trigger) +
10
+ * REPLAY (inject a seeded/learned recipe). It is intentionally local-file
11
+ * backed, mirroring guard.ts's matchset cache: the UserPromptSubmit hook reads
12
+ * it on the hot path, so there is NO network here (server persistence + the
13
+ * LEARN/Stop-hook capture leg land later — docs/procedure-system.md phases).
14
+ *
15
+ * Pure (matchProcedure / buildProcedureInjection / GIT_SEED_SET) is split from
16
+ * the I/O (read/writeProcedureStore) so the matcher + injection text are
17
+ * testable without touching disk — the coordinate-gate.ts shape.
18
+ */
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.GIT_SEED_SET = exports.PROCEDURE_STORE_VERSION = void 0;
54
+ exports.procedureStorePath = procedureStorePath;
55
+ exports.readProcedureStore = readProcedureStore;
56
+ exports.writeProcedureStore = writeProcedureStore;
57
+ exports.upsertProcedure = upsertProcedure;
58
+ exports.removeProcedure = removeProcedure;
59
+ exports.intentSuppressed = intentSuppressed;
60
+ exports.matchProcedure = matchProcedure;
61
+ exports.buildProcedureInjection = buildProcedureInjection;
62
+ const path = __importStar(require("path"));
63
+ const fs = __importStar(require("fs"));
64
+ exports.PROCEDURE_STORE_VERSION = '1';
65
+ // ---------- Store I/O (local, hot-path) --------------------------------------
66
+ function stateDir() {
67
+ const home = process.env.HOME || process.env.USERPROFILE || '';
68
+ return path.join(home, '.greprag', 'state');
69
+ }
70
+ /** Beside the matchset cache (guard.ts), keyed by project_id so it survives
71
+ * renames/worktrees and stays per-project. */
72
+ function procedureStorePath(projectId) {
73
+ return path.join(stateDir(), `procedures-${projectId}.json`);
74
+ }
75
+ /** Read the project's procedure store. Returns an empty store on any miss —
76
+ * fail-open, so a read error never blocks the hot path. */
77
+ function readProcedureStore(projectId) {
78
+ try {
79
+ const raw = fs.readFileSync(procedureStorePath(projectId), 'utf-8');
80
+ const parsed = JSON.parse(raw);
81
+ if (parsed && Array.isArray(parsed.procedures)) {
82
+ return { version: parsed.version || exports.PROCEDURE_STORE_VERSION, procedures: parsed.procedures };
83
+ }
84
+ }
85
+ catch { /* missing / unreadable → empty */ }
86
+ return { version: exports.PROCEDURE_STORE_VERSION, procedures: [] };
87
+ }
88
+ function writeProcedureStore(projectId, store) {
89
+ const file = procedureStorePath(projectId);
90
+ const dir = path.dirname(file);
91
+ if (!fs.existsSync(dir))
92
+ fs.mkdirSync(dir, { recursive: true });
93
+ fs.writeFileSync(file, JSON.stringify(store, null, 2) + '\n');
94
+ }
95
+ /** Insert-or-replace by verb. Destructive existing procedures are NOT silently
96
+ * downgraded: a learned/auto write can't overwrite a destructive=true seed
97
+ * (callers pass `force` for an explicit operator re-seed). Returns the store. */
98
+ function upsertProcedure(store, proc, force = false) {
99
+ const existing = store.procedures.find(p => p.verb === proc.verb);
100
+ if (existing && existing.destructive && !force && proc.status !== 'seeded') {
101
+ return store; // protect the gate — never auto-overwrite a destructive seed
102
+ }
103
+ const next = store.procedures.filter(p => p.verb !== proc.verb);
104
+ next.push({ ...proc, updatedAt: proc.updatedAt || new Date().toISOString() });
105
+ return { version: store.version || exports.PROCEDURE_STORE_VERSION, procedures: next };
106
+ }
107
+ function removeProcedure(store, verb) {
108
+ return {
109
+ version: store.version || exports.PROCEDURE_STORE_VERSION,
110
+ procedures: store.procedures.filter(p => p.verb !== verb),
111
+ };
112
+ }
113
+ // ---------- Matching (PURE) --------------------------------------------------
114
+ /** Does a trigger phrase occur in the (lowercased) prompt? Single tokens match
115
+ * whole-word (`deploy` ≠ `redeployment`); multi-word phrases match as a
116
+ * substring (`ship it`). */
117
+ function triggerHits(promptLower, triggerLower) {
118
+ if (!triggerLower)
119
+ return false;
120
+ if (/\s/.test(triggerLower))
121
+ return promptLower.includes(triggerLower);
122
+ const re = new RegExp(`(^|[^a-z0-9])${escapeRegex(triggerLower)}([^a-z0-9]|$)`);
123
+ return re.test(promptLower);
124
+ }
125
+ function escapeRegex(s) {
126
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
127
+ }
128
+ // ---------- Intent guard (PURE) ----------------------------------------------
129
+ /** Tier-1 intent guard — cheap, deterministic suppression of keyword
130
+ * false-fires. A substring match injects on a *mention*, not a *request*
131
+ * (docs/procedure-system.md): bare "deploy" fires on "don't deploy yet" and
132
+ * "push" on "push back the deadline". For safe verbs that's noise; for a
133
+ * destructive verb a false ⛔ gate is actively misleading. Suppresses two
134
+ * classes — this is the deterministic stopgap; Tier-2's prompt-judge replaces
135
+ * it with real intent recognition. */
136
+ const INTENT_NEGATIONS = [
137
+ "don't", 'dont', 'not', 'no', 'never', 'without', 'avoid', "won't", 'wont',
138
+ "didn't", 'didnt', 'cannot', "can't", 'cant', 'stop',
139
+ ];
140
+ /** The trigger token living inside a common NON-command phrase. */
141
+ const INTENT_COLLISION_PHRASES = [
142
+ 'push back', 'push for', 'push notification', 'push notifications', 'pushover',
143
+ 'merge conflict', 'merge conflicts', 'merge request', 'merge sort',
144
+ 'press release', 'release notes', 'release candidate', 'release date',
145
+ 'commit message', 'commit hash', 'commit history', 'commit sha',
146
+ ];
147
+ /** True if a raw trigger hit should be SUPPRESSED — it reads as a mention, not
148
+ * a request. PURE. (1) the trigger only appears inside a collision phrase;
149
+ * (2) a negation sits within 3 tokens before the trigger. */
150
+ function intentSuppressed(promptLower, triggerLower) {
151
+ // (1) collision phrase — suppress only if the trigger has NO other occurrence
152
+ // outside the collision phrase (a real command alongside the mention wins).
153
+ for (const phrase of INTENT_COLLISION_PHRASES) {
154
+ if (phrase.includes(triggerLower) && promptLower.includes(phrase)) {
155
+ const stripped = promptLower.split(phrase).join(' · ');
156
+ if (!triggerHits(stripped, triggerLower))
157
+ return true;
158
+ }
159
+ }
160
+ // (2) negation within 3 tokens before the trigger ("don't deploy", "no merge").
161
+ const idx = promptLower.search(new RegExp(`(^|[^a-z0-9])${escapeRegex(triggerLower)}([^a-z0-9]|$)`));
162
+ if (idx >= 0) {
163
+ const before = promptLower.slice(0, idx).split(/[^a-z']+/).filter(Boolean);
164
+ const window = ' ' + before.slice(-3).join(' ') + ' ';
165
+ if (INTENT_NEGATIONS.some(neg => window.includes(' ' + neg + ' ')))
166
+ return true;
167
+ }
168
+ return false;
169
+ }
170
+ /** Match a user prompt against the store. Returns the procedure whose
171
+ * LONGEST trigger phrase hits (most-specific wins — `git push` beats `push`,
172
+ * `ship a release` beats `ship`), or null. PURE — no I/O. The Tier-1 intent
173
+ * guard filters mention-not-request hits unless `ignoreIntentGuard` is set
174
+ * (the `match` dry-run uses it to explain a suppression). */
175
+ function matchProcedure(prompt, store, opts = {}) {
176
+ if (!prompt)
177
+ return null;
178
+ const promptLower = prompt.toLowerCase();
179
+ let best = null;
180
+ let bestLen = -1;
181
+ for (const procedure of store.procedures) {
182
+ for (const trigger of procedure.triggers) {
183
+ const t = trigger.toLowerCase();
184
+ if (!triggerHits(promptLower, t))
185
+ continue;
186
+ if (!opts.ignoreIntentGuard && intentSuppressed(promptLower, t))
187
+ continue;
188
+ if (t.length > bestLen) {
189
+ best = { procedure, trigger };
190
+ bestLen = t.length;
191
+ }
192
+ }
193
+ }
194
+ return best;
195
+ }
196
+ // ---------- Injection text (PURE) --------------------------------------------
197
+ /** The additionalContext block injected at UserPromptSubmit when a procedure
198
+ * matches. Leads with the gate for destructive verbs (the guardrail is the
199
+ * point); otherwise leads with the steps. Bounded + labeled so the agent reads
200
+ * it as a known recipe, not a new instruction to reason about. */
201
+ function buildProcedureInjection(proc) {
202
+ const lines = [];
203
+ const tag = proc.destructive ? ' ⚠ DESTRUCTIVE' : '';
204
+ lines.push(`[Procedure: ${proc.verb} — ${proc.status}${tag}] This repo has a known recipe for "${proc.verb}".`);
205
+ if (proc.destructive && proc.caveats) {
206
+ lines.push(` ⛔ GATE: ${proc.caveats}`);
207
+ lines.push(` STEPS (only after approval): ${proc.steps}`);
208
+ }
209
+ else {
210
+ lines.push(` STEPS: ${proc.steps}`);
211
+ if (proc.caveats)
212
+ lines.push(` GATE: ${proc.caveats}`);
213
+ }
214
+ if (proc.endpoint)
215
+ lines.push(` ENDPOINT (done when): ${proc.endpoint}`);
216
+ lines.push(proc.destructive
217
+ ? ` Follow the gate exactly. Never run the steps without a fresh approval this turn.`
218
+ : ` Use this recipe. If it no longer works, say so — that's a stale procedure to re-learn.`);
219
+ return lines.join('\n');
220
+ }
221
+ // ---------- The git-ecosystem seed set ---------------------------------------
222
+ /** The five operational verbs Travis conflates, encoded with their real recipes
223
+ * + gates (docs/procedure-system.md). The deliberate contradiction —
224
+ * deploy = don't-ask, push = always-ask — is exactly what trips a learning
225
+ * dev; both gates ship on day one. `push` is destructive → seed-only. */
226
+ exports.GIT_SEED_SET = [
227
+ {
228
+ verb: 'commit',
229
+ triggers: ['commit', 'check in', 'check it in', 'checkpoint this', 'land it'],
230
+ steps: 'git add -A && git commit -m "wip: <msg>"; then merge the feature branch into the default branch, prune the worktree, delete the merged branch (the /commit flow).',
231
+ caveats: 'Scope = only MY work — never sweep a parallel workstream\'s pending changes. STOPS before push.',
232
+ endpoint: 'changes committed and the feature branch merged into default',
233
+ status: 'seeded',
234
+ },
235
+ {
236
+ verb: 'merge',
237
+ triggers: ['merge', 'merge the branch', 'merge to main', 'merge into main'],
238
+ steps: 'git checkout <default> && git merge <branch> (folded into the commit flow).',
239
+ caveats: 'Another session live in this repo? Coordinate with the peer before merging shared state.',
240
+ endpoint: 'branch merged into the default branch with no conflicts',
241
+ status: 'seeded',
242
+ },
243
+ {
244
+ verb: 'push',
245
+ triggers: ['push', 'git push', 'push to remote', 'push it up', 'push upstream'],
246
+ steps: 'git push',
247
+ caveats: 'git push triggers a PRODUCTION deploy. STOP and get explicit fresh approval before pushing — never push without a fresh "yes" this turn.',
248
+ endpoint: 'operator approved the push AND it completed',
249
+ status: 'seeded',
250
+ destructive: true,
251
+ },
252
+ {
253
+ verb: 'deploy',
254
+ triggers: ['deploy', 'deploy the api', 'deploy the worker', 'redeploy'],
255
+ steps: 'cd packages/api && npm run deploy',
256
+ caveats: 'Routine — after a core fix + commit, run this WITHOUT asking. This is the wrangler deploy of the API worker; it is NOT a git push.',
257
+ endpoint: 'wrangler prints the published worker version (deploy success output)',
258
+ status: 'seeded',
259
+ },
260
+ {
261
+ verb: 'release',
262
+ triggers: ['release', 'ship it', 'ship a release', 'cut a release', 'publish the release', 'do a release'],
263
+ steps: 'Run the /release flow — greprag\'s actual ship path (version bump + publish).',
264
+ caveats: 'greprag ships via /release — NOT /commit and NOT /deploy. Do not conflate the three: commit lands code, deploy pushes the worker, release publishes a version.',
265
+ endpoint: 'the release is published (new version live)',
266
+ status: 'seeded',
267
+ },
268
+ ];
269
+ //# sourceMappingURL=procedure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procedure.js","sourceRoot":"","sources":["../src/procedure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /** Skill-gain landing — the Skill Learning Loop's write-back half
2
+ * (docs/skill-learning-loop.md §fuse shape, operator-ratified 2026-07-01).
3
+ *
4
+ * THE SHAPE (Tony Stark's briefcase suit): the server-side distiller packaged
5
+ * each gain as a focused doc + a blind one-liner. This leg — pure code, never
6
+ * agent voluntarism (the skill-tuning autopsy's law) — lands both files:
7
+ *
8
+ * docs/learned/<slug>.md the laser-focused learning doc
9
+ * SKILL.md (EOF) one FUSE line: the one-liner + the schematic
10
+ * telling the NEXT invocation exactly what to do —
11
+ * expand the doc, fold it in where it belongs,
12
+ * delete the fuse and the doc.
13
+ *
14
+ * The fuse is self-applying because it loads WITH the skill: the next agent
15
+ * to invoke the skill reads it as part of the skill's own instructions, does
16
+ * the short tune with the whole skill in context (the only actor that ever
17
+ * legitimately has it), and the skill converges clean. If a run skips the
18
+ * tune, the fuse persists as ordinary progressive disclosure — the learning
19
+ * stays live either way (graceful degradation, no failure mode).
20
+ *
21
+ * Guards: CAP 3 undigested fuses per skill (overflow waits server-side —
22
+ * a skill drowning in briefcases isn't being used anyway); every artifact
23
+ * stamped `skillgain:<id>`; `greprag skillgain reject <id>` is the undo
24
+ * (removes fuse + doc). Landing routes through resolveSkillDir — the ONE
25
+ * seam that swaps to the greprag-load skill store when skills move into the
26
+ * CLI (the no-SKILL.md endgame).
27
+ *
28
+ * Write-target routing (the trap): greprag's bundled skills publish from the
29
+ * repo source (packages/cli/skill/<name>/) — ~/.claude/skills/<name>/ is an
30
+ * init-overwritten artifact. Bundled + repo present → repo source; otherwise
31
+ * the global skills dir; neither → the gain stays pending. */
32
+ export interface PendingSkillGain {
33
+ nodeId: string;
34
+ skill: string;
35
+ gainType: 'rule' | 'scope' | 'reference';
36
+ text: string;
37
+ oneLiner?: string;
38
+ docSlug?: string;
39
+ docBody?: string;
40
+ }
41
+ /** Skills that ship FROM the greprag repo — their canonical source is
42
+ * packages/cli/skill/<name>/; the installed copy is overwritten at init. */
43
+ export declare const BUNDLED_SKILLS: string[];
44
+ export declare const LEARNED_DIR_RELPATH: string;
45
+ /** v1 legacy zone — reject still scans it for stamps landed before the recut. */
46
+ export declare const LEARNINGS_RELPATH: string;
47
+ /** Max undigested fuse lines a SKILL.md may carry; past this, new gains wait
48
+ * server-side. Operator-ratified (2026-07-01). */
49
+ export declare const MAX_FUSES_PER_SKILL = 3;
50
+ /** Resolve the canonical directory for a skill. `existsFn` injectable for
51
+ * tests. Order: bundled repo source (when cwd IS the greprag repo) → global
52
+ * skills dir → null (defer). THE storage seam — the greprag-load skill-store
53
+ * backend replaces this resolution, nothing above it. */
54
+ export declare function resolveSkillDir(skill: string, cwd: string, homeDir: string, existsFn?: (p: string) => boolean): string | null;
55
+ export declare function hasGainStamp(content: string, nodeId: string): boolean;
56
+ /** Count undigested fuse lines in a SKILL.md body (digested ones were deleted
57
+ * by the tune, so the count self-heals as briefcases get absorbed). PURE. */
58
+ export declare function countFuses(skillMdContent: string): number;
59
+ /** The fuse line — the briefcase's button. One line, blind (the one-liner
60
+ * names the learning; the mass lives in the doc), carrying the exact
61
+ * schematic for the next invocation. PURE — unit-tested. */
62
+ export declare function buildFuseLine(gain: PendingSkillGain, docRelPath: string, projectName: string, dateISO: string): string;
63
+ export type LandOutcome = 'landed' | 'already-landed' | 'capped' | 'deferred';
64
+ /** Land ONE briefcase: write the learned doc + append the fuse to SKILL.md.
65
+ * Deterministic file work only — never throws (failure defers the gain). */
66
+ export declare function landBriefcase(gain: PendingSkillGain, cwd: string, homeDir: string, projectName: string): LandOutcome;
67
+ /** Remove a gain's artifacts wherever they landed — the `skillgain reject`
68
+ * undo: the fuse line (SKILL.md), the learned doc, and any v1-legacy
69
+ * learnings.md line. Returns true if anything was removed. Never throws. */
70
+ export declare function removeLandedGain(skill: string, nodeId: string, cwd: string, homeDir: string): boolean;
71
+ export interface SkillGainLandingReport {
72
+ /** Briefcases landed this session start (for the informational announce). */
73
+ landed: Array<{
74
+ nodeId: string;
75
+ skill: string;
76
+ oneLiner: string;
77
+ }>;
78
+ }
79
+ /** The full landing pass. Every gain with a payload lands as a briefcase
80
+ * (capped per skill + per start); payload-less/unroutable gains stay pending.
81
+ * Returns the report (announce) + the status updates to POST back. */
82
+ export declare function landPendingGains(pending: PendingSkillGain[], cwd: string, homeDir: string, projectName: string): {
83
+ report: SkillGainLandingReport;
84
+ statusUpdates: Array<{
85
+ nodeId: string;
86
+ status: 'landed';
87
+ }>;
88
+ };