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.
package/dist/hook.js CHANGED
@@ -141,8 +141,8 @@ const procedure_shadow_1 = require("./procedure-shadow");
141
141
  const inline_atom_hook_1 = require("./inline-atom-hook");
142
142
  const inline_atom_background_1 = require("./inline-atom-background");
143
143
  const reminder_injector_1 = require("./reminder-injector");
144
- const skill_landing_1 = require("./skill-landing");
145
- const skill_mirror_client_1 = require("./skill-mirror-client");
144
+ const skill_git_ingest_1 = require("./skill-git-ingest");
145
+ const agents_1 = require("./commands/agents");
146
146
  const repodoc_client_1 = require("./repodoc-client");
147
147
  const native_skill_pending_1 = require("./native-skill-pending");
148
148
  const doc_mirror_client_1 = require("./doc-mirror-client");
@@ -851,41 +851,6 @@ async function fetchEnrichmentDown(apiUrl, apiKey) {
851
851
  return null;
852
852
  }
853
853
  }
854
- /** SessionStart pass: the Skill Learning Loop's LANDING leg
855
- * (docs/skill-learning-loop.md — the write-back is CODE, not agent
856
- * voluntarism). Fetch pending gains → auto-land reference-tier into each
857
- * skill's docs/learnings.md → POST landed statuses back → return the report
858
- * for the announce. Undefined on any error → announce silent, gains stay
859
- * pending for the next session start. */
860
- async function fetchAndLandSkillGains(apiUrl, apiKey, anchor, cwd) {
861
- try {
862
- const res = await fetch(`${apiUrl}/v1/skillgain/${anchor.projectId}/pending`, {
863
- headers: { 'Authorization': `Bearer ${apiKey}` },
864
- });
865
- if (!res.ok)
866
- return undefined;
867
- const data = await res.json();
868
- const pending = (data.gains || []).filter(g => g.nodeId && g.skill && g.text);
869
- if (pending.length === 0)
870
- return undefined;
871
- const homeDir = process.env.HOME || process.env.USERPROFILE || '';
872
- const { report, statusUpdates } = (0, skill_landing_1.landPendingGains)(pending, cwd, homeDir, anchor.projectName);
873
- if (statusUpdates.length > 0) {
874
- try {
875
- await fetch(`${apiUrl}/v1/skillgain/${anchor.projectId}/status`, {
876
- method: 'POST',
877
- headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
878
- body: JSON.stringify({ projectName: anchor.projectName, updates: statusUpdates }),
879
- });
880
- }
881
- catch { /* statuses re-sync next start — the stamp keeps lands idempotent */ }
882
- }
883
- return report.landed.length > 0 ? report : undefined;
884
- }
885
- catch {
886
- return undefined;
887
- }
888
- }
889
854
  /** Manifest-liveness policy — mirror of core's assessLiveness threshold (the CLI
890
855
  * is a zero-dep artifact, so the tiny policy is duplicated, like
891
856
  * DOCPTR_ANNOUNCE_LIMIT). A doc must cite ≥3 in-repo paths with ≥60% dead before
@@ -1156,19 +1121,6 @@ async function store(input, source = 'claude-code') {
1156
1121
  }
1157
1122
  catch { /* fail-open — an inline-atom miss never fails the Stop hook */ }
1158
1123
  }
1159
- // Skill mirror (docs/load-system.md Tier 3): a skill-load turn shadows that
1160
- // skill's current markdown into the tenant's load store — upload ONLY on
1161
- // change (local hash state), so an unchanged skill costs zero network.
1162
- // Follower semantics: files stay canonical. Best-effort, never throws.
1163
- if (provenance === 'skill-injection') {
1164
- const mirrorSkill = (0, turn_provenance_1.provenanceHint)(provenance, turn.userPrompt);
1165
- if (mirrorSkill) {
1166
- await (0, skill_mirror_client_1.maybeMirrorSkill)({
1167
- skill: mirrorSkill, cwd, apiUrl: cfg.apiUrl, apiKey: cfg.apiKey,
1168
- sessionId: input.session_id,
1169
- });
1170
- }
1171
- }
1172
1124
  // Repo chunk index (adr/node-identity-port.md): the chunks are DERIVED from a
1173
1125
  // document plus the node graph committed beside it, so they are rebuilt when
1174
1126
  // the document moves rather than when someone remembers to run a push. Same
@@ -1603,10 +1555,9 @@ async function recap(input, mode = 'plain', opts = {}) {
1603
1555
  // Enrichment-health signal (fix c2eb8777) — the live Gemini probe verdict.
1604
1556
  // Null when healthy or unreachable; a positive failure fires the outage announce.
1605
1557
  const enrichmentDownPromise = fetchEnrichmentDown(cfg.apiUrl, cfg.apiKey);
1606
- // Skill Learning Loop landing leg (docs/skill-learning-loop.md): pending
1607
- // gains → auto-land references into learnings docs, hold rule/scope
1608
- // proposals for the announce. Best-effort; undefined → announce silent.
1609
- const skillGainsPromise = fetchAndLandSkillGains(cfg.apiUrl, cfg.apiKey, anchor, cwd);
1558
+ // The Skill Learning Loop no longer lands gains into skill folders: git owns
1559
+ // skills and GrepRAG never edits their content (adr/skill-ownership-git.md).
1560
+ const skillGainsPromise = Promise.resolve(undefined);
1610
1561
  // Tier-3 skill activation manifest (docs/load-system.md): fetch canonical
1611
1562
  // full descriptions, then omit skills this harness already advertises
1612
1563
  // natively. Best-effort; the renderer remains pure. The same roster is what
@@ -1614,6 +1565,20 @@ async function recap(input, mode = 'plain', opts = {}) {
1614
1565
  // extra round trip unless one is stale. adr: adr/skill-bundle-shape.md
1615
1566
  const mirroredSkillsPromise = (async () => {
1616
1567
  try {
1568
+ // Git owns skills: ingest what is committed before reading the roster,
1569
+ // so launchers and the manifest see the committed content. Cheap when
1570
+ // nothing changed (one git ls-tree per source).
1571
+ // adr: adr/skill-ownership-git.md
1572
+ try {
1573
+ const sources = (0, skill_git_ingest_1.gitSkillSources)(cwd);
1574
+ const projectId = sources.find(source => source.scope === 'project')?.projectId;
1575
+ const mirrorHashes = await (0, skill_git_ingest_1.fetchMirrorHashes)(cfg.apiUrl, cfg.apiKey, projectId);
1576
+ await (0, skill_git_ingest_1.ingestCommittedSkills)({
1577
+ apiUrl: cfg.apiUrl, apiKey: cfg.apiKey, sources, mirrorHashes,
1578
+ harness: platform, sessionId: input.session_id,
1579
+ });
1580
+ }
1581
+ catch { /* best effort: the next session start retries */ }
1617
1582
  const params = new URLSearchParams({ scope: 'effective', projectId: anchor.projectId });
1618
1583
  const res = await fetch(`${cfg.apiUrl}/v1/skillmirror?${params.toString()}`, {
1619
1584
  headers: { 'Authorization': `Bearer ${cfg.apiKey}` },
@@ -1636,6 +1601,16 @@ async function recap(input, mode = 'plain', opts = {}) {
1636
1601
  return undefined;
1637
1602
  }
1638
1603
  })();
1604
+ // The Codex/OpenCode AGENTS.md files follow ~/.claude/CLAUDE.md, the git
1605
+ // source, and GrepRAG's read-only copy follows its last commit.
1606
+ // adr: adr/skill-ownership-git.md
1607
+ const instructionsPromise = (async () => {
1608
+ try {
1609
+ (0, agents_1.renderGlobalInstructions)();
1610
+ await (0, agents_1.mirrorCommittedInstructions)({ apiUrl: cfg.apiUrl, apiKey: cfg.apiKey });
1611
+ }
1612
+ catch { /* best effort: the next session start retries */ }
1613
+ })();
1639
1614
  // Equipped-loadouts signal (docs/loadout.md §activation model): the recipient's
1640
1615
  // self-inflating skill bundles. SessionStart fetch → the ONE advisor announce
1641
1616
  // line each; ALSO cached locally so the per-turn Match sensor reads it without
@@ -1727,6 +1702,7 @@ async function recap(input, mode = 'plain', opts = {}) {
1727
1702
  updateAvailablePromise,
1728
1703
  bodyPromise,
1729
1704
  ]);
1705
+ await instructionsPromise;
1730
1706
  const equippedLoadouts = loadoutState.decls;
1731
1707
  // Loadout version-gate deficiency (docs/loadout.md §Version gating step 3): a
1732
1708
  // pending loadout whose equip floor is ABOVE the installed CLI version can't be
package/dist/index.js CHANGED
@@ -1472,11 +1472,11 @@ Persona (tenant-scoped speaking instructions):
1472
1472
  persona show Show the active Persona.
1473
1473
  persona clear Remove the active Persona.
1474
1474
 
1475
- GrepRAG Instructions (canonical global/repo CLAUDE.md + AGENTS.md):
1476
- instructions pull <file> [--scope global|repo] [--push]
1477
- Pull disk instructions into canon.
1478
- instructions push [--scope global|repo|all] [--check] [--force]
1479
- Render canon back to managed instruction files.
1475
+ Instructions (~/.claude/CLAUDE.md in the dotclaude git repo is the source):
1476
+ instructions render [--check] Write ~/.codex/AGENTS.md and
1477
+ ~/.config/opencode/AGENTS.md from the git CLAUDE.md
1478
+ plus ~/.claude/instructions/<harness>.md.
1479
+ instructions status Show whether each rendered file is current.
1480
1480
  agents ... Deprecated alias for instructions.
1481
1481
 
1482
1482
  Project metadata (rename / merge / list):
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
- /** Keep installed native skill adapters at canon.
2
+ /** Keep installed Codex/OpenCode launchers at canon.
3
3
  *
4
- * Adapters were written only by explicit syncs (init, `skill mirror sync`,
5
- * `--only`), so a canon change made anywhere — `skill mirror apply`, another
6
- * session, another machine — left them behind until someone re-synced by hand.
4
+ * Launchers were written only by explicit syncs (init, `skill mirror sync`),
5
+ * so a canon change ingested anywhere — another session, another machine —
6
+ * left them behind until someone re-synced by hand.
7
7
  *
8
8
  * SessionStart calls this with the mirror roster it already fetched. Detection
9
9
  * is local: each managed adapter's stamps against the roster. Only a stale
@@ -16,7 +16,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.readAdapterStamps = readAdapterStamps;
17
17
  exports.staleNativeAdapters = staleNativeAdapters;
18
18
  exports.refreshNativeAdapters = refreshNativeAdapters;
19
- const claude_lifecycle_cutover_1 = require("./claude-lifecycle-cutover");
20
19
  const native_skill_mirror_1 = require("./native-skill-mirror");
21
20
  const skill_mirror_files_1 = require("./skill-mirror-files");
22
21
  /** The identity stamps a generated adapter carries in its frontmatter. */
@@ -37,8 +36,7 @@ function readAdapterStamps(content) {
37
36
  function staleNativeAdapters(params) {
38
37
  const globalRoot = (0, native_skill_mirror_1.nativeSkillRoot)(params.platform, params.homeDir);
39
38
  const roots = [globalRoot];
40
- // Claude adapters live only in the home root (claude-lifecycle-cutover.ts).
41
- const projectRoot = params.projectDir && params.platform !== 'claude-code'
39
+ const projectRoot = params.projectDir
42
40
  ? (0, native_skill_mirror_1.writerOwnedProjectSkillRoot)(params.platform, params.projectDir, params.homeDir)
43
41
  : null;
44
42
  if (projectRoot)
@@ -80,10 +78,11 @@ function staleNativeAdapters(params) {
80
78
  }
81
79
  /** Rewrite each stale managed adapter of this harness from canon, through the
82
80
  * writer the sync commands use. One adapter per write, so a diverged one holds
83
- * back no other. A harness without native adapters is a no-op. */
81
+ * back no other. A harness without native adapters is a no-op, Claude Code
82
+ * included: it reads skills from their git folders (adr/skill-ownership-git.md). */
84
83
  async function refreshNativeAdapters(params) {
85
84
  const platform = params.platform;
86
- if (platform !== 'claude-code' && platform !== 'codex' && platform !== 'opencode') {
85
+ if (platform !== 'codex' && platform !== 'opencode') {
87
86
  return { refreshed: 0, blocked: 0 };
88
87
  }
89
88
  const stale = staleNativeAdapters({ ...params, platform });
@@ -94,15 +93,13 @@ async function refreshNativeAdapters(params) {
94
93
  if (!skill)
95
94
  continue; // canon unreachable: the next session start retries
96
95
  try {
97
- const result = platform === 'claude-code'
98
- ? (0, claude_lifecycle_cutover_1.applyClaudeLifecycleCutover)({ skills: [skill], names: [skill.skillName], homeDir: params.homeDir })
99
- : (0, native_skill_mirror_1.applyNativeSkillMirror)({
100
- platform,
101
- skills: [skill],
102
- homeDir: params.homeDir,
103
- projectDir: params.projectDir,
104
- prune: false,
105
- });
96
+ const result = (0, native_skill_mirror_1.applyNativeSkillMirror)({
97
+ platform,
98
+ skills: [skill],
99
+ homeDir: params.homeDir,
100
+ projectDir: params.projectDir,
101
+ prune: false,
102
+ });
106
103
  refreshed += result.updated;
107
104
  blocked += result.blocked;
108
105
  }
@@ -321,130 +321,49 @@ function canonicalContentHash(skill) {
321
321
  function canonicalLookupArgs(skill) {
322
322
  return `--skill-id ${canonicalSkillId(skill)}`;
323
323
  }
324
- function canonicalWriteArgs(skill) {
325
- if (skill.scope !== 'project' || !skill.projectId)
326
- return '';
327
- const replaces = (skill.replaces || []).map(id => ` --replaces ${id}`).join('');
328
- return `--scope project --project-id ${skill.projectId}${replaces}`;
329
- }
330
- function canonicalEditArgs(skill) {
331
- return [canonicalLookupArgs(skill), canonicalWriteArgs(skill)].filter(Boolean).join(' ');
332
- }
333
- function nativeCreationLocations(platform) {
334
- if (platform === 'codex') {
335
- return '`~/.codex/skills/<new-name>/SKILL.md` (global) or `<repo>/.agents/skills/<new-name>/SKILL.md` (project)';
336
- }
337
- if (platform === 'opencode') {
338
- return '`~/.config/opencode/skills/<new-name>/SKILL.md` (global) or `<repo>/.opencode/skills/<new-name>/SKILL.md` (project)';
339
- }
340
- return '`~/.claude/skills/<new-name>/SKILL.md` (global) or `<repo>/.claude/skills/<new-name>/SKILL.md` (project)';
341
- }
342
- function renderChangeSkillLine(params) {
343
- const exportCommand = `greprag skill mirror export ${params.skillName} ${params.identityArg} --to <dir>`;
344
- const applyCommand = `greprag skill mirror apply <dir> --skill ${params.skillName} ${params.editArgs} --expected-hash <exported-hash> --reason "<why>"`;
345
- if (params.platform === 'codex') {
346
- return `- **Change this skill:** run \`greprag load skill-change\`, then \`${exportCommand}\`; patch the exported Markdown files non-interactively; run \`${applyCommand}\`; then \`${params.syncCommand}\`; then verify with \`${params.loadCommand}\`.`;
347
- }
348
- return `- **Change this skill:** run \`greprag load skill-change\`, then \`greprag skill edit ${params.skillName} ${params.editArgs} --reason "<why>"\`, then \`${params.syncCommand}\`, then verify with \`${params.loadCommand}\`.`;
349
- }
350
- function renderEditingSection(platform, params) {
351
- const exportCommand = `greprag skill mirror export ${params.skillName} ${params.identityArg} --to <dir>`;
352
- const applyCommand = `greprag skill mirror apply <dir> --skill ${params.skillName} ${params.editArgs} --expected-hash <exported-hash> --reason "<why>"`;
353
- if (platform === 'codex') {
354
- return `## Editing
355
-
356
- Codex agents must use the non-interactive mirror path:
357
-
358
- \`\`\`bash
359
- ${exportCommand}
360
- # patch the exported Markdown files with normal file edits
361
- ${applyCommand}
362
- \`\`\`
363
-
364
- Do not launch an interactive editor from Codex. If using \`greprag skill edit\` as an export helper, include \`--no-open\` and run the printed apply command after patching.
365
- `;
366
- }
367
- return `## Editing
368
-
369
- To edit this skill, run the guarded editor flow:
370
-
371
- \`\`\`bash
372
- greprag skill edit ${params.skillName} ${params.editArgs} --reason "<why>"
373
- \`\`\`
374
-
375
- Manual path:
376
-
377
- \`\`\`bash
378
- ${exportCommand}
379
- ${applyCommand}
380
- \`\`\`
381
- `;
324
+ /** Where the skill's one true copy lives: git. adr: adr/skill-ownership-git.md */
325
+ function gitSkillFolder(skill) {
326
+ return skill.scope === 'project'
327
+ ? `\`<repo>/.claude/skills/${skill.skillName}/\`${skill.projectName ? ` in the ${skill.projectName} repo` : ''}`
328
+ : `\`~/.claude/skills/${skill.skillName}/\` in the dotclaude repo`;
382
329
  }
383
330
  function renderAdapterBody(platform, skill) {
384
331
  const skillName = skill.skillName;
385
332
  const skillId = canonicalSkillId(skill);
386
333
  const identityArg = canonicalLookupArgs(skill);
387
- const editArgs = canonicalEditArgs(skill);
388
- const creationLocations = nativeCreationLocations(platform);
389
334
  const syncCommand = (0, skill_activation_manifest_1.nativeAdapterInstallCommand)(platform, [skillName]);
390
- const creationLine = platform === 'claude-code'
391
- ? '- **Create another skill:** use the normal native creation path and leave it unmanaged until a separate Claude cutover is approved.'
392
- : `- **Create another skill:** create a normal native skill at ${creationLocations}; run \`${syncCommand} --dry-run\` and confirm it says \`adopt\`; then run \`${syncCommand}\`. GrepRAG adopts it as canon and replaces the native package with an adapter.`;
393
335
  const companions = skill.files.map(file => file.path).filter(relative => relative !== 'SKILL.md').sort();
394
336
  const harnessArg = `--harness ${platform}`;
395
337
  const loadCommand = `greprag load ${skillName} ${identityArg} ${harnessArg}`;
396
- const changeSkillLine = renderChangeSkillLine({
397
- platform,
398
- skillName,
399
- editArgs,
400
- identityArg,
401
- syncCommand,
402
- loadCommand,
403
- });
404
- const editingSection = renderEditingSection(platform, { skillName, editArgs, identityArg });
405
338
  const companionLines = companions.length
406
339
  ? companions.map(relative => `- \`greprag load ${skillName} ${relative} ${identityArg} ${harnessArg}\``).join('\n')
407
- : '- No companion docs are mirrored into this native adapter.';
340
+ : '- No companion docs are mirrored into this launcher.';
408
341
  return `# ${skillName}
409
342
 
410
343
  ## GENERATED ADAPTER — NEVER EDIT
411
344
 
412
- This is a disposable GrepRAG launcher for ${platform}, not canonical skill content. Never edit or copy this adapter, and never use \`greprag skill install\` to create or change a mirrored skill.
413
-
414
- Do not add or maintain project-state/doc pointers here. Current project state belongs in repo docs and the GrepRAG doc mirror; \`greprag load ${skillName} ${identityArg} ${harnessArg}\` discovers relevant state docs dynamically.
345
+ This is a disposable GrepRAG launcher for ${platform}, not skill content. The skill lives in git at ${gitSkillFolder(skill)}; GrepRAG mirrors the committed files read-only and this launcher loads them.
415
346
 
416
347
  Required action chains:
417
348
 
418
349
  - **Use this skill:** run \`${loadCommand}\` before acting.
419
- ${changeSkillLine}
420
- ${creationLine}
350
+ - **Change this skill:** edit ${gitSkillFolder(skill)} with normal file edits, commit, then run \`${syncCommand}\` (session start does it too) and verify with \`${loadCommand}\`. Uncommitted edits are never served. History and rollback are git log / git revert on that folder.
351
+ - **Create another skill:** create \`~/.claude/skills/<new-name>/SKILL.md\` (dotclaude repo, global) or \`<repo>/.claude/skills/<new-name>/SKILL.md\` (project), commit, then run \`${syncCommand}\`.
421
352
 
422
353
  Authority: ${skillId}
423
354
  Source binding: ${sourceBindingState(skill)}
424
355
  Canonical content hash: ${canonicalContentHash(skill)}
425
356
  ${typeof skill.revision === 'number' ? `Mirror revision: ${skill.revision}` : 'Mirror revision: unknown'}
426
357
 
427
- ${editingSection}
428
-
429
- History and rollback (every canon write keeps its bytes and reason):
430
-
431
- \`\`\`bash
432
- greprag skill history ${skillName} ${identityArg}
433
- greprag skill diff ${skillName} <revA> [<revB>] ${identityArg}
434
- greprag skill revert ${skillName} --to <rev> ${identityArg} --reason "<why>" --expected-hash <current-hash>
435
- greprag skill mirror snapshot list ${skillName} ${identityArg}
436
- greprag skill mirror snapshot promote ${skillName} --name <snapshot> ${editArgs} --expected-hash <current-hash> --reason "<why>"
437
- \`\`\`
438
-
439
358
  ## Mandatory Invocation
440
359
 
441
360
  When this skill activates, run:
442
361
 
443
362
  \`\`\`bash
444
- greprag load ${skillName} ${identityArg} ${harnessArg}
363
+ ${loadCommand}
445
364
  \`\`\`
446
365
 
447
- Read and follow that canonical payload before responding or taking action.
366
+ Read and follow that payload before responding or taking action.
448
367
 
449
368
  ## Companion Docs
450
369