greprag 5.64.0 → 5.65.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.d.ts +30 -0
- package/dist/commands/agent-doctrine-file.js +104 -0
- package/dist/commands/agent-doctrine-file.js.map +1 -0
- package/dist/commands/agents.d.ts +15 -0
- package/dist/commands/agents.js +370 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/codex-chip/native.d.ts +5 -0
- package/dist/commands/codex-chip/native.js +29 -4
- package/dist/commands/codex-chip/native.js.map +1 -1
- package/dist/commands/codex-chip/prompt.js +1 -0
- package/dist/commands/codex-chip/prompt.js.map +1 -1
- package/dist/commands/codex.js +1 -1
- package/dist/commands/codex.js.map +1 -1
- package/dist/commands/fix.d.ts +9 -9
- package/dist/commands/fix.js +18 -19
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/inbox-drain.js +1 -1
- package/dist/commands/inbox-drain.js.map +1 -1
- package/dist/commands/inbox-watch.js +1 -1
- package/dist/commands/inbox-watch.js.map +1 -1
- package/dist/commands/init.js +40 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/load.d.ts +2 -0
- package/dist/commands/load.js +52 -1
- package/dist/commands/load.js.map +1 -1
- package/dist/commands/mechanic-live.js +6 -12
- package/dist/commands/mechanic-live.js.map +1 -1
- package/dist/commands/mechanic-spawn.js +3 -2
- package/dist/commands/mechanic-spawn.js.map +1 -1
- package/dist/commands/mechanic.js +4 -5
- package/dist/commands/mechanic.js.map +1 -1
- package/dist/commands/opencode-interrupt.d.ts +1 -0
- package/dist/commands/opencode-interrupt.js +1 -0
- package/dist/commands/opencode-interrupt.js.map +1 -1
- package/dist/commands/opencode-relay.js +1 -1
- package/dist/commands/opencode-relay.js.map +1 -1
- package/dist/commands/parity.js +6 -4
- package/dist/commands/parity.js.map +1 -1
- package/dist/commands/reminder-registry.js +1 -1
- package/dist/commands/reminder-registry.js.map +1 -1
- package/dist/commands/reminder-types.d.ts +10 -5
- package/dist/commands/skill-mirror-reminder.d.ts +9 -13
- package/dist/commands/skill-mirror-reminder.js +38 -15
- package/dist/commands/skill-mirror-reminder.js.map +1 -1
- package/dist/hook.js +18 -34
- package/dist/hook.js.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/mechanic-friction.d.ts +0 -17
- package/dist/mechanic-friction.js +10 -76
- package/dist/mechanic-friction.js.map +1 -1
- package/dist/opencode-plugin.bundle.js +220 -59
- package/dist/opencode-plugin.js +38 -1
- package/dist/opencode-plugin.js.map +1 -1
- package/dist/skill-activation-manifest.d.ts +37 -0
- package/dist/skill-activation-manifest.js +154 -0
- package/dist/skill-activation-manifest.js.map +1 -0
- package/package.json +1 -1
- package/skill/greprag/docs/codex-chip.md +3 -0
- package/skill/mechanic/SKILL.md +24 -25
- package/skill/mechanic/docs/skill-fix-conventions.md +2 -2
- package/skill/templates/codex-chip-spawn.md +18 -0
|
@@ -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 crypto2 = __toESM(require("crypto"));
|
|
27
|
-
var
|
|
27
|
+
var fs4 = __toESM(require("fs"));
|
|
28
28
|
var os = __toESM(require("os"));
|
|
29
|
-
var
|
|
29
|
+
var path4 = __toESM(require("path"));
|
|
30
30
|
|
|
31
31
|
// src/opencode-plugin-helpers.ts
|
|
32
32
|
var crypto = __toESM(require("crypto"));
|
|
@@ -2210,15 +2210,40 @@ var skillGainAnnounceModule = {
|
|
|
2210
2210
|
};
|
|
2211
2211
|
|
|
2212
2212
|
// src/commands/skill-mirror-reminder.ts
|
|
2213
|
+
var SKILL_ACTIVATION_MANIFEST_MAX_CHARS = 64e3;
|
|
2214
|
+
function renderEntry(skill) {
|
|
2215
|
+
const description = skill.triggerDescription.trim().replace(/\r\n?/g, "\n");
|
|
2216
|
+
const lines = description.split("\n");
|
|
2217
|
+
return `- ${skill.skillName}: ${lines[0]}${lines.slice(1).map((line) => `
|
|
2218
|
+
${line}`).join("")}`;
|
|
2219
|
+
}
|
|
2213
2220
|
function buildSkillMirrorAnnounce(m) {
|
|
2214
2221
|
if (!m || m.count <= 0)
|
|
2215
2222
|
return null;
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
"
|
|
2223
|
+
if (m.skills.length === 0) {
|
|
2224
|
+
return `[greprag load skills: all ${m.count} canonical mirrored skills are already advertised by this harness; use \`greprag load <skill>\` to read the canonical payload.]`;
|
|
2225
|
+
}
|
|
2226
|
+
const header = [
|
|
2227
|
+
"## GrepRAG Load Skills",
|
|
2228
|
+
`These ${m.skills.length} canonical mirrored skills are available through \`greprag load\`` + (m.nativeCount > 0 ? ` (${m.nativeCount} native-advertised duplicate${m.nativeCount === 1 ? "" : "s"} omitted)` : "") + ".",
|
|
2229
|
+
"When the user names a skill (with or without `/`) or the task clearly matches a description below, run `greprag load <skill>` before acting. The command returns the full canonical method; this list is its activation index.",
|
|
2230
|
+
""
|
|
2221
2231
|
].join("\n");
|
|
2232
|
+
let output = header;
|
|
2233
|
+
let included = 0;
|
|
2234
|
+
for (const skill of m.skills) {
|
|
2235
|
+
const block = renderEntry(skill);
|
|
2236
|
+
if (output.length + block.length + 1 > SKILL_ACTIVATION_MANIFEST_MAX_CHARS)
|
|
2237
|
+
break;
|
|
2238
|
+
output += `${block}
|
|
2239
|
+
`;
|
|
2240
|
+
included++;
|
|
2241
|
+
}
|
|
2242
|
+
if (included < m.skills.length) {
|
|
2243
|
+
output += `[Manifest bound reached: ${m.skills.length - included} additional skills are discoverable with \`greprag load\`.]
|
|
2244
|
+
`;
|
|
2245
|
+
}
|
|
2246
|
+
return output.trimEnd();
|
|
2222
2247
|
}
|
|
2223
2248
|
var skillMirrorAnnounceModule = {
|
|
2224
2249
|
id: "skill-mirror-announce",
|
|
@@ -2305,7 +2330,7 @@ var REGISTRY = [
|
|
|
2305
2330
|
skillGainAnnounceModule,
|
|
2306
2331
|
// announce-only skill-gain landings (docs/skill-learning-loop.md)
|
|
2307
2332
|
skillMirrorAnnounceModule,
|
|
2308
|
-
//
|
|
2333
|
+
// native-equivalent activation index for load-only mirrored skills
|
|
2309
2334
|
procedureAnnounceModule,
|
|
2310
2335
|
// active project procedures, rendered generically from operator-owned installs
|
|
2311
2336
|
loadoutRegistrarModule,
|
|
@@ -2403,7 +2428,8 @@ function buildOpenCodeEnv(params) {
|
|
|
2403
2428
|
setupWarning: params.setupWarning ?? null,
|
|
2404
2429
|
corpusApiDocs: params.corpusApiDocs ?? [],
|
|
2405
2430
|
updateAvailable: params.updateAvailable ?? null,
|
|
2406
|
-
procedureAnnounces: params.procedureAnnounces ?? []
|
|
2431
|
+
procedureAnnounces: params.procedureAnnounces ?? [],
|
|
2432
|
+
mirroredSkills: params.mirroredSkills
|
|
2407
2433
|
};
|
|
2408
2434
|
}
|
|
2409
2435
|
function getOpenCodeAnnounces(env) {
|
|
@@ -3103,15 +3129,116 @@ function recodeMessagesToPng(messages, opts) {
|
|
|
3103
3129
|
return stats;
|
|
3104
3130
|
}
|
|
3105
3131
|
|
|
3132
|
+
// src/skill-activation-manifest.ts
|
|
3133
|
+
var fs3 = __toESM(require("fs"));
|
|
3134
|
+
var path3 = __toESM(require("path"));
|
|
3135
|
+
var MAX_NATIVE_SKILL_FILES = 1500;
|
|
3136
|
+
var MAX_SCAN_DEPTH = 7;
|
|
3137
|
+
function homeRoots(homeDir, platform) {
|
|
3138
|
+
if (platform === "claude-code") {
|
|
3139
|
+
return [path3.join(homeDir, ".claude", "skills")];
|
|
3140
|
+
}
|
|
3141
|
+
if (platform === "codex") {
|
|
3142
|
+
return [
|
|
3143
|
+
path3.join(homeDir, ".codex", "skills"),
|
|
3144
|
+
path3.join(homeDir, ".agents", "skills"),
|
|
3145
|
+
path3.join(homeDir, ".codex", "plugins", "cache")
|
|
3146
|
+
];
|
|
3147
|
+
}
|
|
3148
|
+
return [path3.join(homeDir, ".config", "opencode", "skills")];
|
|
3149
|
+
}
|
|
3150
|
+
function ancestorDirs(cwd) {
|
|
3151
|
+
const dirs = [];
|
|
3152
|
+
let current = path3.resolve(cwd);
|
|
3153
|
+
for (let depth = 0; depth < 16; depth++) {
|
|
3154
|
+
dirs.push(current);
|
|
3155
|
+
const parent = path3.dirname(current);
|
|
3156
|
+
if (parent === current)
|
|
3157
|
+
break;
|
|
3158
|
+
current = parent;
|
|
3159
|
+
}
|
|
3160
|
+
return dirs;
|
|
3161
|
+
}
|
|
3162
|
+
function repoRoots(cwd, platform) {
|
|
3163
|
+
return ancestorDirs(cwd).flatMap((dir) => {
|
|
3164
|
+
if (platform === "claude-code")
|
|
3165
|
+
return [path3.join(dir, ".claude", "skills")];
|
|
3166
|
+
if (platform === "codex") {
|
|
3167
|
+
return [path3.join(dir, ".codex", "skills"), path3.join(dir, ".agents", "skills")];
|
|
3168
|
+
}
|
|
3169
|
+
return [path3.join(dir, ".opencode", "skills")];
|
|
3170
|
+
});
|
|
3171
|
+
}
|
|
3172
|
+
function frontmatterName(content) {
|
|
3173
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
3174
|
+
const name = fm && /(?:^|\r?\n)name:\s*["']?([^\r\n"']+)/.exec(fm[1]);
|
|
3175
|
+
return name?.[1]?.trim() || "";
|
|
3176
|
+
}
|
|
3177
|
+
function readNativeSkillNames(params) {
|
|
3178
|
+
const names = /* @__PURE__ */ new Set();
|
|
3179
|
+
let visited = 0;
|
|
3180
|
+
const walk = (dir, depth) => {
|
|
3181
|
+
if (depth > MAX_SCAN_DEPTH || visited >= MAX_NATIVE_SKILL_FILES)
|
|
3182
|
+
return;
|
|
3183
|
+
let entries;
|
|
3184
|
+
try {
|
|
3185
|
+
entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
3186
|
+
} catch {
|
|
3187
|
+
return;
|
|
3188
|
+
}
|
|
3189
|
+
for (const entry of entries) {
|
|
3190
|
+
if (visited >= MAX_NATIVE_SKILL_FILES)
|
|
3191
|
+
return;
|
|
3192
|
+
const full = path3.join(dir, entry.name);
|
|
3193
|
+
if (entry.isDirectory()) {
|
|
3194
|
+
walk(full, depth + 1);
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
if (!entry.isFile() || entry.name.toLowerCase() !== "skill.md")
|
|
3198
|
+
continue;
|
|
3199
|
+
visited++;
|
|
3200
|
+
names.add(path3.basename(path3.dirname(full)).toLowerCase());
|
|
3201
|
+
try {
|
|
3202
|
+
const declared = frontmatterName(fs3.readFileSync(full, "utf8"));
|
|
3203
|
+
if (declared)
|
|
3204
|
+
names.add(declared.toLowerCase());
|
|
3205
|
+
} catch {
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
};
|
|
3209
|
+
const roots = [
|
|
3210
|
+
...homeRoots(params.homeDir, params.platform),
|
|
3211
|
+
...repoRoots(params.cwd, params.platform)
|
|
3212
|
+
];
|
|
3213
|
+
for (const root of roots)
|
|
3214
|
+
walk(root, 0);
|
|
3215
|
+
return names;
|
|
3216
|
+
}
|
|
3217
|
+
function buildMirroredSkillActivation(entries, nativeNames) {
|
|
3218
|
+
const valid = entries.filter((entry) => entry.skillName && entry.triggerDescription);
|
|
3219
|
+
if (valid.length === 0)
|
|
3220
|
+
return void 0;
|
|
3221
|
+
const skills = valid.filter((entry) => !nativeNames.has(entry.skillName.toLowerCase()));
|
|
3222
|
+
return { count: valid.length, skills, nativeCount: valid.length - skills.length };
|
|
3223
|
+
}
|
|
3224
|
+
function activationFromApiRows(params) {
|
|
3225
|
+
const entries = params.rows.filter((row) => typeof row.skillName === "string" && !!row.skillName && typeof row.triggerDescription === "string" && !!row.triggerDescription).map((row) => ({
|
|
3226
|
+
skillName: row.skillName,
|
|
3227
|
+
description: typeof row.description === "string" ? row.description : "",
|
|
3228
|
+
triggerDescription: row.triggerDescription
|
|
3229
|
+
}));
|
|
3230
|
+
return buildMirroredSkillActivation(entries, readNativeSkillNames(params));
|
|
3231
|
+
}
|
|
3232
|
+
|
|
3106
3233
|
// src/opencode-plugin.ts
|
|
3107
|
-
var DEBUG_LOG_PATH =
|
|
3234
|
+
var DEBUG_LOG_PATH = path4.join(os.homedir(), ".greprag", "opencode-plugin-debug.log");
|
|
3108
3235
|
var _debugLogReady = false;
|
|
3109
3236
|
function dlogInit() {
|
|
3110
3237
|
if (_debugLogReady)
|
|
3111
3238
|
return;
|
|
3112
3239
|
_debugLogReady = true;
|
|
3113
3240
|
try {
|
|
3114
|
-
|
|
3241
|
+
fs4.writeFileSync(DEBUG_LOG_PATH, "");
|
|
3115
3242
|
} catch {
|
|
3116
3243
|
}
|
|
3117
3244
|
}
|
|
@@ -3120,7 +3247,7 @@ function dlog(msg) {
|
|
|
3120
3247
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [greprag-memory] ${msg}
|
|
3121
3248
|
`;
|
|
3122
3249
|
try {
|
|
3123
|
-
|
|
3250
|
+
fs4.appendFileSync(DEBUG_LOG_PATH, line);
|
|
3124
3251
|
} catch {
|
|
3125
3252
|
}
|
|
3126
3253
|
}
|
|
@@ -3128,9 +3255,9 @@ dlog(`module top reached: pid=${process.pid} argv0=${process.argv[0]} distPath=$
|
|
|
3128
3255
|
var API_URL = "https://api.greprag.com";
|
|
3129
3256
|
function loadEnvFile(filePath) {
|
|
3130
3257
|
try {
|
|
3131
|
-
if (!
|
|
3258
|
+
if (!fs4.existsSync(filePath))
|
|
3132
3259
|
return;
|
|
3133
|
-
const raw =
|
|
3260
|
+
const raw = fs4.readFileSync(filePath, "utf-8");
|
|
3134
3261
|
for (const line of raw.split(/\r?\n/)) {
|
|
3135
3262
|
const trimmed = line.trim();
|
|
3136
3263
|
if (!trimmed || trimmed.startsWith("#"))
|
|
@@ -3150,12 +3277,12 @@ function loadEnvFile(filePath) {
|
|
|
3150
3277
|
}
|
|
3151
3278
|
}
|
|
3152
3279
|
function loadGrepragEnv() {
|
|
3153
|
-
loadEnvFile(
|
|
3280
|
+
loadEnvFile(path4.join(HOME, ".greprag", ".env"));
|
|
3154
3281
|
try {
|
|
3155
|
-
const p =
|
|
3156
|
-
if (!
|
|
3282
|
+
const p = path4.join(HOME, ".claude", "settings.json");
|
|
3283
|
+
if (!fs4.existsSync(p))
|
|
3157
3284
|
return;
|
|
3158
|
-
const data = JSON.parse(
|
|
3285
|
+
const data = JSON.parse(fs4.readFileSync(p, "utf-8"));
|
|
3159
3286
|
if (data && data.env && typeof data.env === "object") {
|
|
3160
3287
|
for (const [key, val] of Object.entries(data.env)) {
|
|
3161
3288
|
if (!process.env[key] && typeof val === "string") {
|
|
@@ -3168,11 +3295,11 @@ function loadGrepragEnv() {
|
|
|
3168
3295
|
}
|
|
3169
3296
|
loadGrepragEnv();
|
|
3170
3297
|
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>"}`);
|
|
3171
|
-
var WATCHER_LOCK =
|
|
3298
|
+
var WATCHER_LOCK = path4.join(HOME || os.homedir(), ".greprag", "opencode-watch.lock");
|
|
3172
3299
|
var WATCHER_STALE_MS = 3e4;
|
|
3173
3300
|
function findGrepragBinary() {
|
|
3174
3301
|
const override = process.env.GREPRAG_BIN;
|
|
3175
|
-
if (override &&
|
|
3302
|
+
if (override && fs4.existsSync(override))
|
|
3176
3303
|
return override;
|
|
3177
3304
|
const binaryName = process.platform === "win32" ? "greprag.cmd" : "greprag";
|
|
3178
3305
|
try {
|
|
@@ -3181,14 +3308,14 @@ function findGrepragBinary() {
|
|
|
3181
3308
|
const candidate = line.trim();
|
|
3182
3309
|
if (!candidate)
|
|
3183
3310
|
continue;
|
|
3184
|
-
if (!
|
|
3311
|
+
if (!fs4.existsSync(candidate))
|
|
3185
3312
|
continue;
|
|
3186
3313
|
if (process.platform === "win32") {
|
|
3187
|
-
const ext =
|
|
3314
|
+
const ext = path4.extname(candidate).toLowerCase();
|
|
3188
3315
|
if (ext === ".cmd" || ext === ".exe" || ext === ".bat")
|
|
3189
3316
|
return candidate;
|
|
3190
3317
|
const cmdSibling = candidate + ".cmd";
|
|
3191
|
-
if (
|
|
3318
|
+
if (fs4.existsSync(cmdSibling))
|
|
3192
3319
|
return cmdSibling;
|
|
3193
3320
|
continue;
|
|
3194
3321
|
}
|
|
@@ -3197,19 +3324,19 @@ function findGrepragBinary() {
|
|
|
3197
3324
|
} catch {
|
|
3198
3325
|
}
|
|
3199
3326
|
const candidates = process.platform === "win32" ? [
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3327
|
+
path4.join(HOME, "AppData", "Roaming", "npm", "greprag.cmd"),
|
|
3328
|
+
path4.join(HOME, "AppData", "Roaming", "npm", "greprag"),
|
|
3329
|
+
path4.join(HOME, "AppData", "Local", "Yarn", "bin", "greprag.cmd"),
|
|
3330
|
+
path4.join(HOME, "AppData", "Local", "pnpm", "bin", "greprag.cmd")
|
|
3204
3331
|
] : [
|
|
3205
3332
|
"/usr/local/bin/greprag",
|
|
3206
3333
|
"/opt/homebrew/bin/greprag",
|
|
3207
|
-
|
|
3208
|
-
|
|
3334
|
+
path4.join(HOME || "", ".local", "bin", "greprag"),
|
|
3335
|
+
path4.join(HOME || "", ".yarn", "bin", "greprag")
|
|
3209
3336
|
];
|
|
3210
3337
|
for (const c of candidates) {
|
|
3211
3338
|
try {
|
|
3212
|
-
if (c &&
|
|
3339
|
+
if (c && fs4.existsSync(c))
|
|
3213
3340
|
return c;
|
|
3214
3341
|
} catch {
|
|
3215
3342
|
}
|
|
@@ -3218,18 +3345,18 @@ function findGrepragBinary() {
|
|
|
3218
3345
|
}
|
|
3219
3346
|
function tryClaimWatcherLock() {
|
|
3220
3347
|
try {
|
|
3221
|
-
const fd =
|
|
3348
|
+
const fd = fs4.openSync(WATCHER_LOCK, "wx");
|
|
3222
3349
|
return { ok: true, fd };
|
|
3223
3350
|
} catch (err) {
|
|
3224
3351
|
if (err.code !== "EEXIST") {
|
|
3225
3352
|
return { ok: false, reason: "lock-create-failed" };
|
|
3226
3353
|
}
|
|
3227
3354
|
try {
|
|
3228
|
-
const stat =
|
|
3355
|
+
const stat = fs4.statSync(WATCHER_LOCK);
|
|
3229
3356
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
3230
3357
|
let pidAlive = false;
|
|
3231
3358
|
try {
|
|
3232
|
-
const pid = parseInt(
|
|
3359
|
+
const pid = parseInt(fs4.readFileSync(WATCHER_LOCK, "utf-8").trim(), 10);
|
|
3233
3360
|
pidAlive = pid > 0 && isPidAlive(pid);
|
|
3234
3361
|
} catch {
|
|
3235
3362
|
}
|
|
@@ -3237,10 +3364,10 @@ function tryClaimWatcherLock() {
|
|
|
3237
3364
|
return { ok: false, reason: "busy" };
|
|
3238
3365
|
}
|
|
3239
3366
|
try {
|
|
3240
|
-
|
|
3367
|
+
fs4.unlinkSync(WATCHER_LOCK);
|
|
3241
3368
|
} catch {
|
|
3242
3369
|
}
|
|
3243
|
-
const fd =
|
|
3370
|
+
const fd = fs4.openSync(WATCHER_LOCK, "wx");
|
|
3244
3371
|
return { ok: true, fd };
|
|
3245
3372
|
} catch (err2) {
|
|
3246
3373
|
return { ok: false, reason: "lock-stale-replace-failed" };
|
|
@@ -3281,11 +3408,11 @@ function startCaptureWatcher() {
|
|
|
3281
3408
|
return;
|
|
3282
3409
|
}
|
|
3283
3410
|
try {
|
|
3284
|
-
|
|
3285
|
-
|
|
3411
|
+
fs4.writeSync(claim.fd, String(process.pid));
|
|
3412
|
+
fs4.closeSync(claim.fd);
|
|
3286
3413
|
} catch {
|
|
3287
3414
|
try {
|
|
3288
|
-
|
|
3415
|
+
fs4.unlinkSync(WATCHER_LOCK);
|
|
3289
3416
|
} catch {
|
|
3290
3417
|
}
|
|
3291
3418
|
return;
|
|
@@ -3301,11 +3428,11 @@ function startCaptureWatcher() {
|
|
|
3301
3428
|
const claim2 = tryClaimWatcherLock();
|
|
3302
3429
|
if (claim2.ok) {
|
|
3303
3430
|
try {
|
|
3304
|
-
|
|
3305
|
-
|
|
3431
|
+
fs4.writeSync(claim2.fd, String(process.pid));
|
|
3432
|
+
fs4.closeSync(claim2.fd);
|
|
3306
3433
|
} catch {
|
|
3307
3434
|
try {
|
|
3308
|
-
|
|
3435
|
+
fs4.unlinkSync(WATCHER_LOCK);
|
|
3309
3436
|
} catch {
|
|
3310
3437
|
}
|
|
3311
3438
|
return false;
|
|
@@ -3348,7 +3475,7 @@ function startCaptureWatcher() {
|
|
|
3348
3475
|
childStartTime = Date.now();
|
|
3349
3476
|
dlog(`startCaptureWatcher: spawned 'greprag opencode watch' pid=${child.pid ?? "<none>"}`);
|
|
3350
3477
|
try {
|
|
3351
|
-
|
|
3478
|
+
fs4.writeFileSync(WATCHER_LOCK, String(child.pid));
|
|
3352
3479
|
} catch {
|
|
3353
3480
|
}
|
|
3354
3481
|
child.stderr?.on("data", (chunk2) => {
|
|
@@ -3360,9 +3487,9 @@ function startCaptureWatcher() {
|
|
|
3360
3487
|
child.on("exit", (code, signal) => {
|
|
3361
3488
|
dlog(`startCaptureWatcher: child pid=${child.pid ?? "<none>"} exited code=${code} signal=${signal || "none"}`);
|
|
3362
3489
|
try {
|
|
3363
|
-
const current =
|
|
3490
|
+
const current = fs4.readFileSync(WATCHER_LOCK, "utf-8").trim();
|
|
3364
3491
|
if (current === String(child.pid))
|
|
3365
|
-
|
|
3492
|
+
fs4.unlinkSync(WATCHER_LOCK);
|
|
3366
3493
|
} catch {
|
|
3367
3494
|
}
|
|
3368
3495
|
currentChild = null;
|
|
@@ -3391,7 +3518,7 @@ function startCaptureWatcher() {
|
|
|
3391
3518
|
`
|
|
3392
3519
|
);
|
|
3393
3520
|
try {
|
|
3394
|
-
|
|
3521
|
+
fs4.unlinkSync(WATCHER_LOCK);
|
|
3395
3522
|
} catch {
|
|
3396
3523
|
}
|
|
3397
3524
|
return;
|
|
@@ -3423,7 +3550,7 @@ function startCaptureWatcher() {
|
|
|
3423
3550
|
}, 2e3).unref();
|
|
3424
3551
|
}
|
|
3425
3552
|
try {
|
|
3426
|
-
|
|
3553
|
+
fs4.unlinkSync(WATCHER_LOCK);
|
|
3427
3554
|
} catch {
|
|
3428
3555
|
}
|
|
3429
3556
|
};
|
|
@@ -3462,6 +3589,37 @@ var announcedBySession = /* @__PURE__ */ new Set();
|
|
|
3462
3589
|
var turnCountBySession = /* @__PURE__ */ new Map();
|
|
3463
3590
|
var cachedRecap = null;
|
|
3464
3591
|
var RECAP_CACHE_TTL_MS = 5 * 6e4;
|
|
3592
|
+
var cachedSkillRows = null;
|
|
3593
|
+
var SKILL_ACTIVATION_CACHE_TTL_MS = 5 * 6e4;
|
|
3594
|
+
async function fetchSkillActivation(apiKey, cwd) {
|
|
3595
|
+
const now = Date.now();
|
|
3596
|
+
if (cachedSkillRows && now - cachedSkillRows.fetchedAt < SKILL_ACTIVATION_CACHE_TTL_MS) {
|
|
3597
|
+
return activationFromApiRows({
|
|
3598
|
+
rows: cachedSkillRows.rows,
|
|
3599
|
+
platform: "opencode",
|
|
3600
|
+
cwd,
|
|
3601
|
+
homeDir: HOME
|
|
3602
|
+
});
|
|
3603
|
+
}
|
|
3604
|
+
try {
|
|
3605
|
+
const response = await fetch(`${API_URL}/v1/skillmirror`, {
|
|
3606
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3607
|
+
});
|
|
3608
|
+
if (!response.ok)
|
|
3609
|
+
return void 0;
|
|
3610
|
+
const data = await response.json();
|
|
3611
|
+
const rows = data.skills || [];
|
|
3612
|
+
cachedSkillRows = { rows, fetchedAt: now };
|
|
3613
|
+
return activationFromApiRows({
|
|
3614
|
+
rows,
|
|
3615
|
+
platform: "opencode",
|
|
3616
|
+
cwd,
|
|
3617
|
+
homeDir: HOME
|
|
3618
|
+
});
|
|
3619
|
+
} catch {
|
|
3620
|
+
return void 0;
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3465
3623
|
function startSessionRelay(sessionId, serverUrl) {
|
|
3466
3624
|
if (process.env.GREPRAG_OPENCODE_RELAY === "0")
|
|
3467
3625
|
return;
|
|
@@ -3498,11 +3656,11 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
3498
3656
|
return;
|
|
3499
3657
|
}
|
|
3500
3658
|
try {
|
|
3501
|
-
|
|
3502
|
-
|
|
3659
|
+
fs4.writeSync(claim.fd, String(process.pid));
|
|
3660
|
+
fs4.closeSync(claim.fd);
|
|
3503
3661
|
} catch {
|
|
3504
3662
|
try {
|
|
3505
|
-
|
|
3663
|
+
fs4.unlinkSync(lockPath);
|
|
3506
3664
|
} catch {
|
|
3507
3665
|
}
|
|
3508
3666
|
return;
|
|
@@ -3517,11 +3675,11 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
3517
3675
|
const claim2 = tryClaimRelayLock(lockPath);
|
|
3518
3676
|
if (claim2.ok) {
|
|
3519
3677
|
try {
|
|
3520
|
-
|
|
3521
|
-
|
|
3678
|
+
fs4.writeSync(claim2.fd, String(process.pid));
|
|
3679
|
+
fs4.closeSync(claim2.fd);
|
|
3522
3680
|
} catch {
|
|
3523
3681
|
try {
|
|
3524
|
-
|
|
3682
|
+
fs4.unlinkSync(lockPath);
|
|
3525
3683
|
} catch {
|
|
3526
3684
|
}
|
|
3527
3685
|
return false;
|
|
@@ -3557,7 +3715,7 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
3557
3715
|
childStartTime = Date.now();
|
|
3558
3716
|
dlog(`startSessionRelay: spawned 'greprag opencode relay' pid=${child.pid ?? "<none>"}`);
|
|
3559
3717
|
try {
|
|
3560
|
-
|
|
3718
|
+
fs4.writeFileSync(lockPath, String(child.pid));
|
|
3561
3719
|
} catch {
|
|
3562
3720
|
}
|
|
3563
3721
|
child.stderr?.on("data", (chunk2) => {
|
|
@@ -3568,9 +3726,9 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
3568
3726
|
});
|
|
3569
3727
|
child.on("exit", (code, signal) => {
|
|
3570
3728
|
try {
|
|
3571
|
-
const current =
|
|
3729
|
+
const current = fs4.readFileSync(lockPath, "utf-8").trim();
|
|
3572
3730
|
if (current === String(child.pid))
|
|
3573
|
-
|
|
3731
|
+
fs4.unlinkSync(lockPath);
|
|
3574
3732
|
} catch {
|
|
3575
3733
|
}
|
|
3576
3734
|
currentChild = null;
|
|
@@ -3597,7 +3755,7 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
3597
3755
|
`
|
|
3598
3756
|
);
|
|
3599
3757
|
try {
|
|
3600
|
-
|
|
3758
|
+
fs4.unlinkSync(lockPath);
|
|
3601
3759
|
} catch {
|
|
3602
3760
|
}
|
|
3603
3761
|
return;
|
|
@@ -3629,7 +3787,7 @@ function startSessionRelay(sessionId, serverUrl) {
|
|
|
3629
3787
|
}, 2e3).unref();
|
|
3630
3788
|
}
|
|
3631
3789
|
try {
|
|
3632
|
-
|
|
3790
|
+
fs4.unlinkSync(lockPath);
|
|
3633
3791
|
} catch {
|
|
3634
3792
|
}
|
|
3635
3793
|
};
|
|
@@ -3745,7 +3903,9 @@ var GrepRAGMemoryPlugin = async (ctx) => {
|
|
|
3745
3903
|
if (sid && !relayArmedBySession.has(sid)) {
|
|
3746
3904
|
startSessionRelay(sid, ctx.serverUrl.toString());
|
|
3747
3905
|
}
|
|
3748
|
-
const
|
|
3906
|
+
const sessionContext = sid ? await resolveSessionContext(sid) : { anchor: fallbackAnchor, workingDir: fallbackWorkingDir };
|
|
3907
|
+
const anchor = sessionContext.anchor;
|
|
3908
|
+
const workingDir = sessionContext.workingDir;
|
|
3749
3909
|
let body;
|
|
3750
3910
|
if (cachedRecap && cachedRecap.projectId === anchor.projectId && Date.now() - cachedRecap.fetchedAt < RECAP_CACHE_TTL_MS) {
|
|
3751
3911
|
body = cachedRecap.body;
|
|
@@ -3806,7 +3966,8 @@ ALWAYS pass \`--from-session ${sid82}\` when you run \`greprag send\`, so recipi
|
|
|
3806
3966
|
} catch {
|
|
3807
3967
|
return [];
|
|
3808
3968
|
}
|
|
3809
|
-
})()
|
|
3969
|
+
})(),
|
|
3970
|
+
mirroredSkills: !announcedBySession.has(sid8) ? await fetchSkillActivation(apiKey, workingDir) : void 0
|
|
3810
3971
|
});
|
|
3811
3972
|
if (!announcedBySession.has(sid8)) {
|
|
3812
3973
|
announcedBySession.add(sid8);
|
package/dist/opencode-plugin.js
CHANGED
|
@@ -100,6 +100,7 @@ const opencode_plugin_crush_1 = require("./opencode-plugin-crush");
|
|
|
100
100
|
const opencode_interrupt_1 = require("./commands/opencode-interrupt");
|
|
101
101
|
const procedure_1 = require("./procedure");
|
|
102
102
|
const opencode_plugin_png_1 = require("./opencode-plugin-png");
|
|
103
|
+
const skill_activation_manifest_1 = require("./skill-activation-manifest");
|
|
103
104
|
// ============================================================================
|
|
104
105
|
// File-based debug log. opencode's plugin loader (Bun) does NOT route plugin
|
|
105
106
|
// stderr into the opencode log file at ~/.local/share/opencode/log/*.log —
|
|
@@ -560,6 +561,35 @@ const turnCountBySession = new Map();
|
|
|
560
561
|
* every LLM call — small enough to be cheap, big enough to be useful. */
|
|
561
562
|
let cachedRecap = null;
|
|
562
563
|
const RECAP_CACHE_TTL_MS = 5 * 60_000;
|
|
564
|
+
let cachedSkillRows = null;
|
|
565
|
+
const SKILL_ACTIVATION_CACHE_TTL_MS = 5 * 60_000;
|
|
566
|
+
async function fetchSkillActivation(apiKey, cwd) {
|
|
567
|
+
const now = Date.now();
|
|
568
|
+
if (cachedSkillRows && now - cachedSkillRows.fetchedAt < SKILL_ACTIVATION_CACHE_TTL_MS) {
|
|
569
|
+
return (0, skill_activation_manifest_1.activationFromApiRows)({
|
|
570
|
+
rows: cachedSkillRows.rows, platform: 'opencode', cwd, homeDir: opencode_plugin_helpers_1.HOME,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
try {
|
|
574
|
+
const response = await fetch(`${API_URL}/v1/skillmirror`, {
|
|
575
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
576
|
+
});
|
|
577
|
+
if (!response.ok)
|
|
578
|
+
return undefined;
|
|
579
|
+
const data = await response.json();
|
|
580
|
+
const rows = data.skills || [];
|
|
581
|
+
cachedSkillRows = { rows, fetchedAt: now };
|
|
582
|
+
return (0, skill_activation_manifest_1.activationFromApiRows)({
|
|
583
|
+
rows,
|
|
584
|
+
platform: 'opencode',
|
|
585
|
+
cwd,
|
|
586
|
+
homeDir: opencode_plugin_helpers_1.HOME,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
return undefined;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
563
593
|
// ============================================================================
|
|
564
594
|
// Per-session relay spawner — "anytime opencode is opened and being used"
|
|
565
595
|
// ============================================================================
|
|
@@ -895,7 +925,11 @@ const GrepRAGMemoryPlugin = async (ctx) => {
|
|
|
895
925
|
// Resolve anchor — the session's directory is canonical,
|
|
896
926
|
// fallbackAnchor is the closure's boot-time directory (used when sid
|
|
897
927
|
// is absent)
|
|
898
|
-
const
|
|
928
|
+
const sessionContext = sid
|
|
929
|
+
? await resolveSessionContext(sid)
|
|
930
|
+
: { anchor: fallbackAnchor, workingDir: fallbackWorkingDir };
|
|
931
|
+
const anchor = sessionContext.anchor;
|
|
932
|
+
const workingDir = sessionContext.workingDir;
|
|
899
933
|
// Recap body is per-project (not per-session) and changes slowly, so
|
|
900
934
|
// we cache it. Push on every fire so the LLM sees the recap in ALL
|
|
901
935
|
// turns, not just the first. See module-level `cachedRecap` comment
|
|
@@ -975,6 +1009,9 @@ const GrepRAGMemoryPlugin = async (ctx) => {
|
|
|
975
1009
|
return [];
|
|
976
1010
|
}
|
|
977
1011
|
})(),
|
|
1012
|
+
mirroredSkills: !announcedBySession.has(sid8)
|
|
1013
|
+
? await fetchSkillActivation(apiKey, workingDir)
|
|
1014
|
+
: undefined,
|
|
978
1015
|
});
|
|
979
1016
|
// Announces: inject on first fire per session (static primers)
|
|
980
1017
|
if (!announcedBySession.has(sid8)) {
|