greprag 5.83.2 → 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/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/init.js +17 -29
- package/dist/commands/load.js +15 -35
- package/dist/commands/parity.js +1 -1
- package/dist/commands/reminder-registry.js +1 -8
- package/dist/commands/session.js +2 -2
- package/dist/commands/skill-mirror-reminder.js +1 -19
- package/dist/commands/skill.js +236 -448
- package/dist/hook.js +31 -54
- package/dist/index.js +19 -152
- package/dist/native-adapter-refresh.js +15 -18
- package/dist/native-skill-mirror.js +11 -89
- package/dist/opencode-plugin.bundle.js +82 -282
- package/dist/reminder-injector.js +1 -1
- 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 -251
- package/dist/skill-staleness.js +3 -6
- 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/os.md +1 -1
- package/skill/templates/prompt-audit.md +26 -49
- package/skill/templates/skill-change.md +15 -11
- package/dist/commands/sms.js +0 -215
|
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
|
|
25
25
|
// src/opencode-plugin.ts
|
|
26
26
|
var crypto6 = __toESM(require("crypto"));
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
var
|
|
27
|
+
var fs11 = __toESM(require("fs"));
|
|
28
|
+
var os4 = __toESM(require("os"));
|
|
29
|
+
var path12 = __toESM(require("path"));
|
|
30
30
|
|
|
31
31
|
// src/opencode-plugin-helpers.ts
|
|
32
32
|
var crypto = __toESM(require("crypto"));
|
|
@@ -2179,12 +2179,15 @@ var fs3 = __toESM(require("fs"));
|
|
|
2179
2179
|
var path4 = __toESM(require("path"));
|
|
2180
2180
|
|
|
2181
2181
|
// src/skill-landing.ts
|
|
2182
|
-
var
|
|
2182
|
+
var path2 = __toESM(require("path"));
|
|
2183
|
+
var BUNDLED_SKILLS = ["greprag", "commander", "content-advisor", "mechanic"];
|
|
2184
|
+
var LEARNED_DIR_RELPATH = path2.join("docs", "learned");
|
|
2185
|
+
var LEARNINGS_RELPATH = path2.join("docs", "learnings.md");
|
|
2183
2186
|
|
|
2184
2187
|
// src/skill-mirror-files.ts
|
|
2185
2188
|
var crypto2 = __toESM(require("node:crypto"));
|
|
2186
2189
|
var fs2 = __toESM(require("node:fs"));
|
|
2187
|
-
var
|
|
2190
|
+
var path3 = __toESM(require("node:path"));
|
|
2188
2191
|
function computeSkillFileHash(files) {
|
|
2189
2192
|
const hash = crypto2.createHash("sha256");
|
|
2190
2193
|
for (const file of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
@@ -2208,13 +2211,13 @@ function isLinkedSkillFolder(dir) {
|
|
|
2208
2211
|
function isSkillFolderOwnedElsewhere(dir) {
|
|
2209
2212
|
if (isLinkedSkillFolder(dir))
|
|
2210
2213
|
return true;
|
|
2211
|
-
const root =
|
|
2212
|
-
const harnessDir =
|
|
2213
|
-
if (
|
|
2214
|
+
const root = path3.dirname(path3.resolve(dir));
|
|
2215
|
+
const harnessDir = path3.basename(path3.dirname(root));
|
|
2216
|
+
if (path3.basename(root) !== "skills" || !INSTALLED_SKILL_HARNESS_DIRS.includes(harnessDir))
|
|
2214
2217
|
return false;
|
|
2215
2218
|
let skillMd = "";
|
|
2216
2219
|
try {
|
|
2217
|
-
skillMd = fs2.readFileSync(
|
|
2220
|
+
skillMd = fs2.readFileSync(path3.join(dir, "SKILL.md"), "utf8");
|
|
2218
2221
|
} catch {
|
|
2219
2222
|
}
|
|
2220
2223
|
if (isGeneratedSkillAdapter(skillMd))
|
|
@@ -2225,8 +2228,8 @@ function isSkillFolderOwnedElsewhere(dir) {
|
|
|
2225
2228
|
if (harnessDir !== ".claude" && harnessDir !== ".agents")
|
|
2226
2229
|
return false;
|
|
2227
2230
|
try {
|
|
2228
|
-
const lock = JSON.parse(fs2.readFileSync(
|
|
2229
|
-
return Boolean(lock?.skills && Object.prototype.hasOwnProperty.call(lock.skills,
|
|
2231
|
+
const lock = JSON.parse(fs2.readFileSync(path3.join(path3.dirname(path3.dirname(root)), ".agents", ".skill-lock.json"), "utf8"));
|
|
2232
|
+
return Boolean(lock?.skills && Object.prototype.hasOwnProperty.call(lock.skills, path3.basename(dir)));
|
|
2230
2233
|
} catch {
|
|
2231
2234
|
return false;
|
|
2232
2235
|
}
|
|
@@ -2237,11 +2240,6 @@ function isSafeMirroredSkillFile(file) {
|
|
|
2237
2240
|
return /^docs\/(?!.*(?:^|\/)\.\.(?:\/|$))[A-Za-z0-9._\/-]+\.md$/.test(file.path);
|
|
2238
2241
|
}
|
|
2239
2242
|
|
|
2240
|
-
// src/skill-landing.ts
|
|
2241
|
-
var BUNDLED_SKILLS = ["greprag", "commander", "content-advisor", "mechanic"];
|
|
2242
|
-
var LEARNED_DIR_RELPATH = path3.join("docs", "learned");
|
|
2243
|
-
var LEARNINGS_RELPATH = path3.join("docs", "learnings.md");
|
|
2244
|
-
|
|
2245
2243
|
// src/skill-activation-manifest.ts
|
|
2246
2244
|
var MAX_NATIVE_SKILL_FILES = 1500;
|
|
2247
2245
|
var MAX_SCAN_DEPTH = 7;
|
|
@@ -2348,19 +2346,15 @@ function readNativeSkillNames(params) {
|
|
|
2348
2346
|
}
|
|
2349
2347
|
function nativeAdapterGap(platform, mirrored, native) {
|
|
2350
2348
|
const missing = [];
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
for (const { skillName, scope } of mirrored) {
|
|
2349
|
+
if (platform !== "codex" && platform !== "opencode")
|
|
2350
|
+
return { missing };
|
|
2351
|
+
for (const { skillName } of mirrored) {
|
|
2355
2352
|
if (!skillName || BUNDLED_SKILLS.includes(skillName))
|
|
2356
2353
|
continue;
|
|
2357
|
-
|
|
2358
|
-
if (!kind)
|
|
2354
|
+
if (!native.get(skillName.toLowerCase()))
|
|
2359
2355
|
missing.push(skillName);
|
|
2360
|
-
else if (kind === "local" && platform === "claude-code" && scope !== "project")
|
|
2361
|
-
localCopies.push(skillName);
|
|
2362
2356
|
}
|
|
2363
|
-
return { missing
|
|
2357
|
+
return { missing };
|
|
2364
2358
|
}
|
|
2365
2359
|
function buildMirroredSkillActivation(entries, native, platform) {
|
|
2366
2360
|
const valid = entries.filter((entry) => entry.skillName && entry.triggerDescription);
|
|
@@ -2377,16 +2371,7 @@ function buildMirroredSkillActivation(entries, native, platform) {
|
|
|
2377
2371
|
function nativeAdapterInstallCommand(platform, missingNames) {
|
|
2378
2372
|
if (missingNames.length === 0)
|
|
2379
2373
|
return null;
|
|
2380
|
-
|
|
2381
|
-
return `greprag skill mirror sync claude-code --only ${[...missingNames].sort().join(",")}`;
|
|
2382
|
-
}
|
|
2383
|
-
if (platform === "codex" || platform === "opencode") {
|
|
2384
|
-
return `greprag skill mirror sync ${platform}`;
|
|
2385
|
-
}
|
|
2386
|
-
return null;
|
|
2387
|
-
}
|
|
2388
|
-
function localCopyCutoverCommand(platform, localCopies) {
|
|
2389
|
-
return localCopies.length > 0 ? nativeAdapterInstallCommand(platform, ["<name>"]) : null;
|
|
2374
|
+
return platform === "codex" || platform === "opencode" ? `greprag skill mirror sync ${platform}` : null;
|
|
2390
2375
|
}
|
|
2391
2376
|
function activationFromApiRows(params) {
|
|
2392
2377
|
const entries = params.rows.filter((row) => typeof row.skillName === "string" && !!row.skillName && typeof row.triggerDescription === "string" && !!row.triggerDescription).map((row) => ({
|
|
@@ -2409,20 +2394,9 @@ function renderEntry(skill) {
|
|
|
2409
2394
|
function buildSkillMirrorAnnounce(m, platform) {
|
|
2410
2395
|
if (!m || m.count <= 0)
|
|
2411
2396
|
return null;
|
|
2412
|
-
const cutoverCommand = localCopyCutoverCommand(platform || "", m.localCopies);
|
|
2413
|
-
const copies = m.localCopies.length === 1 ? "one mirrored skill" : `${m.localCopies.length} mirrored skills`;
|
|
2414
|
-
const copySection = cutoverCommand ? [
|
|
2415
|
-
"### Hand-Kept Copies",
|
|
2416
|
-
`This harness lists ${copies} from a hand-kept copy instead of an adapter, so it keeps running that copy when the mirrored skill changes: ${m.localCopies.join(", ")}. Replacing a copy with its adapter is the user's call, one skill at a time (the old SKILL.md is backed up first):`,
|
|
2417
|
-
"",
|
|
2418
|
-
` ${cutoverCommand}`,
|
|
2419
|
-
"",
|
|
2420
|
-
"Offer that command when the user asks why a skill behaves out of date, or when you needed one of them this session.",
|
|
2421
|
-
""
|
|
2422
|
-
] : [];
|
|
2423
2397
|
if (m.skills.length === 0) {
|
|
2424
2398
|
const line = "[greprag skills: slash skills are available. 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. Use `greprag load <skill>` to read skill instructions.]";
|
|
2425
|
-
return
|
|
2399
|
+
return line;
|
|
2426
2400
|
}
|
|
2427
2401
|
const installCommand = nativeAdapterInstallCommand(platform || "", m.missing);
|
|
2428
2402
|
const gapSection = installCommand ? [
|
|
@@ -2440,7 +2414,6 @@ function buildSkillMirrorAnnounce(m, platform) {
|
|
|
2440
2414
|
"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.",
|
|
2441
2415
|
"",
|
|
2442
2416
|
...gapSection,
|
|
2443
|
-
...copySection,
|
|
2444
2417
|
"### Trigger Rules",
|
|
2445
2418
|
"If the user names a skill (with or without `/`) OR the request clearly matches a skill's description below, you MUST activate that skill for the current turn. Match meaning, not exact keywords.",
|
|
2446
2419
|
"",
|
|
@@ -2466,7 +2439,6 @@ function buildSkillMirrorAnnounce(m, platform) {
|
|
|
2466
2439
|
}
|
|
2467
2440
|
var skillMirrorAnnounceModule = {
|
|
2468
2441
|
id: "skill-mirror-announce",
|
|
2469
|
-
source: "prompt",
|
|
2470
2442
|
dependsOn: ["load-primer"],
|
|
2471
2443
|
// references `greprag load` — the primer establishes it
|
|
2472
2444
|
detect: (_env) => ({ tier: "silent" }),
|
|
@@ -2549,7 +2521,7 @@ function buildDeliveryAnnounce(env) {
|
|
|
2549
2521
|
`[DELIVERY \u2014 ${project}]`,
|
|
2550
2522
|
"Commit useful, passing work. Only committed state delivers; ignore uncommitted and untracked work in every checkout.",
|
|
2551
2523
|
coordinationLine(env.platform),
|
|
2552
|
-
"Land every ready same-repo commit: update the default branch, rebase your worktree onto its tip, retest there, take greprag merge-lock in the canonical checkout, recheck the tip, merge --ff-only, release --landed. Tip moved? Free the lock and prepare again. Never rebase a shared default branch.",
|
|
2524
|
+
"Land every ready same-repo commit: update the default branch, rebase your worktree onto its tip, retest there, take greprag merge-lock in the canonical checkout, recheck the tip, merge --ff-only, release --landed. Tip moved? Free the lock and prepare again. A chip's branch arrives rebased by the chip: only fast-forward it; refused, free the lock and send it back. Never rebase in another session's worktree or a shared default branch.",
|
|
2553
2525
|
"Deploy through this repo's delivery profile, from its canonical primary checkout unless the profile says otherwise. Worktrees build; they do not deploy. Then verify production serves the commit you shipped.",
|
|
2554
2526
|
"THE GOAL ALREADY AUTHORIZES ALL OF THIS. Do not stop to ask permission to commit, merge, or deploy. Separate approval is for effects outside code delivery: destructive data, secrets, money, customer-facing messages.",
|
|
2555
2527
|
"Why each rule, and the details: `greprag load delivery`."
|
|
@@ -4177,11 +4149,6 @@ function recodeMessagesToPng(messages, opts) {
|
|
|
4177
4149
|
return stats;
|
|
4178
4150
|
}
|
|
4179
4151
|
|
|
4180
|
-
// src/claude-lifecycle-cutover.ts
|
|
4181
|
-
var fs11 = __toESM(require("fs"));
|
|
4182
|
-
var os4 = __toESM(require("os"));
|
|
4183
|
-
var path12 = __toESM(require("path"));
|
|
4184
|
-
|
|
4185
4152
|
// src/native-skill-mirror.ts
|
|
4186
4153
|
var fs10 = __toESM(require("node:fs"));
|
|
4187
4154
|
var os3 = __toESM(require("node:os"));
|
|
@@ -4423,123 +4390,44 @@ function canonicalContentHash(skill) {
|
|
|
4423
4390
|
function canonicalLookupArgs(skill) {
|
|
4424
4391
|
return `--skill-id ${canonicalSkillId(skill)}`;
|
|
4425
4392
|
}
|
|
4426
|
-
function
|
|
4427
|
-
|
|
4428
|
-
return "";
|
|
4429
|
-
const replaces = (skill.replaces || []).map((id) => ` --replaces ${id}`).join("");
|
|
4430
|
-
return `--scope project --project-id ${skill.projectId}${replaces}`;
|
|
4431
|
-
}
|
|
4432
|
-
function canonicalEditArgs(skill) {
|
|
4433
|
-
return [canonicalLookupArgs(skill), canonicalWriteArgs(skill)].filter(Boolean).join(" ");
|
|
4434
|
-
}
|
|
4435
|
-
function nativeCreationLocations(platform) {
|
|
4436
|
-
if (platform === "codex") {
|
|
4437
|
-
return "`~/.codex/skills/<new-name>/SKILL.md` (global) or `<repo>/.agents/skills/<new-name>/SKILL.md` (project)";
|
|
4438
|
-
}
|
|
4439
|
-
if (platform === "opencode") {
|
|
4440
|
-
return "`~/.config/opencode/skills/<new-name>/SKILL.md` (global) or `<repo>/.opencode/skills/<new-name>/SKILL.md` (project)";
|
|
4441
|
-
}
|
|
4442
|
-
return "`~/.claude/skills/<new-name>/SKILL.md` (global) or `<repo>/.claude/skills/<new-name>/SKILL.md` (project)";
|
|
4443
|
-
}
|
|
4444
|
-
function renderChangeSkillLine(params) {
|
|
4445
|
-
const exportCommand = `greprag skill mirror export ${params.skillName} ${params.identityArg} --to <dir>`;
|
|
4446
|
-
const applyCommand = `greprag skill mirror apply <dir> --skill ${params.skillName} ${params.editArgs} --expected-hash <exported-hash>`;
|
|
4447
|
-
if (params.platform === "codex") {
|
|
4448
|
-
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}\`.`;
|
|
4449
|
-
}
|
|
4450
|
-
return `- **Change this skill:** run \`greprag load skill-change\`, then \`greprag skill edit ${params.skillName} ${params.editArgs}\`, then \`${params.syncCommand}\`, then verify with \`${params.loadCommand}\`.`;
|
|
4451
|
-
}
|
|
4452
|
-
function renderEditingSection(platform, params) {
|
|
4453
|
-
const exportCommand = `greprag skill mirror export ${params.skillName} ${params.identityArg} --to <dir>`;
|
|
4454
|
-
const applyCommand = `greprag skill mirror apply <dir> --skill ${params.skillName} ${params.editArgs} --expected-hash <exported-hash>`;
|
|
4455
|
-
if (platform === "codex") {
|
|
4456
|
-
return `## Editing
|
|
4457
|
-
|
|
4458
|
-
Codex agents must use the non-interactive mirror path:
|
|
4459
|
-
|
|
4460
|
-
\`\`\`bash
|
|
4461
|
-
${exportCommand}
|
|
4462
|
-
# patch the exported Markdown files with normal file edits
|
|
4463
|
-
${applyCommand}
|
|
4464
|
-
\`\`\`
|
|
4465
|
-
|
|
4466
|
-
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.
|
|
4467
|
-
`;
|
|
4468
|
-
}
|
|
4469
|
-
return `## Editing
|
|
4470
|
-
|
|
4471
|
-
To edit this skill, run the guarded editor flow:
|
|
4472
|
-
|
|
4473
|
-
\`\`\`bash
|
|
4474
|
-
greprag skill edit ${params.skillName} ${params.editArgs}
|
|
4475
|
-
\`\`\`
|
|
4476
|
-
|
|
4477
|
-
Manual path:
|
|
4478
|
-
|
|
4479
|
-
\`\`\`bash
|
|
4480
|
-
${exportCommand}
|
|
4481
|
-
${applyCommand}
|
|
4482
|
-
\`\`\`
|
|
4483
|
-
`;
|
|
4393
|
+
function gitSkillFolder(skill) {
|
|
4394
|
+
return skill.scope === "project" ? `\`<repo>/.claude/skills/${skill.skillName}/\`${skill.projectName ? ` in the ${skill.projectName} repo` : ""}` : `\`~/.claude/skills/${skill.skillName}/\` in the dotclaude repo`;
|
|
4484
4395
|
}
|
|
4485
4396
|
function renderAdapterBody(platform, skill) {
|
|
4486
4397
|
const skillName = skill.skillName;
|
|
4487
4398
|
const skillId = canonicalSkillId(skill);
|
|
4488
4399
|
const identityArg = canonicalLookupArgs(skill);
|
|
4489
|
-
const editArgs = canonicalEditArgs(skill);
|
|
4490
|
-
const creationLocations = nativeCreationLocations(platform);
|
|
4491
4400
|
const syncCommand = nativeAdapterInstallCommand(platform, [skillName]);
|
|
4492
|
-
const creationLine = platform === "claude-code" ? "- **Create another skill:** use the normal native creation path and leave it unmanaged until a separate Claude cutover is approved." : `- **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.`;
|
|
4493
4401
|
const companions = skill.files.map((file) => file.path).filter((relative) => relative !== "SKILL.md").sort();
|
|
4494
4402
|
const harnessArg = `--harness ${platform}`;
|
|
4495
4403
|
const loadCommand = `greprag load ${skillName} ${identityArg} ${harnessArg}`;
|
|
4496
|
-
const
|
|
4497
|
-
platform,
|
|
4498
|
-
skillName,
|
|
4499
|
-
editArgs,
|
|
4500
|
-
identityArg,
|
|
4501
|
-
syncCommand,
|
|
4502
|
-
loadCommand
|
|
4503
|
-
});
|
|
4504
|
-
const editingSection = renderEditingSection(platform, { skillName, editArgs, identityArg });
|
|
4505
|
-
const companionLines = companions.length ? companions.map((relative) => `- \`greprag load ${skillName} ${relative} ${identityArg} ${harnessArg}\``).join("\n") : "- No companion docs are mirrored into this native adapter.";
|
|
4404
|
+
const companionLines = companions.length ? companions.map((relative) => `- \`greprag load ${skillName} ${relative} ${identityArg} ${harnessArg}\``).join("\n") : "- No companion docs are mirrored into this launcher.";
|
|
4506
4405
|
return `# ${skillName}
|
|
4507
4406
|
|
|
4508
4407
|
## GENERATED ADAPTER \u2014 NEVER EDIT
|
|
4509
4408
|
|
|
4510
|
-
This is a disposable GrepRAG launcher for ${platform}, not
|
|
4511
|
-
|
|
4512
|
-
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.
|
|
4409
|
+
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.
|
|
4513
4410
|
|
|
4514
4411
|
Required action chains:
|
|
4515
4412
|
|
|
4516
4413
|
- **Use this skill:** run \`${loadCommand}\` before acting.
|
|
4517
|
-
${
|
|
4518
|
-
|
|
4414
|
+
- **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.
|
|
4415
|
+
- **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}\`.
|
|
4519
4416
|
|
|
4520
4417
|
Authority: ${skillId}
|
|
4521
4418
|
Source binding: ${sourceBindingState(skill)}
|
|
4522
4419
|
Canonical content hash: ${canonicalContentHash(skill)}
|
|
4523
4420
|
${typeof skill.revision === "number" ? `Mirror revision: ${skill.revision}` : "Mirror revision: unknown"}
|
|
4524
4421
|
|
|
4525
|
-
${editingSection}
|
|
4526
|
-
|
|
4527
|
-
Snapshot rollback:
|
|
4528
|
-
|
|
4529
|
-
\`\`\`bash
|
|
4530
|
-
greprag skill mirror snapshot list ${skillName} ${identityArg}
|
|
4531
|
-
greprag skill mirror snapshot promote ${skillName} --name <snapshot> ${editArgs} --expected-hash <current-hash>
|
|
4532
|
-
\`\`\`
|
|
4533
|
-
|
|
4534
4422
|
## Mandatory Invocation
|
|
4535
4423
|
|
|
4536
4424
|
When this skill activates, run:
|
|
4537
4425
|
|
|
4538
4426
|
\`\`\`bash
|
|
4539
|
-
|
|
4427
|
+
${loadCommand}
|
|
4540
4428
|
\`\`\`
|
|
4541
4429
|
|
|
4542
|
-
Read and follow that
|
|
4430
|
+
Read and follow that payload before responding or taking action.
|
|
4543
4431
|
|
|
4544
4432
|
## Companion Docs
|
|
4545
4433
|
|
|
@@ -4803,94 +4691,6 @@ async function fetchNativeMirroredSkill(apiUrl, apiKey, row) {
|
|
|
4803
4691
|
} : null;
|
|
4804
4692
|
}
|
|
4805
4693
|
|
|
4806
|
-
// src/claude-lifecycle-cutover.ts
|
|
4807
|
-
var CLAUDE_LIFECYCLE_SKILLS = ["commit", "deploy", "release"];
|
|
4808
|
-
function adapterFor(skill) {
|
|
4809
|
-
const files = buildNativeSkillAdapter("claude-code", skill, { allowClaudeCode: true });
|
|
4810
|
-
if (!files || files.length !== 1 || files[0].path !== "SKILL.md") {
|
|
4811
|
-
throw new Error(`Claude lifecycle adapter is invalid for ${skill.skillName}.`);
|
|
4812
|
-
}
|
|
4813
|
-
return files;
|
|
4814
|
-
}
|
|
4815
|
-
function safeTimestamp(now) {
|
|
4816
|
-
return now.toISOString().replace(/[:.]/g, "-");
|
|
4817
|
-
}
|
|
4818
|
-
function requiredSkills(skills, names) {
|
|
4819
|
-
const byName = new Map(skills.filter((skill) => skill.scope !== "project").map((skill) => [skill.skillName, skill]));
|
|
4820
|
-
return names.map((name) => {
|
|
4821
|
-
const skill = byName.get(name);
|
|
4822
|
-
if (!skill)
|
|
4823
|
-
throw new Error(`Canonical Claude lifecycle skill missing: ${name}.`);
|
|
4824
|
-
return skill;
|
|
4825
|
-
});
|
|
4826
|
-
}
|
|
4827
|
-
function applyClaudeLifecycleCutover(params) {
|
|
4828
|
-
const homeDir = params.homeDir || os4.homedir();
|
|
4829
|
-
const root = nativeSkillRoot("claude-code", homeDir);
|
|
4830
|
-
const state = readState(root);
|
|
4831
|
-
const names = params.names?.length ? params.names : CLAUDE_LIFECYCLE_SKILLS;
|
|
4832
|
-
const prepared = requiredSkills(params.skills, names).map((skill) => {
|
|
4833
|
-
const target = path12.join(root, skill.skillName);
|
|
4834
|
-
if (isSkillFolderOwnedElsewhere(target)) {
|
|
4835
|
-
throw new Error(`Claude skill folder is owned elsewhere (a link or another installer's package): ${skill.skillName}; not written.`);
|
|
4836
|
-
}
|
|
4837
|
-
const skillMd = path12.join(target, "SKILL.md");
|
|
4838
|
-
const adapterFiles = adapterFor(skill);
|
|
4839
|
-
const nextHash = computeSkillFileHash(adapterFiles);
|
|
4840
|
-
const managed = state.skills[skill.skillName];
|
|
4841
|
-
let currentContent;
|
|
4842
|
-
if (fs11.existsSync(skillMd))
|
|
4843
|
-
currentContent = fs11.readFileSync(skillMd, "utf8");
|
|
4844
|
-
if (managed) {
|
|
4845
|
-
const currentFiles = currentContent === void 0 ? null : [{ path: "SKILL.md", content: currentContent }];
|
|
4846
|
-
if (!currentFiles || computeSkillFileHash(currentFiles) !== managed.hash) {
|
|
4847
|
-
throw new Error(`Claude lifecycle adapter diverged: ${skill.skillName}.`);
|
|
4848
|
-
}
|
|
4849
|
-
} else if (fs11.existsSync(target) && currentContent === void 0) {
|
|
4850
|
-
throw new Error(`Claude lifecycle package has no SKILL.md: ${skill.skillName}.`);
|
|
4851
|
-
}
|
|
4852
|
-
return { skill, target, skillMd, adapterFiles, nextHash, managed, currentContent };
|
|
4853
|
-
});
|
|
4854
|
-
const replacements = prepared.filter((item) => !item.managed && item.currentContent !== void 0);
|
|
4855
|
-
let backupDir;
|
|
4856
|
-
if (replacements.length > 0) {
|
|
4857
|
-
backupDir = path12.join(
|
|
4858
|
-
homeDir,
|
|
4859
|
-
".greprag",
|
|
4860
|
-
"backups",
|
|
4861
|
-
"claude-lifecycle-cutover",
|
|
4862
|
-
safeTimestamp(params.now || /* @__PURE__ */ new Date())
|
|
4863
|
-
);
|
|
4864
|
-
for (const item of replacements) {
|
|
4865
|
-
const destination = path12.join(backupDir, item.skill.skillName, "SKILL.md");
|
|
4866
|
-
fs11.mkdirSync(path12.dirname(destination), { recursive: true });
|
|
4867
|
-
fs11.writeFileSync(destination, item.currentContent, "utf8");
|
|
4868
|
-
}
|
|
4869
|
-
}
|
|
4870
|
-
const result = {
|
|
4871
|
-
installed: 0,
|
|
4872
|
-
updated: 0,
|
|
4873
|
-
current: 0,
|
|
4874
|
-
blocked: 0,
|
|
4875
|
-
backupDir
|
|
4876
|
-
};
|
|
4877
|
-
for (const item of prepared) {
|
|
4878
|
-
if (item.managed && item.managed.hash === item.nextHash) {
|
|
4879
|
-
result.current++;
|
|
4880
|
-
continue;
|
|
4881
|
-
}
|
|
4882
|
-
fs11.mkdirSync(item.target, { recursive: true });
|
|
4883
|
-
fs11.writeFileSync(item.skillMd, item.adapterFiles[0].content, "utf8");
|
|
4884
|
-
state.skills[item.skill.skillName] = { hash: item.nextHash, files: ["SKILL.md"] };
|
|
4885
|
-
if (item.managed)
|
|
4886
|
-
result.updated++;
|
|
4887
|
-
else
|
|
4888
|
-
result.installed++;
|
|
4889
|
-
}
|
|
4890
|
-
writeState(root, state);
|
|
4891
|
-
return result;
|
|
4892
|
-
}
|
|
4893
|
-
|
|
4894
4694
|
// src/native-adapter-refresh.ts
|
|
4895
4695
|
function readAdapterStamps(content) {
|
|
4896
4696
|
const frontmatter = /^---\n([\s\S]*?)\n---/.exec(content.replace(/\r\n?/g, "\n"))?.[1] || "";
|
|
@@ -4906,7 +4706,7 @@ function readAdapterStamps(content) {
|
|
|
4906
4706
|
function staleNativeAdapters(params) {
|
|
4907
4707
|
const globalRoot = nativeSkillRoot(params.platform, params.homeDir);
|
|
4908
4708
|
const roots = [globalRoot];
|
|
4909
|
-
const projectRoot = params.projectDir
|
|
4709
|
+
const projectRoot = params.projectDir ? writerOwnedProjectSkillRoot(params.platform, params.projectDir, params.homeDir) : null;
|
|
4910
4710
|
if (projectRoot)
|
|
4911
4711
|
roots.push(projectRoot);
|
|
4912
4712
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -4940,7 +4740,7 @@ function staleNativeAdapters(params) {
|
|
|
4940
4740
|
}
|
|
4941
4741
|
async function refreshNativeAdapters(params) {
|
|
4942
4742
|
const platform = params.platform;
|
|
4943
|
-
if (platform !== "
|
|
4743
|
+
if (platform !== "codex" && platform !== "opencode") {
|
|
4944
4744
|
return { refreshed: 0, blocked: 0 };
|
|
4945
4745
|
}
|
|
4946
4746
|
const stale = staleNativeAdapters({ ...params, platform });
|
|
@@ -4951,7 +4751,7 @@ async function refreshNativeAdapters(params) {
|
|
|
4951
4751
|
if (!skill)
|
|
4952
4752
|
continue;
|
|
4953
4753
|
try {
|
|
4954
|
-
const result =
|
|
4754
|
+
const result = applyNativeSkillMirror({
|
|
4955
4755
|
platform,
|
|
4956
4756
|
skills: [skill],
|
|
4957
4757
|
homeDir: params.homeDir,
|
|
@@ -4968,14 +4768,14 @@ async function refreshNativeAdapters(params) {
|
|
|
4968
4768
|
}
|
|
4969
4769
|
|
|
4970
4770
|
// src/opencode-plugin.ts
|
|
4971
|
-
var DEBUG_LOG_PATH =
|
|
4771
|
+
var DEBUG_LOG_PATH = path12.join(os4.homedir(), ".greprag", "opencode-plugin-debug.log");
|
|
4972
4772
|
var _debugLogReady = false;
|
|
4973
4773
|
function dlogInit() {
|
|
4974
4774
|
if (_debugLogReady)
|
|
4975
4775
|
return;
|
|
4976
4776
|
_debugLogReady = true;
|
|
4977
4777
|
try {
|
|
4978
|
-
|
|
4778
|
+
fs11.writeFileSync(DEBUG_LOG_PATH, "");
|
|
4979
4779
|
} catch {
|
|
4980
4780
|
}
|
|
4981
4781
|
}
|
|
@@ -4984,7 +4784,7 @@ function dlog(msg) {
|
|
|
4984
4784
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [greprag-memory] ${msg}
|
|
4985
4785
|
`;
|
|
4986
4786
|
try {
|
|
4987
|
-
|
|
4787
|
+
fs11.appendFileSync(DEBUG_LOG_PATH, line);
|
|
4988
4788
|
} catch {
|
|
4989
4789
|
}
|
|
4990
4790
|
}
|
|
@@ -4992,9 +4792,9 @@ dlog(`module top reached: pid=${process.pid} argv0=${process.argv[0]} distPath=$
|
|
|
4992
4792
|
var API_URL = "https://api.greprag.com";
|
|
4993
4793
|
function loadEnvFile(filePath2) {
|
|
4994
4794
|
try {
|
|
4995
|
-
if (!
|
|
4795
|
+
if (!fs11.existsSync(filePath2))
|
|
4996
4796
|
return;
|
|
4997
|
-
const raw =
|
|
4797
|
+
const raw = fs11.readFileSync(filePath2, "utf-8");
|
|
4998
4798
|
for (const line of raw.split(/\r?\n/)) {
|
|
4999
4799
|
const trimmed = line.trim();
|
|
5000
4800
|
if (!trimmed || trimmed.startsWith("#"))
|
|
@@ -5014,12 +4814,12 @@ function loadEnvFile(filePath2) {
|
|
|
5014
4814
|
}
|
|
5015
4815
|
}
|
|
5016
4816
|
function loadGrepragEnv() {
|
|
5017
|
-
loadEnvFile(
|
|
4817
|
+
loadEnvFile(path12.join(HOME, ".greprag", ".env"));
|
|
5018
4818
|
try {
|
|
5019
|
-
const p =
|
|
5020
|
-
if (!
|
|
4819
|
+
const p = path12.join(HOME, ".claude", "settings.json");
|
|
4820
|
+
if (!fs11.existsSync(p))
|
|
5021
4821
|
return;
|
|
5022
|
-
const data = JSON.parse(
|
|
4822
|
+
const data = JSON.parse(fs11.readFileSync(p, "utf-8"));
|
|
5023
4823
|
if (data && data.env && typeof data.env === "object") {
|
|
5024
4824
|
for (const [key, val] of Object.entries(data.env)) {
|
|
5025
4825
|
if (!process.env[key] && typeof val === "string") {
|
|
@@ -5032,11 +4832,11 @@ function loadGrepragEnv() {
|
|
|
5032
4832
|
}
|
|
5033
4833
|
loadGrepragEnv();
|
|
5034
4834
|
dlog(`env loaded: MEMORY_HOOK_ENABLED=${process.env.MEMORY_HOOK_ENABLED || "<unset>"} GREPRAG_API_KEY=${process.env.GREPRAG_API_KEY ? "set" : "<unset>"} GREPRAG_OPENCODE_CAPTURE=${process.env.GREPRAG_OPENCODE_CAPTURE || "<unset>"}`);
|
|
5035
|
-
var WATCHER_LOCK =
|
|
4835
|
+
var WATCHER_LOCK = path12.join(HOME || os4.homedir(), ".greprag", "opencode-watch.lock");
|
|
5036
4836
|
var WATCHER_STALE_MS = 3e4;
|
|
5037
4837
|
function findGrepragBinary() {
|
|
5038
4838
|
const override = process.env.GREPRAG_BIN;
|
|
5039
|
-
if (override &&
|
|
4839
|
+
if (override && fs11.existsSync(override))
|
|
5040
4840
|
return override;
|
|
5041
4841
|
const binaryName = process.platform === "win32" ? "greprag.cmd" : "greprag";
|
|
5042
4842
|
try {
|
|
@@ -5045,14 +4845,14 @@ function findGrepragBinary() {
|
|
|
5045
4845
|
const candidate = line.trim();
|
|
5046
4846
|
if (!candidate)
|
|
5047
4847
|
continue;
|
|
5048
|
-
if (!
|
|
4848
|
+
if (!fs11.existsSync(candidate))
|
|
5049
4849
|
continue;
|
|
5050
4850
|
if (process.platform === "win32") {
|
|
5051
|
-
const ext =
|
|
4851
|
+
const ext = path12.extname(candidate).toLowerCase();
|
|
5052
4852
|
if (ext === ".cmd" || ext === ".exe" || ext === ".bat")
|
|
5053
4853
|
return candidate;
|
|
5054
4854
|
const cmdSibling = candidate + ".cmd";
|
|
5055
|
-
if (
|
|
4855
|
+
if (fs11.existsSync(cmdSibling))
|
|
5056
4856
|
return cmdSibling;
|
|
5057
4857
|
continue;
|
|
5058
4858
|
}
|
|
@@ -5061,19 +4861,19 @@ function findGrepragBinary() {
|
|
|
5061
4861
|
} catch {
|
|
5062
4862
|
}
|
|
5063
4863
|
const candidates = process.platform === "win32" ? [
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
4864
|
+
path12.join(HOME, "AppData", "Roaming", "npm", "greprag.cmd"),
|
|
4865
|
+
path12.join(HOME, "AppData", "Roaming", "npm", "greprag"),
|
|
4866
|
+
path12.join(HOME, "AppData", "Local", "Yarn", "bin", "greprag.cmd"),
|
|
4867
|
+
path12.join(HOME, "AppData", "Local", "pnpm", "bin", "greprag.cmd")
|
|
5068
4868
|
] : [
|
|
5069
4869
|
"/usr/local/bin/greprag",
|
|
5070
4870
|
"/opt/homebrew/bin/greprag",
|
|
5071
|
-
|
|
5072
|
-
|
|
4871
|
+
path12.join(HOME || "", ".local", "bin", "greprag"),
|
|
4872
|
+
path12.join(HOME || "", ".yarn", "bin", "greprag")
|
|
5073
4873
|
];
|
|
5074
4874
|
for (const c of candidates) {
|
|
5075
4875
|
try {
|
|
5076
|
-
if (c &&
|
|
4876
|
+
if (c && fs11.existsSync(c))
|
|
5077
4877
|
return c;
|
|
5078
4878
|
} catch {
|
|
5079
4879
|
}
|
|
@@ -5082,18 +4882,18 @@ function findGrepragBinary() {
|
|
|
5082
4882
|
}
|
|
5083
4883
|
function tryClaimWatcherLock() {
|
|
5084
4884
|
try {
|
|
5085
|
-
const fd =
|
|
4885
|
+
const fd = fs11.openSync(WATCHER_LOCK, "wx");
|
|
5086
4886
|
return { ok: true, fd };
|
|
5087
4887
|
} catch (err) {
|
|
5088
4888
|
if (err.code !== "EEXIST") {
|
|
5089
4889
|
return { ok: false, reason: "lock-create-failed" };
|
|
5090
4890
|
}
|
|
5091
4891
|
try {
|
|
5092
|
-
const stat =
|
|
4892
|
+
const stat = fs11.statSync(WATCHER_LOCK);
|
|
5093
4893
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
5094
4894
|
let pidAlive = false;
|
|
5095
4895
|
try {
|
|
5096
|
-
const pid = parseInt(
|
|
4896
|
+
const pid = parseInt(fs11.readFileSync(WATCHER_LOCK, "utf-8").trim(), 10);
|
|
5097
4897
|
pidAlive = pid > 0 && isPidAlive(pid);
|
|
5098
4898
|
} catch {
|
|
5099
4899
|
}
|
|
@@ -5101,10 +4901,10 @@ function tryClaimWatcherLock() {
|
|
|
5101
4901
|
return { ok: false, reason: "busy" };
|
|
5102
4902
|
}
|
|
5103
4903
|
try {
|
|
5104
|
-
|
|
4904
|
+
fs11.unlinkSync(WATCHER_LOCK);
|
|
5105
4905
|
} catch {
|
|
5106
4906
|
}
|
|
5107
|
-
const fd =
|
|
4907
|
+
const fd = fs11.openSync(WATCHER_LOCK, "wx");
|
|
5108
4908
|
return { ok: true, fd };
|
|
5109
4909
|
} catch (err2) {
|
|
5110
4910
|
return { ok: false, reason: "lock-stale-replace-failed" };
|
|
@@ -5145,11 +4945,11 @@ function startCaptureWatcher() {
|
|
|
5145
4945
|
return;
|
|
5146
4946
|
}
|
|
5147
4947
|
try {
|
|
5148
|
-
|
|
5149
|
-
|
|
4948
|
+
fs11.writeSync(claim.fd, String(process.pid));
|
|
4949
|
+
fs11.closeSync(claim.fd);
|
|
5150
4950
|
} catch {
|
|
5151
4951
|
try {
|
|
5152
|
-
|
|
4952
|
+
fs11.unlinkSync(WATCHER_LOCK);
|
|
5153
4953
|
} catch {
|
|
5154
4954
|
}
|
|
5155
4955
|
return;
|
|
@@ -5165,11 +4965,11 @@ function startCaptureWatcher() {
|
|
|
5165
4965
|
const claim2 = tryClaimWatcherLock();
|
|
5166
4966
|
if (claim2.ok) {
|
|
5167
4967
|
try {
|
|
5168
|
-
|
|
5169
|
-
|
|
4968
|
+
fs11.writeSync(claim2.fd, String(process.pid));
|
|
4969
|
+
fs11.closeSync(claim2.fd);
|
|
5170
4970
|
} catch {
|
|
5171
4971
|
try {
|
|
5172
|
-
|
|
4972
|
+
fs11.unlinkSync(WATCHER_LOCK);
|
|
5173
4973
|
} catch {
|
|
5174
4974
|
}
|
|
5175
4975
|
return false;
|
|
@@ -5212,7 +5012,7 @@ function startCaptureWatcher() {
|
|
|
5212
5012
|
childStartTime = Date.now();
|
|
5213
5013
|
dlog(`startCaptureWatcher: spawned 'greprag opencode watch' pid=${child.pid ?? "<none>"}`);
|
|
5214
5014
|
try {
|
|
5215
|
-
|
|
5015
|
+
fs11.writeFileSync(WATCHER_LOCK, String(child.pid));
|
|
5216
5016
|
} catch {
|
|
5217
5017
|
}
|
|
5218
5018
|
child.stderr?.on("data", (chunk2) => {
|
|
@@ -5224,9 +5024,9 @@ function startCaptureWatcher() {
|
|
|
5224
5024
|
child.on("exit", (code, signal) => {
|
|
5225
5025
|
dlog(`startCaptureWatcher: child pid=${child.pid ?? "<none>"} exited code=${code} signal=${signal || "none"}`);
|
|
5226
5026
|
try {
|
|
5227
|
-
const current =
|
|
5027
|
+
const current = fs11.readFileSync(WATCHER_LOCK, "utf-8").trim();
|
|
5228
5028
|
if (current === String(child.pid))
|
|
5229
|
-
|
|
5029
|
+
fs11.unlinkSync(WATCHER_LOCK);
|
|
5230
5030
|
} catch {
|
|
5231
5031
|
}
|
|
5232
5032
|
currentChild = null;
|
|
@@ -5255,7 +5055,7 @@ function startCaptureWatcher() {
|
|
|
5255
5055
|
`
|
|
5256
5056
|
);
|
|
5257
5057
|
try {
|
|
5258
|
-
|
|
5058
|
+
fs11.unlinkSync(WATCHER_LOCK);
|
|
5259
5059
|
} catch {
|
|
5260
5060
|
}
|
|
5261
5061
|
return;
|
|
@@ -5287,7 +5087,7 @@ function startCaptureWatcher() {
|
|
|
5287
5087
|
}, 2e3).unref();
|
|
5288
5088
|
}
|
|
5289
5089
|
try {
|
|
5290
|
-
|
|
5090
|
+
fs11.unlinkSync(WATCHER_LOCK);
|
|
5291
5091
|
} catch {
|
|
5292
5092
|
}
|
|
5293
5093
|
};
|
|
@@ -5357,7 +5157,7 @@ async function fetchSkillActivation(apiKey, cwd) {
|
|
|
5357
5157
|
rows,
|
|
5358
5158
|
apiUrl: API_URL,
|
|
5359
5159
|
apiKey,
|
|
5360
|
-
homeDir:
|
|
5160
|
+
homeDir: os4.homedir(),
|
|
5361
5161
|
projectDir: cwd
|
|
5362
5162
|
}).catch(() => void 0);
|
|
5363
5163
|
return activationFromApiRows({
|
|
@@ -5432,11 +5232,11 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
5432
5232
|
return;
|
|
5433
5233
|
}
|
|
5434
5234
|
try {
|
|
5435
|
-
|
|
5436
|
-
|
|
5235
|
+
fs11.writeSync(claim.fd, String(process.pid));
|
|
5236
|
+
fs11.closeSync(claim.fd);
|
|
5437
5237
|
} catch {
|
|
5438
5238
|
try {
|
|
5439
|
-
|
|
5239
|
+
fs11.unlinkSync(lockPath);
|
|
5440
5240
|
} catch {
|
|
5441
5241
|
}
|
|
5442
5242
|
return;
|
|
@@ -5451,11 +5251,11 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
5451
5251
|
const claim2 = tryClaimRelayLock(lockPath);
|
|
5452
5252
|
if (claim2.ok) {
|
|
5453
5253
|
try {
|
|
5454
|
-
|
|
5455
|
-
|
|
5254
|
+
fs11.writeSync(claim2.fd, String(process.pid));
|
|
5255
|
+
fs11.closeSync(claim2.fd);
|
|
5456
5256
|
} catch {
|
|
5457
5257
|
try {
|
|
5458
|
-
|
|
5258
|
+
fs11.unlinkSync(lockPath);
|
|
5459
5259
|
} catch {
|
|
5460
5260
|
}
|
|
5461
5261
|
return false;
|
|
@@ -5491,7 +5291,7 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
5491
5291
|
childStartTime = Date.now();
|
|
5492
5292
|
dlog(`startSessionRelay: spawned 'greprag opencode relay' pid=${child.pid ?? "<none>"}`);
|
|
5493
5293
|
try {
|
|
5494
|
-
|
|
5294
|
+
fs11.writeFileSync(lockPath, String(child.pid));
|
|
5495
5295
|
} catch {
|
|
5496
5296
|
}
|
|
5497
5297
|
child.stderr?.on("data", (chunk2) => {
|
|
@@ -5502,9 +5302,9 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
5502
5302
|
});
|
|
5503
5303
|
child.on("exit", (code, signal) => {
|
|
5504
5304
|
try {
|
|
5505
|
-
const current =
|
|
5305
|
+
const current = fs11.readFileSync(lockPath, "utf-8").trim();
|
|
5506
5306
|
if (current === String(child.pid))
|
|
5507
|
-
|
|
5307
|
+
fs11.unlinkSync(lockPath);
|
|
5508
5308
|
} catch {
|
|
5509
5309
|
}
|
|
5510
5310
|
currentChild = null;
|
|
@@ -5531,7 +5331,7 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
5531
5331
|
`
|
|
5532
5332
|
);
|
|
5533
5333
|
try {
|
|
5534
|
-
|
|
5334
|
+
fs11.unlinkSync(lockPath);
|
|
5535
5335
|
} catch {
|
|
5536
5336
|
}
|
|
5537
5337
|
return;
|
|
@@ -5563,7 +5363,7 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
5563
5363
|
}, 2e3).unref();
|
|
5564
5364
|
}
|
|
5565
5365
|
try {
|
|
5566
|
-
|
|
5366
|
+
fs11.unlinkSync(lockPath);
|
|
5567
5367
|
} catch {
|
|
5568
5368
|
}
|
|
5569
5369
|
};
|