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/commands/agent-doctrine-file.js +5 -128
- package/dist/commands/agents.js +125 -846
- package/dist/commands/init.js +17 -29
- package/dist/commands/load.js +14 -36
- package/dist/commands/parity.js +1 -1
- package/dist/commands/skill-mirror-reminder.js +1 -18
- package/dist/commands/skill.js +137 -566
- package/dist/hook.js +30 -54
- package/dist/index.js +5 -5
- package/dist/native-adapter-refresh.js +15 -18
- package/dist/native-skill-mirror.js +11 -92
- package/dist/opencode-plugin.bundle.js +81 -283
- package/dist/skill-activation-manifest.js +14 -37
- package/dist/skill-git-ingest.js +297 -0
- package/dist/skill-landing.js +7 -173
- package/dist/skill-mirror-client.js +4 -280
- package/dist/skill-staleness.js +3 -6
- package/package.json +1 -1
- package/skill/mechanic/docs/skill-fix-conventions.md +1 -1
- package/skill/templates/os.md +1 -1
- package/skill/templates/prompt-audit.md +26 -49
- package/skill/templates/skill-change.md +15 -13
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
|
|
145
|
-
const
|
|
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
|
|
1607
|
-
//
|
|
1608
|
-
|
|
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
|
-
|
|
1476
|
-
instructions
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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
|
|
2
|
+
/** Keep installed Codex/OpenCode launchers at canon.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
|
|
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 !== '
|
|
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 =
|
|
98
|
-
|
|
99
|
-
:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
|
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
|
|
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
|
-
${
|
|
420
|
-
|
|
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
|
-
|
|
363
|
+
${loadCommand}
|
|
445
364
|
\`\`\`
|
|
446
365
|
|
|
447
|
-
Read and follow that
|
|
366
|
+
Read and follow that payload before responding or taking action.
|
|
448
367
|
|
|
449
368
|
## Companion Docs
|
|
450
369
|
|