greprag 5.50.0 → 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.
- package/dist/commands/load.d.ts +8 -5
- package/dist/commands/load.js +81 -10
- package/dist/commands/load.js.map +1 -1
- package/dist/commands/reminder-registry.js +3 -1
- package/dist/commands/reminder-registry.js.map +1 -1
- package/dist/commands/reminder-types.d.ts +8 -0
- package/dist/commands/skill-mirror-reminder.d.ts +15 -0
- package/dist/commands/skill-mirror-reminder.js +33 -0
- package/dist/commands/skill-mirror-reminder.js.map +1 -0
- package/dist/hook.js +193 -11
- package/dist/hook.js.map +1 -1
- package/dist/opencode-plugin.bundle.js +25 -1
- package/dist/procedure-watch.d.ts +153 -0
- package/dist/procedure-watch.js +349 -0
- package/dist/procedure-watch.js.map +1 -0
- package/dist/skill-mirror-client.d.ts +37 -0
- package/dist/skill-mirror-client.js +172 -0
- package/dist/skill-mirror-client.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Procedure watch — the Procedure System's span-watch state + close logic
|
|
3
|
+
* (docs/procedure-system.md §V1 LEARN-leg build spec, component 1).
|
|
4
|
+
*
|
|
5
|
+
* The unit of learning is a WATCH WINDOW: the UserPromptSubmit trigger opens
|
|
6
|
+
* it, the Stop hook observes each turn inside it, negative continuity closes
|
|
7
|
+
* it ("is the <verb> procedure still live?" — cessation, never completion).
|
|
8
|
+
* One JSON file beside the procedure store; ONE active watch at a time (v1).
|
|
9
|
+
*
|
|
10
|
+
* PURE open/advance/close (openWatch / buildTurnDigest / advanceWatch /
|
|
11
|
+
* liveSpan / applyDistillTransition) is split from the file I/O (read/write/
|
|
12
|
+
* clear) — the procedure.ts shape — so hysteresis, the watchdog, and the
|
|
13
|
+
* transition table are unit-testable without a hook.
|
|
14
|
+
*
|
|
15
|
+
* Endpoint-detection invariants (§Endpoint detection):
|
|
16
|
+
* - hysteresis: one OFF turn never closes (a tangent can't truncate the
|
|
17
|
+
* span); close at offStreak ≥ 2.
|
|
18
|
+
* - the endpoint stamps at the LAST LIVE turn, not the first dead one —
|
|
19
|
+
* span = observations[0 .. lastLiveTurn].
|
|
20
|
+
* - judge unreachable → offStreak untouched (the watch extends); the
|
|
21
|
+
* max-turn watchdog is the backstop, never the primary mechanism. */
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
39
|
+
var ownKeys = function(o) {
|
|
40
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
41
|
+
var ar = [];
|
|
42
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
43
|
+
return ar;
|
|
44
|
+
};
|
|
45
|
+
return ownKeys(o);
|
|
46
|
+
};
|
|
47
|
+
return function (mod) {
|
|
48
|
+
if (mod && mod.__esModule) return mod;
|
|
49
|
+
var result = {};
|
|
50
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
51
|
+
__setModuleDefault(result, mod);
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.TIER1_LEARN_TRIGGERS = exports.DIGEST_USER_CAP = exports.DIGEST_TOTAL_CAP = exports.WATCH_OFF_STREAK_CLOSE = exports.WATCH_MAX_TURNS = void 0;
|
|
57
|
+
exports.matchLearnTrigger = matchLearnTrigger;
|
|
58
|
+
exports.isDestructiveVerb = isDestructiveVerb;
|
|
59
|
+
exports.learnTriggersForVerb = learnTriggersForVerb;
|
|
60
|
+
exports.openWatch = openWatch;
|
|
61
|
+
exports.buildTurnDigest = buildTurnDigest;
|
|
62
|
+
exports.willExceedWatchdog = willExceedWatchdog;
|
|
63
|
+
exports.advanceWatch = advanceWatch;
|
|
64
|
+
exports.liveSpan = liveSpan;
|
|
65
|
+
exports.applyDistillTransition = applyDistillTransition;
|
|
66
|
+
exports.procedureWatchPath = procedureWatchPath;
|
|
67
|
+
exports.hasProcedureWatch = hasProcedureWatch;
|
|
68
|
+
exports.readProcedureWatch = readProcedureWatch;
|
|
69
|
+
exports.writeProcedureWatch = writeProcedureWatch;
|
|
70
|
+
exports.clearProcedureWatch = clearProcedureWatch;
|
|
71
|
+
exports.openWatchIfIdle = openWatchIfIdle;
|
|
72
|
+
const path = __importStar(require("path"));
|
|
73
|
+
const fs = __importStar(require("fs"));
|
|
74
|
+
const procedure_1 = require("./procedure");
|
|
75
|
+
/** Watchdog backstop: a watch never observes past this many turns — the next
|
|
76
|
+
* turn aborts it (log a fix-queue smell, never distill). */
|
|
77
|
+
exports.WATCH_MAX_TURNS = 15;
|
|
78
|
+
/** Hysteresis: consecutive OFF turns required to close (a one-turn tangent
|
|
79
|
+
* can't truncate the span). */
|
|
80
|
+
exports.WATCH_OFF_STREAK_CLOSE = 2;
|
|
81
|
+
/** Per-turn digest cap, serialized. */
|
|
82
|
+
exports.DIGEST_TOTAL_CAP = 1_500;
|
|
83
|
+
/** User-prompt head cap inside the digest. */
|
|
84
|
+
exports.DIGEST_USER_CAP = 300;
|
|
85
|
+
const DIGEST_MAX_COMMANDS = 6;
|
|
86
|
+
const DIGEST_COMMAND_CAP = 180;
|
|
87
|
+
const DIGEST_EXIT_HINT_CAP = 80;
|
|
88
|
+
const DIGEST_MAX_FILES = 8;
|
|
89
|
+
// ---------- Tier-1 LEARN trigger vocabulary (PURE data) -----------------------
|
|
90
|
+
/** The Tier-1 trigger set for OPENING A LEARN WATCH, independent of the store
|
|
91
|
+
* (docs/procedure-system.md §Tier 1: deploy / push / release / ship / build /
|
|
92
|
+
* test — `ship` phrases map to the `release` verb, matching GIT_SEED_SET).
|
|
93
|
+
* `build` + `test` have no seed: the clean LEARN proof case. `push` is
|
|
94
|
+
* destructive — it sits here only so the opener can NAME the refusal; a LEARN
|
|
95
|
+
* watch never opens for it (the seed is the canon even when stale). Entries
|
|
96
|
+
* are Procedure-shaped (steps empty — vocabulary, not recipes) so the same
|
|
97
|
+
* matcher + intent guard run over them. */
|
|
98
|
+
exports.TIER1_LEARN_TRIGGERS = [
|
|
99
|
+
{ verb: 'deploy', triggers: ['deploy', 'deploy the api', 'deploy the worker', 'redeploy'], steps: '', status: 'seeded' },
|
|
100
|
+
{ verb: 'push', triggers: ['push', 'git push', 'push to remote', 'push it up', 'push upstream'], steps: '', status: 'seeded', destructive: true },
|
|
101
|
+
{ verb: 'release', triggers: ['release', 'ship', 'ship it', 'ship a release', 'cut a release', 'publish the release', 'do a release'], steps: '', status: 'seeded' },
|
|
102
|
+
{ verb: 'build', triggers: ['build', 'rebuild', 'compile', 'run the build'], steps: '', status: 'seeded' },
|
|
103
|
+
{ verb: 'test', triggers: ['test', 'tests', 'run the tests', 'run tests'], steps: '', status: 'seeded' },
|
|
104
|
+
];
|
|
105
|
+
/** Match a prompt against the Tier-1 LEARN vocabulary (same matcher + intent
|
|
106
|
+
* guard as the store path). PURE. */
|
|
107
|
+
function matchLearnTrigger(prompt) {
|
|
108
|
+
return (0, procedure_1.matchProcedure)(prompt, {
|
|
109
|
+
version: procedure_1.PROCEDURE_STORE_VERSION,
|
|
110
|
+
procedures: exports.TIER1_LEARN_TRIGGERS,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Is this verb destructive — per the store's procedure OR the Tier-1
|
|
114
|
+
* vocabulary? Destructive verbs are never learn-writable and a LEARN watch
|
|
115
|
+
* never opens for them. PURE. */
|
|
116
|
+
function isDestructiveVerb(verb, store) {
|
|
117
|
+
if (store.procedures.some(p => p.verb === verb && p.destructive))
|
|
118
|
+
return true;
|
|
119
|
+
return exports.TIER1_LEARN_TRIGGERS.some(p => p.verb === verb && p.destructive);
|
|
120
|
+
}
|
|
121
|
+
/** The trigger phrases a LEARNED procedure should match on next time — the
|
|
122
|
+
* store procedure's own triggers when it exists (stale re-learn keeps them),
|
|
123
|
+
* else the Tier-1 vocabulary's, else the bare verb. PURE. */
|
|
124
|
+
function learnTriggersForVerb(verb, store) {
|
|
125
|
+
const existing = store.procedures.find(p => p.verb === verb);
|
|
126
|
+
if (existing && existing.triggers.length)
|
|
127
|
+
return existing.triggers;
|
|
128
|
+
const vocab = exports.TIER1_LEARN_TRIGGERS.find(p => p.verb === verb);
|
|
129
|
+
if (vocab && vocab.triggers.length)
|
|
130
|
+
return vocab.triggers;
|
|
131
|
+
return [verb];
|
|
132
|
+
}
|
|
133
|
+
// ---------- Open (PURE) -------------------------------------------------------
|
|
134
|
+
function openWatch(verb, phase, openedAt) {
|
|
135
|
+
return {
|
|
136
|
+
verb,
|
|
137
|
+
phase,
|
|
138
|
+
openedAt: openedAt || new Date().toISOString(),
|
|
139
|
+
turnCount: 0,
|
|
140
|
+
observations: [],
|
|
141
|
+
lastLiveTurn: 0,
|
|
142
|
+
offStreak: 0,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function oneLine(s) {
|
|
146
|
+
return (s || '').replace(/\s+/g, ' ').trim();
|
|
147
|
+
}
|
|
148
|
+
/** Build one compact TurnDigest: user-prompt head ≤300 chars, Bash commands
|
|
149
|
+
* (+ a short output-tail exit hint) from toolCalls, files touched, turn
|
|
150
|
+
* status — ≤1.5K serialized total. PURE — unit-tested. */
|
|
151
|
+
function buildTurnDigest(turn, turnNumber) {
|
|
152
|
+
const commands = [];
|
|
153
|
+
for (const tc of turn.toolCalls) {
|
|
154
|
+
if (tc.name !== 'Bash' || !tc.brief)
|
|
155
|
+
continue;
|
|
156
|
+
if (commands.length >= DIGEST_MAX_COMMANDS)
|
|
157
|
+
break;
|
|
158
|
+
let cmd = oneLine(tc.brief).slice(0, DIGEST_COMMAND_CAP);
|
|
159
|
+
if (tc._output) {
|
|
160
|
+
const lines = tc._output.split('\n').map(l => l.trim()).filter(Boolean);
|
|
161
|
+
const tail = lines.length ? lines[lines.length - 1].slice(0, DIGEST_EXIT_HINT_CAP) : '';
|
|
162
|
+
if (tail)
|
|
163
|
+
cmd += ` ⇒ ${tail}`;
|
|
164
|
+
}
|
|
165
|
+
commands.push(cmd);
|
|
166
|
+
}
|
|
167
|
+
const digest = {
|
|
168
|
+
turn: turnNumber,
|
|
169
|
+
user: oneLine(turn.userPrompt).slice(0, exports.DIGEST_USER_CAP),
|
|
170
|
+
commands,
|
|
171
|
+
files: turn.filesTouched.slice(0, DIGEST_MAX_FILES).map(f => f.slice(0, 160)),
|
|
172
|
+
status: turn.status || 'completed',
|
|
173
|
+
};
|
|
174
|
+
// Total-size guard: trim breadth (files, then commands, then the user head)
|
|
175
|
+
// until the serialized digest fits the cap.
|
|
176
|
+
while (JSON.stringify(digest).length > exports.DIGEST_TOTAL_CAP) {
|
|
177
|
+
if (digest.files.length > 2)
|
|
178
|
+
digest.files = digest.files.slice(0, digest.files.length - 1);
|
|
179
|
+
else if (digest.commands.length > 1)
|
|
180
|
+
digest.commands = digest.commands.slice(0, digest.commands.length - 1);
|
|
181
|
+
else if (digest.user.length > 100)
|
|
182
|
+
digest.user = digest.user.slice(0, digest.user.length - 50);
|
|
183
|
+
else
|
|
184
|
+
break; // structurally minimal — accept
|
|
185
|
+
}
|
|
186
|
+
return digest;
|
|
187
|
+
}
|
|
188
|
+
/** Would observing one more turn cross the watchdog? The caller checks this
|
|
189
|
+
* BEFORE the judge call so the aborting turn costs nothing. PURE. */
|
|
190
|
+
function willExceedWatchdog(watch) {
|
|
191
|
+
return watch.turnCount >= exports.WATCH_MAX_TURNS;
|
|
192
|
+
}
|
|
193
|
+
/** Advance the watch by one observed turn. Appends the digest, then applies
|
|
194
|
+
* the continuity verdict per §Endpoint detection:
|
|
195
|
+
* live=true → stamp lastLiveTurn, reset offStreak
|
|
196
|
+
* live=false → offStreak++
|
|
197
|
+
* live=null → judge unreachable: offStreak UNTOUCHED (the watch extends;
|
|
198
|
+
* the watchdog is the backstop)
|
|
199
|
+
* Dispositions: 'watchdog' when the turn count exceeds the cap (defensive —
|
|
200
|
+
* callers should pre-check willExceedWatchdog), 'close' at
|
|
201
|
+
* offStreak ≥ WATCH_OFF_STREAK_CLOSE, else 'continue'. PURE — unit-tested. */
|
|
202
|
+
function advanceWatch(watch, digest, live) {
|
|
203
|
+
const next = {
|
|
204
|
+
...watch,
|
|
205
|
+
turnCount: watch.turnCount + 1,
|
|
206
|
+
observations: [...watch.observations, digest],
|
|
207
|
+
};
|
|
208
|
+
if (next.turnCount > exports.WATCH_MAX_TURNS) {
|
|
209
|
+
return { watch: next, disposition: 'watchdog' };
|
|
210
|
+
}
|
|
211
|
+
if (live === true) {
|
|
212
|
+
next.lastLiveTurn = next.turnCount;
|
|
213
|
+
next.offStreak = 0;
|
|
214
|
+
}
|
|
215
|
+
else if (live === false) {
|
|
216
|
+
next.offStreak = watch.offStreak + 1;
|
|
217
|
+
} // live === null → untouched
|
|
218
|
+
if (next.offStreak >= exports.WATCH_OFF_STREAK_CLOSE) {
|
|
219
|
+
return { watch: next, disposition: 'close' };
|
|
220
|
+
}
|
|
221
|
+
return { watch: next, disposition: 'continue' };
|
|
222
|
+
}
|
|
223
|
+
/** The live span — the endpoint stamps at the last LIVE turn, so trailing
|
|
224
|
+
* not-live turns never enter the artifact. Span = observations[0 ..
|
|
225
|
+
* lastLiveTurn]. Empty when the watch was never live (nothing to distill —
|
|
226
|
+
* never register garbage). PURE. */
|
|
227
|
+
function liveSpan(watch) {
|
|
228
|
+
return watch.observations.slice(0, watch.lastLiveTurn);
|
|
229
|
+
}
|
|
230
|
+
/** Apply the spec's transition table (component 6) to the procedure store:
|
|
231
|
+
*
|
|
232
|
+
* LEARN | any (span ended) | status=learned, steps/endpoint/caveats from distill
|
|
233
|
+
* REPLAY | clean | status=confirmed (steps untouched)
|
|
234
|
+
* REPLAY | floundered | re-learn in place: distill the failed span → learned
|
|
235
|
+
* any | distill unreadable / judge down | no write; watch discarded
|
|
236
|
+
*
|
|
237
|
+
* Each row gates on the fields it actually consumes: LEARN and
|
|
238
|
+
* REPLAY-floundered need the distilled fields; REPLAY-clean needs the
|
|
239
|
+
* outcome. A missing required field = the unreadable/judge-down row → no
|
|
240
|
+
* write. All writes flow through upsertProcedure, whose destructive guard
|
|
241
|
+
* already refuses to overwrite a `push` seed (never weakened here).
|
|
242
|
+
* PURE — unit-tested. Returns the (possibly unchanged) store + what happened. */
|
|
243
|
+
function applyDistillTransition(store, watch, outcome, distilled, fallbackTriggers) {
|
|
244
|
+
const existing = store.procedures.find(p => p.verb === watch.verb);
|
|
245
|
+
if (watch.phase === 'LEARN') {
|
|
246
|
+
if (!distilled)
|
|
247
|
+
return { store, action: 'discarded' };
|
|
248
|
+
const proc = {
|
|
249
|
+
verb: watch.verb,
|
|
250
|
+
triggers: existing?.triggers?.length ? existing.triggers : fallbackTriggers,
|
|
251
|
+
steps: distilled.steps,
|
|
252
|
+
endpoint: distilled.endpoint,
|
|
253
|
+
caveats: distilled.caveats,
|
|
254
|
+
status: 'learned',
|
|
255
|
+
destructive: existing?.destructive,
|
|
256
|
+
};
|
|
257
|
+
return { store: (0, procedure_1.upsertProcedure)(store, proc), action: 'learned' };
|
|
258
|
+
}
|
|
259
|
+
// REPLAY
|
|
260
|
+
if (outcome === 'clean') {
|
|
261
|
+
if (!existing)
|
|
262
|
+
return { store, action: 'discarded' };
|
|
263
|
+
return {
|
|
264
|
+
store: (0, procedure_1.upsertProcedure)(store, { ...existing, status: 'confirmed' }),
|
|
265
|
+
action: 'confirmed',
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (outcome === 'floundered') {
|
|
269
|
+
// The failed span already contains the new winning path — a stale REPLAY
|
|
270
|
+
// span IS the next LEARN span; no extra failure needed.
|
|
271
|
+
if (!distilled)
|
|
272
|
+
return { store, action: 'discarded' };
|
|
273
|
+
const proc = {
|
|
274
|
+
verb: watch.verb,
|
|
275
|
+
triggers: existing?.triggers?.length ? existing.triggers : fallbackTriggers,
|
|
276
|
+
steps: distilled.steps,
|
|
277
|
+
endpoint: distilled.endpoint,
|
|
278
|
+
caveats: distilled.caveats,
|
|
279
|
+
status: 'learned',
|
|
280
|
+
destructive: existing?.destructive,
|
|
281
|
+
};
|
|
282
|
+
return { store: (0, procedure_1.upsertProcedure)(store, proc), action: 'relearned' };
|
|
283
|
+
}
|
|
284
|
+
// outcome null → judge down → no write.
|
|
285
|
+
return { store, action: 'discarded' };
|
|
286
|
+
}
|
|
287
|
+
// ---------- Watch file I/O (beside the procedure store) -----------------------
|
|
288
|
+
function stateDir() {
|
|
289
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
290
|
+
return path.join(home, '.greprag', 'state');
|
|
291
|
+
}
|
|
292
|
+
function procedureWatchPath(projectId) {
|
|
293
|
+
return path.join(stateDir(), `procedure-watch-${projectId}.json`);
|
|
294
|
+
}
|
|
295
|
+
/** The Stop-hook observer's zero-cost gate: no file → no watch → no work. */
|
|
296
|
+
function hasProcedureWatch(projectId) {
|
|
297
|
+
try {
|
|
298
|
+
return fs.existsSync(procedureWatchPath(projectId));
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/** Read the active watch. Null on any miss/corruption — fail-open; the caller
|
|
305
|
+
* clears the file so a corrupt watch can't wedge the observer. */
|
|
306
|
+
function readProcedureWatch(projectId) {
|
|
307
|
+
try {
|
|
308
|
+
const raw = fs.readFileSync(procedureWatchPath(projectId), 'utf-8');
|
|
309
|
+
const w = JSON.parse(raw);
|
|
310
|
+
if (w && typeof w.verb === 'string' && w.verb
|
|
311
|
+
&& (w.phase === 'LEARN' || w.phase === 'REPLAY')
|
|
312
|
+
&& Array.isArray(w.observations)) {
|
|
313
|
+
return {
|
|
314
|
+
verb: w.verb,
|
|
315
|
+
phase: w.phase,
|
|
316
|
+
openedAt: typeof w.openedAt === 'string' ? w.openedAt : '',
|
|
317
|
+
turnCount: typeof w.turnCount === 'number' ? w.turnCount : w.observations.length,
|
|
318
|
+
observations: w.observations,
|
|
319
|
+
lastLiveTurn: typeof w.lastLiveTurn === 'number' ? w.lastLiveTurn : 0,
|
|
320
|
+
offStreak: typeof w.offStreak === 'number' ? w.offStreak : 0,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch { /* missing / unreadable → null */ }
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
function writeProcedureWatch(projectId, watch) {
|
|
328
|
+
const file = procedureWatchPath(projectId);
|
|
329
|
+
const dir = path.dirname(file);
|
|
330
|
+
if (!fs.existsSync(dir))
|
|
331
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
332
|
+
fs.writeFileSync(file, JSON.stringify(watch, null, 2) + '\n');
|
|
333
|
+
}
|
|
334
|
+
function clearProcedureWatch(projectId) {
|
|
335
|
+
try {
|
|
336
|
+
fs.unlinkSync(procedureWatchPath(projectId));
|
|
337
|
+
}
|
|
338
|
+
catch { /* already gone */ }
|
|
339
|
+
}
|
|
340
|
+
/** Open a watch iff none is active (ONE active watch at a time, v1 — an
|
|
341
|
+
* in-flight watch is never replaced by a new trigger). Returns whether a
|
|
342
|
+
* watch was opened. */
|
|
343
|
+
function openWatchIfIdle(projectId, verb, phase) {
|
|
344
|
+
if (hasProcedureWatch(projectId))
|
|
345
|
+
return false;
|
|
346
|
+
writeProcedureWatch(projectId, openWatch(verb, phase));
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=procedure-watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procedure-watch.js","sourceRoot":"","sources":["../src/procedure-watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Skill-mirror client — the Tier-3 mirror's upload half
|
|
2
|
+
* (docs/load-system.md §Tier 3). Runs inside the Stop hook: a skill-load turn
|
|
3
|
+
* triggers `maybeMirrorSkill`, which content-hashes the skill's markdown and
|
|
4
|
+
* uploads ONLY on change. Follower semantics — files canonical, the mirror
|
|
5
|
+
* shadows "last used state." Best-effort end to end: a mirror failure never
|
|
6
|
+
* touches the turn.
|
|
7
|
+
*
|
|
8
|
+
* Local freshness state (`~/.greprag/state/skill-mirror.json`) remembers the
|
|
9
|
+
* last-mirrored hash per skill so an unchanged skill costs one hash pass and
|
|
10
|
+
* ZERO network. Markdown only, v1 — SKILL.md + docs/**\/*.md; script-bearing
|
|
11
|
+
* assets stay file-bound (see the spec's named gaps). */
|
|
12
|
+
export interface SkillFile {
|
|
13
|
+
path: string;
|
|
14
|
+
content: string;
|
|
15
|
+
}
|
|
16
|
+
/** Collect the skill's markdown: SKILL.md (required) + docs/**\/*.md, capped.
|
|
17
|
+
* Returns null when the dir has no SKILL.md. Never throws. */
|
|
18
|
+
export declare function collectSkillFiles(skillDir: string): SkillFile[] | null;
|
|
19
|
+
/** Deterministic content hash over path+content pairs. PURE — unit-tested. */
|
|
20
|
+
export declare function computeMirrorHash(files: SkillFile[]): string;
|
|
21
|
+
interface MirrorState {
|
|
22
|
+
skills: Record<string, {
|
|
23
|
+
hash: string;
|
|
24
|
+
mirroredAt: string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export declare function readMirrorState(): MirrorState;
|
|
28
|
+
export declare function writeMirrorState(state: MirrorState): void;
|
|
29
|
+
export type MirrorOutcome = 'mirrored' | 'fresh' | 'skipped';
|
|
30
|
+
/** Mirror one skill if its content changed since the last mirror. Never throws. */
|
|
31
|
+
export declare function maybeMirrorSkill(params: {
|
|
32
|
+
skill: string;
|
|
33
|
+
cwd: string;
|
|
34
|
+
apiUrl: string;
|
|
35
|
+
apiKey: string;
|
|
36
|
+
}): Promise<MirrorOutcome>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Skill-mirror client — the Tier-3 mirror's upload half
|
|
3
|
+
* (docs/load-system.md §Tier 3). Runs inside the Stop hook: a skill-load turn
|
|
4
|
+
* triggers `maybeMirrorSkill`, which content-hashes the skill's markdown and
|
|
5
|
+
* uploads ONLY on change. Follower semantics — files canonical, the mirror
|
|
6
|
+
* shadows "last used state." Best-effort end to end: a mirror failure never
|
|
7
|
+
* touches the turn.
|
|
8
|
+
*
|
|
9
|
+
* Local freshness state (`~/.greprag/state/skill-mirror.json`) remembers the
|
|
10
|
+
* last-mirrored hash per skill so an unchanged skill costs one hash pass and
|
|
11
|
+
* ZERO network. Markdown only, v1 — SKILL.md + docs/**\/*.md; script-bearing
|
|
12
|
+
* assets stay file-bound (see the spec's named gaps). */
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.collectSkillFiles = collectSkillFiles;
|
|
48
|
+
exports.computeMirrorHash = computeMirrorHash;
|
|
49
|
+
exports.readMirrorState = readMirrorState;
|
|
50
|
+
exports.writeMirrorState = writeMirrorState;
|
|
51
|
+
exports.maybeMirrorSkill = maybeMirrorSkill;
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
const path = __importStar(require("path"));
|
|
54
|
+
const crypto = __importStar(require("crypto"));
|
|
55
|
+
const skill_landing_1 = require("./skill-landing");
|
|
56
|
+
/** Mirrors the server's caps (SKILL_MIRROR_* in @greprag/core — the CLI is
|
|
57
|
+
* core-free, so the numbers are restated; the server re-validates anyway). */
|
|
58
|
+
const MAX_FILES = 20;
|
|
59
|
+
const MAX_FILE_CHARS = 100_000;
|
|
60
|
+
/** Collect the skill's markdown: SKILL.md (required) + docs/**\/*.md, capped.
|
|
61
|
+
* Returns null when the dir has no SKILL.md. Never throws. */
|
|
62
|
+
function collectSkillFiles(skillDir) {
|
|
63
|
+
try {
|
|
64
|
+
const files = [];
|
|
65
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
66
|
+
let main;
|
|
67
|
+
try {
|
|
68
|
+
main = fs.readFileSync(skillMd, 'utf-8');
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (main.length > MAX_FILE_CHARS)
|
|
74
|
+
return null; // a >100KB SKILL.md is not a mirror candidate
|
|
75
|
+
files.push({ path: 'SKILL.md', content: main });
|
|
76
|
+
const docsDir = path.join(skillDir, 'docs');
|
|
77
|
+
const walk = (dir, rel) => {
|
|
78
|
+
let entries;
|
|
79
|
+
try {
|
|
80
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
86
|
+
if (files.length >= MAX_FILES)
|
|
87
|
+
return;
|
|
88
|
+
const abs = path.join(dir, e.name);
|
|
89
|
+
const relPath = `${rel}/${e.name}`;
|
|
90
|
+
if (e.isDirectory()) {
|
|
91
|
+
walk(abs, relPath);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!e.name.toLowerCase().endsWith('.md'))
|
|
95
|
+
continue;
|
|
96
|
+
try {
|
|
97
|
+
const content = fs.readFileSync(abs, 'utf-8');
|
|
98
|
+
if (content.length <= MAX_FILE_CHARS)
|
|
99
|
+
files.push({ path: relPath, content });
|
|
100
|
+
}
|
|
101
|
+
catch { /* unreadable — skip */ }
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
walk(docsDir, 'docs');
|
|
105
|
+
return files;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Deterministic content hash over path+content pairs. PURE — unit-tested. */
|
|
112
|
+
function computeMirrorHash(files) {
|
|
113
|
+
const h = crypto.createHash('sha256');
|
|
114
|
+
for (const f of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
115
|
+
h.update(f.path).update('\0').update(f.content).update('\0');
|
|
116
|
+
}
|
|
117
|
+
return h.digest('hex');
|
|
118
|
+
}
|
|
119
|
+
function statePath() {
|
|
120
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
121
|
+
return path.join(home, '.greprag', 'state', 'skill-mirror.json');
|
|
122
|
+
}
|
|
123
|
+
function readMirrorState() {
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(fs.readFileSync(statePath(), 'utf-8'));
|
|
126
|
+
if (parsed && typeof parsed.skills === 'object' && parsed.skills) {
|
|
127
|
+
return { skills: parsed.skills };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch { /* missing/unreadable → empty */ }
|
|
131
|
+
return { skills: {} };
|
|
132
|
+
}
|
|
133
|
+
function writeMirrorState(state) {
|
|
134
|
+
try {
|
|
135
|
+
const file = statePath();
|
|
136
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
137
|
+
fs.writeFileSync(file, JSON.stringify(state, null, 2) + '\n');
|
|
138
|
+
}
|
|
139
|
+
catch { /* best-effort — worst case is one redundant upload next use */ }
|
|
140
|
+
}
|
|
141
|
+
/** Mirror one skill if its content changed since the last mirror. Never throws. */
|
|
142
|
+
async function maybeMirrorSkill(params) {
|
|
143
|
+
try {
|
|
144
|
+
if (!/^[A-Za-z0-9._-]{1,64}$/.test(params.skill))
|
|
145
|
+
return 'skipped';
|
|
146
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
147
|
+
const dir = (0, skill_landing_1.resolveSkillDir)(params.skill, params.cwd, homeDir);
|
|
148
|
+
if (!dir)
|
|
149
|
+
return 'skipped';
|
|
150
|
+
const files = collectSkillFiles(dir);
|
|
151
|
+
if (!files)
|
|
152
|
+
return 'skipped';
|
|
153
|
+
const hash = computeMirrorHash(files);
|
|
154
|
+
const state = readMirrorState();
|
|
155
|
+
if (state.skills[params.skill]?.hash === hash)
|
|
156
|
+
return 'fresh';
|
|
157
|
+
const res = await fetch(`${params.apiUrl}/v1/skillmirror/${encodeURIComponent(params.skill)}`, {
|
|
158
|
+
method: 'POST',
|
|
159
|
+
headers: { 'Authorization': `Bearer ${params.apiKey}`, 'Content-Type': 'application/json' },
|
|
160
|
+
body: JSON.stringify({ files, contentHash: hash }),
|
|
161
|
+
});
|
|
162
|
+
if (!res.ok)
|
|
163
|
+
return 'skipped';
|
|
164
|
+
state.skills[params.skill] = { hash, mirroredAt: new Date().toISOString() };
|
|
165
|
+
writeMirrorState(state);
|
|
166
|
+
return 'mirrored';
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return 'skipped';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=skill-mirror-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-mirror-client.js","sourceRoot":"","sources":["../src/skill-mirror-client.ts"],"names":[],"mappings":"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"}
|