greprag 5.84.0 → 5.85.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.
@@ -74,29 +74,20 @@ async function trySyncNativeSkillMirror(apiKey, platform, cwd = process.cwd()) {
74
74
  return `Native skill mirror unavailable; existing skills preserved (${message})`;
75
75
  }
76
76
  }
77
- async function tryBootstrapAgentDoctrine(apiKey, harness) {
77
+ /** Render the Codex/OpenCode AGENTS.md files from ~/.claude/CLAUDE.md (the git
78
+ * source) and say what happened. adr: adr/skill-ownership-git.md */
79
+ function renderInstructionsSummary() {
78
80
  try {
79
- return await (0, agents_1.bootstrapAgentDoctrine)(apiKey, harness);
81
+ const results = (0, agents_1.renderGlobalInstructions)();
82
+ if (results.every(r => r.status === 'no-source'))
83
+ return 'AGENTS.md render: no ~/.claude/CLAUDE.md yet';
84
+ const written = results.filter(r => r.status === 'written').length;
85
+ return written ? `AGENTS.md render: ${written} file(s) rewritten from ~/.claude/CLAUDE.md` : 'AGENTS.md render: current';
80
86
  }
81
87
  catch (error) {
82
- const message = error instanceof Error ? error.message : String(error);
83
- console.warn(` GrepRAG Instructions materialization skipped: ${message}`);
84
- return null;
88
+ return `AGENTS.md render skipped: ${error instanceof Error ? error.message : String(error)}`;
85
89
  }
86
90
  }
87
- function doctrineBootstrapSummary(result) {
88
- if (!result)
89
- return 'GrepRAG Instructions: materialization unavailable; existing files preserved';
90
- if (result.canonicalScopes.length === 0)
91
- return 'GrepRAG Instructions: no canonical scopes adopted yet';
92
- const state = result.changedFollowers > 0
93
- ? `${result.changedFollowers} follower(s) materialized`
94
- : `${result.currentFollowers} follower(s) already current`;
95
- const blocked = result.blockedFollowers > 0
96
- ? `; ${result.blockedFollowers} existing follower(s) preserved (run greprag instructions push explicitly)`
97
- : '';
98
- return `GrepRAG Instructions (${result.canonicalScopes.join(' + ')}): ${state}${blocked}`;
99
- }
100
91
  function hasEnvPrefix(prefix) {
101
92
  return Object.keys(process.env).some(k => k.startsWith(prefix));
102
93
  }
@@ -344,13 +335,11 @@ async function runInit(opts) {
344
335
  // chip-spawn POINTER announce names the trigger + the command). One less
345
336
  // install-time file write, and it works in every project, not just where the
346
337
  // file happened to be installed.
347
- // Step 7: Materialize canonical doctrine for Claude. Once global canon
348
- // exists, it owns ~/.claude/CLAUDE.md; running the legacy direct patch after
349
- // sync would immediately diverge the materialized follower. Pre-adoption
350
- // tenants retain the old patch path unchanged.
351
- const doctrine = await tryBootstrapAgentDoctrine(apiKey, 'claude-code');
352
- changes.push(doctrineBootstrapSummary(doctrine));
353
- if (!doctrine?.canonicalScopes.includes('global')) {
338
+ // Step 7: ~/.claude/CLAUDE.md. A file committed in git is its owner's to
339
+ // edit, so init leaves it alone; an untracked one gets the greprag CLI
340
+ // section as before. adr: adr/skill-ownership-git.md
341
+ changes.push(renderInstructionsSummary());
342
+ if ((0, agents_1.committedInstructionSource)() === null) {
354
343
  const claudeMdPatched = patchGlobalClaudeMd();
355
344
  changes.push(claudeMdPatched
356
345
  ? 'Patched ~/.claude/CLAUDE.md greprag CLI section'
@@ -525,13 +514,13 @@ async function runOpenCodeInit(opts) {
525
514
  console.warn(' Plugin bundle not found (build issue) — run `npm run build` in packages/cli and retry');
526
515
  }
527
516
  envChanges.push(await trySyncNativeSkillMirror(apiKey, 'opencode'));
528
- const doctrine = await tryBootstrapAgentDoctrine(apiKey, 'opencode');
517
+ const instructionsSummary = renderInstructionsSummary();
529
518
  // Summary
530
519
  console.log('\n Setup complete!\n');
531
520
  for (const c of envChanges)
532
521
  console.log(` - ${c}`);
533
522
  console.log(` - Project anchor: ${anchor.anchorPath} (source: ${anchor.source})`);
534
- console.log(` - ${doctrineBootstrapSummary(doctrine)}`);
523
+ console.log(` - ${instructionsSummary}`);
535
524
  if (pluginInstalled)
536
525
  console.log(` - Plugin: ${pluginMain}`);
537
526
  console.log(` - Shared env: ${getGrepragEnvPath()}`);
@@ -583,8 +572,7 @@ async function runCodexInit(opts) {
583
572
  if (codexSkill)
584
573
  changes.push(`Skill: installed → ${codexSkill}`);
585
574
  changes.push(await trySyncNativeSkillMirror(apiKey, 'codex'));
586
- const doctrine = await tryBootstrapAgentDoctrine(apiKey, 'codex');
587
- changes.push(doctrineBootstrapSummary(doctrine));
575
+ changes.push(renderInstructionsSummary());
588
576
  try {
589
577
  const res = await fetch(`${API_URL}/v1/inbox/projects/register`, {
590
578
  method: 'POST',
@@ -60,7 +60,6 @@ const os = __importStar(require("os"));
60
60
  const harness_1 = require("../harness");
61
61
  const skill_activation_manifest_1 = require("../skill-activation-manifest");
62
62
  const project_anchor_1 = require("../project-anchor");
63
- const skill_landing_1 = require("../skill-landing");
64
63
  const skill_mirror_files_1 = require("../skill-mirror-files");
65
64
  const proc_1 = require("../proc");
66
65
  const skill_staleness_1 = require("../skill-staleness");
@@ -91,7 +90,7 @@ const LIBRARY = {
91
90
  },
92
91
  'skill-change': {
93
92
  files: ['skill/templates/skill-change.md'],
94
- purpose: 'Internal bundled schema for safely updating a skill after a run: when to edit, Convention A/B shapes, and when to propose instead.',
93
+ purpose: 'How to change a skill after a run: edit its git folder and commit (GrepRAG only mirrors it), Convention A/B shapes, and when to propose instead.',
95
94
  },
96
95
  mechanic: {
97
96
  files: ['skill/mechanic/SKILL.md', 'skill/mechanic/docs/skill-fix-conventions.md'],
@@ -109,10 +108,10 @@ const LIBRARY = {
109
108
  files: ['skill/templates/chip-leader-opencode.md'],
110
109
  purpose: 'Plan a MULTI-CHIP mission for opencode (integration branch, seams, merge order). Loaded from chip-bootloader when ≥2 chips are needed.',
111
110
  },
112
- // adr: adr/prompt-audit-canon.md — the audit lands through `instructions pull --push`, never a follower edit.
111
+ // adr: adr/prompt-audit-canon.md — the audit lands as an edit to ~/.claude/CLAUDE.md in git, never to a rendered AGENTS.md.
113
112
  'prompt-audit': {
114
113
  files: ['skill/templates/prompt-audit.md'],
115
- purpose: 'Audit canonical CLAUDE.md/AGENTS.md instructions for dated-model cruft (shipped rubric) and land accepted edits through `instructions pull --push`, never a follower edit.',
114
+ purpose: 'Audit CLAUDE.md instructions for dated-model cruft (shipped rubric) and land accepted edits in ~/.claude/CLAUDE.md (git); the AGENTS.md files are rendered from it.',
116
115
  },
117
116
  };
118
117
  /** Absolute path to a payload shipped in the package. */
@@ -189,7 +188,7 @@ async function printCatalog() {
189
188
  for (const name of names) {
190
189
  console.log(` ${name.padEnd(width)} ${LIBRARY[name].purpose}`);
191
190
  }
192
- console.log(` ${'instructions'.padEnd(width)} Canonical global + repo GrepRAG Instructions; CLAUDE.md/AGENTS.md are rendered followers.`);
191
+ console.log(` ${'instructions'.padEnd(width)} Read-only copy of ~/.claude/CLAUDE.md (git is the source; AGENTS.md files are rendered from it).`);
193
192
  console.log(` ${'agents'.padEnd(width)} Deprecated alias for instructions.`);
194
193
  // Tier-3 section: the operator's own skills, auto-mirrored from use.
195
194
  const data = await mirrorGet('/v1/skillmirror');
@@ -201,20 +200,18 @@ async function printCatalog() {
201
200
  // A mirrored skill with no native adapter on this harness never reaches the
202
201
  // harness's own skill list — the agent can only reach it through this
203
202
  // catalog. Mark the gap here and name the command that closes it.
204
- // A hand-kept copy does reach that list, but the harness runs the copy and
205
- // never sees canon move on, so it is marked too (with `~`).
206
203
  const platform = (0, harness_1.inferCurrentHarness)() || '';
207
204
  const native = platform
208
205
  ? (0, skill_activation_manifest_1.readNativeSkillNames)({ platform, cwd: process.cwd(), homeDir: os.homedir() })
209
206
  : new Map();
210
- const { missing, localCopies } = (0, skill_activation_manifest_1.nativeAdapterGap)(platform, skills, native);
207
+ const { missing } = (0, skill_activation_manifest_1.nativeAdapterGap)(platform, skills, native);
211
208
  const w = Math.max(...skills.map((s) => (s.skillName || '').length), 8);
212
- console.log('\nYour mirrored skills (auto-fresh from use — work on any machine/harness):\n');
209
+ console.log('\nYour mirrored skills (copied from git commits — work on any machine/harness):\n');
213
210
  for (const s of skills) {
214
211
  if (!s.skillName)
215
212
  continue;
216
213
  const scope = s.scope === 'project' && s.projectId ? ` [project:${s.projectId.slice(0, 8)}]` : '';
217
- const gap = missing.includes(s.skillName) ? ' *' : localCopies.includes(s.skillName) ? ' ~' : '';
214
+ const gap = missing.includes(s.skillName) ? ' *' : '';
218
215
  console.log(` ${(s.skillName + scope + gap).padEnd(w + 20)} ${(s.description || '').slice(0, 110)}`);
219
216
  }
220
217
  const installCommand = (0, skill_activation_manifest_1.nativeAdapterInstallCommand)(platform, missing);
@@ -223,13 +220,6 @@ async function printCatalog() {
223
220
  console.log(' in this harness\'s own skill list. Install the adapters with:\n');
224
221
  console.log(` ${installCommand}\n`);
225
222
  }
226
- const cutoverCommand = (0, skill_activation_manifest_1.localCopyCutoverCommand)(platform, localCopies);
227
- if (cutoverCommand) {
228
- console.log(`\n ~ ${localCopies.length} skill(s) run from a hand-kept copy in ${platform}, not an adapter — the harness`);
229
- console.log(' keeps running that copy when the mirrored skill changes. Replacing a copy is a per-skill');
230
- console.log(' call; its SKILL.md is backed up first:\n');
231
- console.log(` ${cutoverCommand}\n`);
232
- }
233
223
  }
234
224
  console.log('\n greprag load <name> print the full entry / mirrored skill');
235
225
  console.log(' greprag load /<name> print a user-named slash skill');
@@ -451,13 +441,13 @@ async function printMirroredSkill(name, args) {
451
441
  // adr: adr/skill-adapter-never-canon.md
452
442
  if ((0, skill_mirror_files_1.isGeneratedSkillAdapter)(file.content)) {
453
443
  const identityArg = args.skillId ? ` --skill-id ${args.skillId}` : '';
454
- console.error(`Mirrored skill "${name}" has no canonical body — the mirror is holding the generated adapter.\n` +
455
- `Refusing to serve it: the adapter is the launcher that sent you here, not the skill.\n\n` +
456
- `Restore the real body from an earlier revision or the pre-adoption snapshot:\n` +
444
+ console.error(`Mirrored skill "${name}" has no body — the mirror is holding a generated launcher.\n` +
445
+ `Refusing to serve it: the launcher is what sent you here, not the skill.\n\n` +
446
+ `The skill lives in git. Restore SKILL.md in its folder (~/.claude/skills/${name}/ in the dotclaude repo, ` +
447
+ `or <repo>/.claude/skills/${name}/), commit, then run \`greprag skill mirror sync\`. Earlier mirrored ` +
448
+ `bytes stay readable:\n` +
457
449
  ` greprag skill history ${name}${identityArg}\n` +
458
- ` greprag skill revert ${name} --to <rev>${identityArg} --reason "<why>" --expected-hash <current-hash>\n` +
459
- ` greprag skill mirror snapshot list ${name}${identityArg}\n` +
460
- ` greprag skill mirror snapshot promote ${name} --name <snapshot>${identityArg} --expected-hash <current-hash> --reason "<why>"\n`);
450
+ ` greprag skill mirror snapshot restore ${name} --name <snapshot>${identityArg} --to <dir>\n`);
461
451
  process.exitCode = 1;
462
452
  return true;
463
453
  }
@@ -473,18 +463,6 @@ async function printMirroredSkill(name, args) {
473
463
  }
474
464
  process.stdout.write(file.content.endsWith('\n') ? file.content : file.content + '\n');
475
465
  if (!args.docPath) {
476
- // A mirror-managed skill's SKILL.md is a generated adapter, so the Skill
477
- // Learning Loop cannot land a fuse there without fighting the mirror for
478
- // the file. Its pending gains ride the load payload instead — this is the
479
- // moment the agent reads the skill. adr: adr/skill-fuse-delivery.md
480
- try {
481
- const pending = await mirrorGet('/v1/skillgain/pending');
482
- const gains = pending?.gains || [];
483
- const block = (0, skill_landing_1.buildLoadFuseBlock)(name, gains);
484
- if (block)
485
- process.stdout.write(block);
486
- }
487
- catch { /* a gain that fails to surface must never break the skill load */ }
488
466
  await printStateDocHints(name, file.content);
489
467
  const companions = files.map((f) => f.path).filter((p) => p !== 'SKILL.md');
490
468
  if (companions.length > 0) {
@@ -506,7 +484,7 @@ async function runLoad(args) {
506
484
  if (name === 'instructions' || name === 'agents') {
507
485
  if (await printGrepRagInstructions(args.slice(1)))
508
486
  return;
509
- console.error('No canonical GrepRAG Instructions found. Seed them with `greprag instructions adopt <CLAUDE.md|AGENTS.md>`.');
487
+ console.error('No mirrored instructions yet. `greprag instructions render` mirrors the committed ~/.claude/CLAUDE.md.');
510
488
  process.exit(1);
511
489
  }
512
490
  // An explicit --skill-id names one mirrored skill, so it outranks a bundled
@@ -254,7 +254,7 @@ async function tableCmd(args) {
254
254
  console.log(` reconciled: ${u.lastReconcile ? u.lastReconcile.slice(0, 10) : 'never'}`);
255
255
  console.log('');
256
256
  }
257
- console.log('Load-canonical GrepRAG Instructions reconcile with `greprag instructions push`; other units use a parity fix chip.');
257
+ console.log('Instruction files reconcile with `greprag instructions render`; other units use a parity fix chip.');
258
258
  }
259
259
  // ---------- Dispatch ------------------------------------------------------------
260
260
  async function runParity(args) {
@@ -18,28 +18,12 @@ function renderEntry(skill) {
18
18
  function buildSkillMirrorAnnounce(m, platform) {
19
19
  if (!m || m.count <= 0)
20
20
  return null;
21
- // A hand-kept copy is in the native skill list, so it is not in the trigger
22
- // list below, but the harness runs that copy and never sees canon move on.
23
- // Name each one; replacing a live copy is the user's call, skill by skill.
24
- const cutoverCommand = (0, skill_activation_manifest_1.localCopyCutoverCommand)(platform || '', m.localCopies);
25
- const copies = m.localCopies.length === 1 ? 'one mirrored skill' : `${m.localCopies.length} mirrored skills`;
26
- const copySection = cutoverCommand ? [
27
- '### Hand-Kept Copies',
28
- `This harness lists ${copies} from a hand-kept copy instead of an adapter, `
29
- + `so it keeps running that copy when the mirrored skill changes: ${m.localCopies.join(', ')}. `
30
- + 'Replacing a copy with its adapter is the user\'s call, one skill at a time (the old SKILL.md is backed up first):',
31
- '',
32
- ` ${cutoverCommand}`,
33
- '',
34
- 'Offer that command when the user asks why a skill behaves out of date, or when you needed one of them this session.',
35
- '',
36
- ] : [];
37
21
  if (m.skills.length === 0) {
38
22
  const line = '[greprag skills: slash skills are available. '
39
23
  + 'When discussing skills with the user, say use/create/update/refresh `/skill`; '
40
24
  + 'keep storage mechanics internal unless diagnosing a failure or the user asks how it works. '
41
25
  + 'Use `greprag load <skill>` to read skill instructions.]';
42
- return [line, '', ...copySection].join('\n').trimEnd();
26
+ return line;
43
27
  }
44
28
  // Mirrored skills with no native package never reach the native skill list.
45
29
  // Name the gap and the one command that closes it, or it stays invisible
@@ -64,7 +48,6 @@ function buildSkillMirrorAnnounce(m, platform) {
64
48
  'When discussing skills with the user, say use/create/update/refresh `/skill`; keep storage mechanics internal unless diagnosing a failure or the user asks how it works.',
65
49
  '',
66
50
  ...gapSection,
67
- ...copySection,
68
51
  '### Trigger Rules',
69
52
  'If the user names a skill (with or without `/`) OR the request clearly matches a skill\'s description below, '
70
53
  + 'you MUST activate that skill for the current turn. Match meaning, not exact keywords.',