greprag 5.83.2 → 5.84.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/app-model.js +1 -1
- package/dist/commands/delivery-reminder.js +1 -1
- package/dist/commands/discord.js +12 -61
- package/dist/commands/inbox-watch.js +0 -13
- package/dist/commands/load.js +4 -2
- package/dist/commands/reminder-registry.js +1 -8
- package/dist/commands/session.js +2 -2
- package/dist/commands/skill-mirror-reminder.js +0 -1
- package/dist/commands/skill.js +241 -24
- package/dist/hook.js +2 -1
- package/dist/index.js +14 -147
- package/dist/native-skill-mirror.js +9 -6
- package/dist/opencode-plugin.bundle.js +10 -8
- package/dist/reminder-injector.js +1 -1
- package/dist/skill-mirror-client.js +29 -0
- package/dist/skill-staleness.js +2 -2
- package/package.json +1 -1
- package/skill/commander/SKILL.md +10 -12
- package/skill/greprag/SKILL.md +1 -1
- package/skill/greprag/docs/discord-handoff.md +6 -30
- package/skill/mechanic/docs/skill-fix-conventions.md +1 -1
- package/skill/templates/chip-spawn.md +6 -2
- package/skill/templates/delivery.md +16 -0
- package/skill/templates/skill-change.md +3 -1
- package/dist/commands/sms.js +0 -215
|
@@ -96,6 +96,22 @@ again. Never rebase a shared default branch. A busy merge lock means retry
|
|
|
96
96
|
after its holder finishes — never bypass it, and never take over someone
|
|
97
97
|
else's in-progress merge.
|
|
98
98
|
|
|
99
|
+
### Another session's branch is rebased by that session
|
|
100
|
+
|
|
101
|
+
Step 2 happens in the checkout of whoever owns the branch, because only that
|
|
102
|
+
session can edit there and so only it can resolve a conflict. A chip rebases
|
|
103
|
+
onto its merge target's tip and retests before it reports, so its parent lands
|
|
104
|
+
it with steps 3 to 5 alone. Never run `git -C <their worktree> rebase`: the
|
|
105
|
+
write guard refuses your edits there, so the first conflict leaves you
|
|
106
|
+
aborting, or leaves a half-finished rebase in someone else's checkout. If the
|
|
107
|
+
fast-forward is refused because the tip moved, free the lock and send the
|
|
108
|
+
branch back to its owner to rebase and retest. A chip that already closed left
|
|
109
|
+
no worktree behind, so rebase its branch in a checkout you can edit.
|
|
110
|
+
|
|
111
|
+
Field trigger (2026-10-06): a parent landing chip branches with
|
|
112
|
+
`git -C <chip-worktree> rebase main` hit the same ADR conflict twice and could
|
|
113
|
+
not resolve it either time.
|
|
114
|
+
|
|
99
115
|
This lock is a short Git critical section. It is not a delivery lease, and it
|
|
100
116
|
is not peer-acknowledgement polling.
|
|
101
117
|
|
|
@@ -40,7 +40,9 @@ Explicitly requested creation, porting, or redesign is authorized work. The prop
|
|
|
40
40
|
- Bundled GrepRAG skill: edit `packages/cli/skill/<name>/`, never the installed artifact.
|
|
41
41
|
- Mirrored/local skill: edit its canonical source, not the generated Codex/Claude/OpenCode adapter.
|
|
42
42
|
- Unknown source: stop and identify the canonical source before editing.
|
|
43
|
-
- Codex/non-interactive harness: do not launch an editor. Use `greprag skill mirror export <skill> --to <dir>`, patch the exported Markdown files with file edits, then `greprag skill mirror apply <dir> --skill <skill> --expected-hash <exported-hash
|
|
43
|
+
- Codex/non-interactive harness: do not launch an editor. Use `greprag skill mirror export <skill> --to <dir>`, patch the exported Markdown files with file edits, then `greprag skill mirror apply <dir> --skill <skill> --expected-hash <exported-hash> --reason "<why>"`. If using `greprag skill edit` as the export helper, pass `--no-open`.
|
|
44
|
+
- **ABOUT TO WRITE A MIRRORED SKILL? STOP - PASS `--reason "<one line>"`.** `skill edit`, `skill mirror apply`, `snapshot promote` and `skill revert` refuse without it. GrepRAG keeps every revision's bytes with that reason, so write the learning the edit captures, not "update skill".
|
|
45
|
+
- History: `greprag skill history <skill>` lists revisions (date, author, reason, changes); `greprag skill diff <skill> <revA> [<revB>]` shows a unified diff; `greprag skill revert <skill> --to <rev> --reason "<why>" --expected-hash <current-hash>` makes an old revision current as a new one. Add the adapter's `--skill-id` to each.
|
|
44
46
|
|
|
45
47
|
## Skill-Refresh Chips
|
|
46
48
|
|
package/dist/commands/sms.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/** greprag sms <pair|unpair|me> — Front Desk SMS rail CLI.
|
|
3
|
-
*
|
|
4
|
-
* pair POSTs /v1/sms/pair with the current project anchor; prints the
|
|
5
|
-
* 6-char code + the greprag number to text it to.
|
|
6
|
-
* unpair DELETEs /v1/sms/pair (optionally for one --phone).
|
|
7
|
-
* me GETs /v1/sms/me — the tenant's bound phones.
|
|
8
|
-
*
|
|
9
|
-
* Self-contained HTTP client (does not import @greprag/core), mirroring
|
|
10
|
-
* commands/email.ts. See docs/receptionist-sms-mvp.md.
|
|
11
|
-
*/
|
|
12
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
-
}
|
|
18
|
-
Object.defineProperty(o, k2, desc);
|
|
19
|
-
}) : (function(o, m, k, k2) {
|
|
20
|
-
if (k2 === undefined) k2 = k;
|
|
21
|
-
o[k2] = m[k];
|
|
22
|
-
}));
|
|
23
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
-
}) : function(o, v) {
|
|
26
|
-
o["default"] = v;
|
|
27
|
-
});
|
|
28
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
-
var ownKeys = function(o) {
|
|
30
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
-
var ar = [];
|
|
32
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
-
return ar;
|
|
34
|
-
};
|
|
35
|
-
return ownKeys(o);
|
|
36
|
-
};
|
|
37
|
-
return function (mod) {
|
|
38
|
-
if (mod && mod.__esModule) return mod;
|
|
39
|
-
var result = {};
|
|
40
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
-
__setModuleDefault(result, mod);
|
|
42
|
-
return result;
|
|
43
|
-
};
|
|
44
|
-
})();
|
|
45
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.runSms = runSms;
|
|
47
|
-
const fs = __importStar(require("fs"));
|
|
48
|
-
const path = __importStar(require("path"));
|
|
49
|
-
const project_anchor_1 = require("../project-anchor");
|
|
50
|
-
const API_URL_DEFAULT = 'https://api.greprag.com';
|
|
51
|
-
function loadEnvFile(filePath) {
|
|
52
|
-
try {
|
|
53
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
54
|
-
for (const line of content.split('\n')) {
|
|
55
|
-
const trimmed = line.trim();
|
|
56
|
-
if (!trimmed || trimmed.startsWith('#'))
|
|
57
|
-
continue;
|
|
58
|
-
const eqIdx = trimmed.indexOf('=');
|
|
59
|
-
if (eqIdx < 1)
|
|
60
|
-
continue;
|
|
61
|
-
const key = trimmed.slice(0, eqIdx).trim();
|
|
62
|
-
let value = trimmed.slice(eqIdx + 1).trim();
|
|
63
|
-
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
64
|
-
(value.startsWith("'") && value.endsWith("'"))) {
|
|
65
|
-
value = value.slice(1, -1);
|
|
66
|
-
}
|
|
67
|
-
if (!process.env[key])
|
|
68
|
-
process.env[key] = value;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch { /* file missing — fine */ }
|
|
72
|
-
}
|
|
73
|
-
function getConfig() {
|
|
74
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
75
|
-
if (homeDir)
|
|
76
|
-
loadEnvFile(path.join(homeDir, '.greprag', '.env'));
|
|
77
|
-
if (!process.env.GREPRAG_API_KEY)
|
|
78
|
-
loadEnvFile(path.join(process.cwd(), '.env'));
|
|
79
|
-
return {
|
|
80
|
-
apiUrl: process.env.GREPRAG_API_URL || API_URL_DEFAULT,
|
|
81
|
-
apiKey: process.env.GREPRAG_API_KEY || '',
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function getFlag(args, flag) {
|
|
85
|
-
const idx = args.indexOf(flag);
|
|
86
|
-
if (idx === -1 || idx + 1 >= args.length)
|
|
87
|
-
return undefined;
|
|
88
|
-
return args[idx + 1];
|
|
89
|
-
}
|
|
90
|
-
async function callPair(cfg, phone, projectId) {
|
|
91
|
-
const payload = { phone };
|
|
92
|
-
if (projectId)
|
|
93
|
-
payload.project_id = projectId;
|
|
94
|
-
const res = await fetch(`${cfg.apiUrl}/v1/sms/pair`, {
|
|
95
|
-
method: 'POST',
|
|
96
|
-
headers: { 'Authorization': `Bearer ${cfg.apiKey}`, 'Content-Type': 'application/json' },
|
|
97
|
-
body: JSON.stringify(payload),
|
|
98
|
-
});
|
|
99
|
-
return res.json();
|
|
100
|
-
}
|
|
101
|
-
async function callUnpair(cfg, phone) {
|
|
102
|
-
const res = await fetch(`${cfg.apiUrl}/v1/sms/pair`, {
|
|
103
|
-
method: 'DELETE',
|
|
104
|
-
headers: { 'Authorization': `Bearer ${cfg.apiKey}`, 'Content-Type': 'application/json' },
|
|
105
|
-
body: JSON.stringify(phone ? { phone } : {}),
|
|
106
|
-
});
|
|
107
|
-
return res.json();
|
|
108
|
-
}
|
|
109
|
-
async function callMe(cfg) {
|
|
110
|
-
const res = await fetch(`${cfg.apiUrl}/v1/sms/me`, {
|
|
111
|
-
method: 'GET',
|
|
112
|
-
headers: { 'Authorization': `Bearer ${cfg.apiKey}` },
|
|
113
|
-
});
|
|
114
|
-
return res.json();
|
|
115
|
-
}
|
|
116
|
-
const SMS_HELP = `
|
|
117
|
-
greprag sms — Front Desk SMS rail. Reach a cheap receptionist by text to triage
|
|
118
|
-
your inbox and route messages to your sessions from your phone.
|
|
119
|
-
|
|
120
|
-
Subcommands:
|
|
121
|
-
greprag sms pair --phone <e164> Generate a 15-min code BOUND to that
|
|
122
|
-
phone; text it (or "PAIR <code>") FROM
|
|
123
|
-
that exact number to the greprag number
|
|
124
|
-
to bind it. --phone is required and must
|
|
125
|
-
be full E.164 (e.g. +15551234567) — the
|
|
126
|
-
code only binds when claimed from it. The
|
|
127
|
-
current directory's project anchor becomes
|
|
128
|
-
your home project.
|
|
129
|
-
greprag sms unpair [--phone <e164>] Unbind one phone (or all phones).
|
|
130
|
-
greprag sms me Show bound phones + the greprag number.
|
|
131
|
-
|
|
132
|
-
Once paired, text the greprag number:
|
|
133
|
-
"what's waiting?" → the receptionist reads your inbox.
|
|
134
|
-
"tell session a1b2c3d4 to ship it" → routes a message to that session.
|
|
135
|
-
`.trim();
|
|
136
|
-
async function runSms(args) {
|
|
137
|
-
const sub = args[0];
|
|
138
|
-
if (!sub || sub === 'help' || sub === '--help' || sub === '-h') {
|
|
139
|
-
console.log(SMS_HELP);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const cfg = getConfig();
|
|
143
|
-
if (!cfg.apiKey) {
|
|
144
|
-
console.error('Not configured. Run: greprag init');
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
if (sub === 'pair') {
|
|
148
|
-
// --phone is required: the code is bound to it, and only a claim texted from
|
|
149
|
-
// that exact number succeeds (the identity guard against brute-force binds).
|
|
150
|
-
const phone = getFlag(args, '--phone');
|
|
151
|
-
if (!phone) {
|
|
152
|
-
console.error('Error: --phone <e164> is required (the number you will text from, e.g. +15551234567).');
|
|
153
|
-
process.exit(1);
|
|
154
|
-
}
|
|
155
|
-
// The home/default project is the current directory's anchor. The API keys
|
|
156
|
-
// pairing by project_id; a `--project <name>` would need a server-side name
|
|
157
|
-
// lookup, so for the MVP the anchor is the source of truth (run pair from
|
|
158
|
-
// the project dir you want as home, or leave a message naming any project).
|
|
159
|
-
const anchor = (0, project_anchor_1.readAnchor)(process.cwd());
|
|
160
|
-
const projectId = anchor.projectId || null;
|
|
161
|
-
const result = await callPair(cfg, phone, projectId);
|
|
162
|
-
if (!result.ok) {
|
|
163
|
-
console.error(`Error: ${result.error}`);
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
console.log(`Pairing code: ${result.code}`);
|
|
167
|
-
if (result.bound_phone) {
|
|
168
|
-
console.log(`Bound to ${result.bound_phone} — text the code FROM that number only.`);
|
|
169
|
-
}
|
|
170
|
-
if (result.sms_number) {
|
|
171
|
-
console.log(`Text it to the greprag number: ${result.sms_number}`);
|
|
172
|
-
console.log(` (send "${result.code}" or "PAIR ${result.code}")`);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
console.log(`Text "${result.code}" (or "PAIR ${result.code}") to the greprag number.`);
|
|
176
|
-
console.log(` (number not configured server-side yet — ask the operator)`);
|
|
177
|
-
}
|
|
178
|
-
console.log(`Code expires in ${result.expires_in_minutes} minutes.`);
|
|
179
|
-
if (result.project_name) {
|
|
180
|
-
console.log(`After pairing, your home project is "${result.project_name}".`);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
console.log(`No default project set — name one when you leave a message.`);
|
|
184
|
-
}
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
if (sub === 'unpair') {
|
|
188
|
-
const phone = getFlag(args, '--phone');
|
|
189
|
-
const result = await callUnpair(cfg, phone);
|
|
190
|
-
if (!result.ok) {
|
|
191
|
-
console.error(`Error: ${result.error}`);
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
console.log(`Unpaired ${result.removed} phone(s).`);
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (sub === 'me') {
|
|
198
|
-
const result = await callMe(cfg);
|
|
199
|
-
if (!result.ok) {
|
|
200
|
-
console.error(`Error: ${result.error}`);
|
|
201
|
-
process.exit(1);
|
|
202
|
-
}
|
|
203
|
-
console.log(`greprag number: ${result.sms_number ?? '(not configured)'}`);
|
|
204
|
-
if (!result.paired || !result.phones || result.phones.length === 0) {
|
|
205
|
-
console.log('No phones paired. Run: greprag sms pair');
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
console.log(`Paired phones (${result.phones.length}):`);
|
|
209
|
-
for (const p of result.phones) {
|
|
210
|
-
console.log(` ${p.phone} paired ${p.paired_at} last inbound ${p.last_seen_inbound_at ?? '(never)'}`);
|
|
211
|
-
}
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
console.log(SMS_HELP);
|
|
215
|
-
}
|