@jcode.labs/ragmir 2.10.0 → 2.12.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/README.md +12 -1
- package/dist/chunk-stats.d.ts +8 -0
- package/dist/chunk-stats.d.ts.map +1 -0
- package/dist/chunk-stats.js +31 -0
- package/dist/chunk-stats.js.map +1 -0
- package/dist/cli.js +125 -8
- package/dist/cli.js.map +1 -1
- package/dist/context-resources.d.ts +4 -0
- package/dist/context-resources.d.ts.map +1 -0
- package/dist/context-resources.js +87 -0
- package/dist/context-resources.js.map +1 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +15 -4
- package/dist/doctor.js.map +1 -1
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/evaluate.js +8 -0
- package/dist/evaluate.js.map +1 -1
- package/dist/gitignore.d.ts +1 -1
- package/dist/gitignore.d.ts.map +1 -1
- package/dist/gitignore.js +3 -2
- package/dist/gitignore.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/ingest.d.ts.map +1 -1
- package/dist/ingest.js +7 -1
- package/dist/ingest.js.map +1 -1
- package/dist/knowledge-bases.d.ts +4 -0
- package/dist/knowledge-bases.d.ts.map +1 -0
- package/dist/knowledge-bases.js +113 -0
- package/dist/knowledge-bases.js.map +1 -0
- package/dist/mcp.d.ts +3 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +38 -7
- package/dist/mcp.js.map +1 -1
- package/dist/package-manager.d.ts +2 -0
- package/dist/package-manager.d.ts.map +1 -1
- package/dist/package-manager.js +18 -1
- package/dist/package-manager.js.map +1 -1
- package/dist/preview.d.ts +3 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +115 -0
- package/dist/preview.js.map +1 -0
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +70 -21
- package/dist/query.js.map +1 -1
- package/dist/research.d.ts.map +1 -1
- package/dist/research.js +2 -0
- package/dist/research.js.map +1 -1
- package/dist/setup.d.ts +3 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +10 -5
- package/dist/setup.js.map +1 -1
- package/dist/skill.d.ts +16 -3
- package/dist/skill.d.ts.map +1 -1
- package/dist/skill.js +319 -20
- package/dist/skill.js.map +1 -1
- package/dist/types.d.ts +142 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/skills/ragmir/SKILL.md +28 -0
package/dist/setup.js
CHANGED
|
@@ -6,10 +6,10 @@ import { ingest } from "./ingest.js";
|
|
|
6
6
|
import { initProject } from "./init.js";
|
|
7
7
|
import { rgrCommand } from "./package-manager.js";
|
|
8
8
|
import { enableSemanticEmbeddings } from "./semantic-config.js";
|
|
9
|
-
import {
|
|
9
|
+
import { installAgentSkills, } from "./skill.js";
|
|
10
10
|
const CONFIGURATION_PROMPT = `You are helping configure Ragmir for this repository.
|
|
11
11
|
|
|
12
|
-
Work from the
|
|
12
|
+
Work from the knowledge-base root where \`rgr setup\` was run. Your goal is to improve \`.ragmir/config.json\` so Ragmir indexes useful repository knowledge without indexing secrets, generated files, or noisy bulk data. In a monorepo with nested Ragmir bases, keep an app base scoped to that app; only the root base should index shared or cross-app knowledge.
|
|
13
13
|
|
|
14
14
|
Tasks:
|
|
15
15
|
1. Inspect the repository structure and the current \`.ragmir/config.json\`.
|
|
@@ -24,7 +24,7 @@ Keep all proposed paths relative to the repository root. Do not add secrets or p
|
|
|
24
24
|
export async function setupProject(options = {}) {
|
|
25
25
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
26
26
|
const created = await initProject(cwd);
|
|
27
|
-
const installOptions = { cwd };
|
|
27
|
+
const installOptions = { cwd, scope: "project", mode: "link" };
|
|
28
28
|
if (options.targetDir !== undefined) {
|
|
29
29
|
installOptions.targetDir = options.targetDir;
|
|
30
30
|
}
|
|
@@ -40,7 +40,11 @@ export async function setupProject(options = {}) {
|
|
|
40
40
|
if (options.mcpArgs !== undefined) {
|
|
41
41
|
installOptions.mcpArgs = options.mcpArgs;
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
if (options.forceAgentSkills !== undefined) {
|
|
44
|
+
installOptions.force = options.forceAgentSkills;
|
|
45
|
+
}
|
|
46
|
+
const agentSkills = await installAgentSkills(installOptions);
|
|
47
|
+
const agentKit = agentSkills.projectKit;
|
|
44
48
|
const semantic = options.semantic ? await setupSemanticEmbeddings(cwd) : null;
|
|
45
49
|
let report = await doctor(cwd);
|
|
46
50
|
let ingested = null;
|
|
@@ -55,6 +59,7 @@ export async function setupProject(options = {}) {
|
|
|
55
59
|
runCommand: command.display,
|
|
56
60
|
created,
|
|
57
61
|
agentKit,
|
|
62
|
+
agentInstallations: agentSkills.installations,
|
|
58
63
|
semantic,
|
|
59
64
|
ingested,
|
|
60
65
|
doctor: report,
|
|
@@ -80,7 +85,7 @@ function setupNextSteps(report) {
|
|
|
80
85
|
if (report.ready) {
|
|
81
86
|
return [
|
|
82
87
|
"Ask questions with the search or ask command shown by `rgr doctor`.",
|
|
83
|
-
"
|
|
88
|
+
"Restart or reload the selected agents so they discover the installed Ragmir skills.",
|
|
84
89
|
"Wire the matching MCP helper from .ragmir/ when the agent should call Ragmir tools directly.",
|
|
85
90
|
];
|
|
86
91
|
}
|
package/dist/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAiC,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAuB,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtE,OAAO,EAAuC,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AACpG,OAAO,
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/dist/skill.d.ts
CHANGED
|
@@ -22,19 +22,19 @@ export interface InstallSkillResult {
|
|
|
22
22
|
clineConfigPath: string;
|
|
23
23
|
agentSetupPath: string;
|
|
24
24
|
readmePath: string;
|
|
25
|
+
runnerPath: string;
|
|
25
26
|
agentHelpers: AgentHelperFile[];
|
|
26
27
|
mcpServerName: string;
|
|
27
28
|
mcpCommand: string;
|
|
28
29
|
mcpArgs: string[];
|
|
29
30
|
written: string[];
|
|
30
31
|
}
|
|
31
|
-
export interface InstallAgentSkillsOptions {
|
|
32
|
-
cwd?: string;
|
|
33
|
-
agents?: readonly AgentTarget[];
|
|
32
|
+
export interface InstallAgentSkillsOptions extends InstallSkillOptions {
|
|
34
33
|
scope?: AgentInstallScope;
|
|
35
34
|
mode?: AgentInstallMode;
|
|
36
35
|
homeDir?: string;
|
|
37
36
|
env?: Record<string, string | undefined>;
|
|
37
|
+
force?: boolean;
|
|
38
38
|
}
|
|
39
39
|
export interface AgentSkillInstallation {
|
|
40
40
|
agent: AgentTarget;
|
|
@@ -54,6 +54,18 @@ export interface AgentHelperFile {
|
|
|
54
54
|
label: string;
|
|
55
55
|
path: string;
|
|
56
56
|
}
|
|
57
|
+
export type RagmirRunnerMode = "local-bin" | "workspace" | "installed-package" | "npm-cache";
|
|
58
|
+
export interface AgentIntegrationReport {
|
|
59
|
+
runnerPath: string;
|
|
60
|
+
runnerReady: boolean;
|
|
61
|
+
runnerMode: RagmirRunnerMode | null;
|
|
62
|
+
runnerRequiresDownload: boolean;
|
|
63
|
+
projectAgents: AgentTarget[];
|
|
64
|
+
userAgents: AgentTarget[];
|
|
65
|
+
nativeAgents: AgentTarget[];
|
|
66
|
+
ready: boolean;
|
|
67
|
+
warnings: string[];
|
|
68
|
+
}
|
|
57
69
|
export declare const SKILL_NAMES: readonly ["ragmir", "ragmir-audio-summary", "ragmir-markdown-report", "ragmir-legal-dossier"];
|
|
58
70
|
export declare const MCP_CONFIG_FILENAME = "mcp.json";
|
|
59
71
|
export declare const AGENT_SETUP_FILENAME = "agent-setup.md";
|
|
@@ -63,4 +75,5 @@ export declare function bundledSkillPath(skillName?: string): string;
|
|
|
63
75
|
export declare function parseAgentTargets(value: string | readonly string[] | undefined): AgentTarget[];
|
|
64
76
|
export declare function installSkill(options?: InstallSkillOptions): Promise<InstallSkillResult>;
|
|
65
77
|
export declare function installAgentSkills(options?: InstallAgentSkillsOptions): Promise<InstallAgentSkillsResult>;
|
|
78
|
+
export declare function inspectAgentIntegration(cwd?: string, homeDir?: string, env?: Record<string, string | undefined>): AgentIntegrationReport;
|
|
66
79
|
//# sourceMappingURL=skill.d.ts.map
|
package/dist/skill.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"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"}
|
package/dist/skill.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { cp, lstat, mkdir, readFile, realpath, rm, symlink, writeFile } from "node:fs/promises";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import { fileURLToPath } from "node:url";
|
|
4
6
|
import { DEFAULT_SKILL_TARGET_DIR, RAGMIR_DIR, RAGMIR_PROJECT_ROOT_ENV } from "./defaults.js";
|
|
5
7
|
import { ensureRagmirGitignore } from "./gitignore.js";
|
|
6
|
-
import {
|
|
8
|
+
import { knowledgeBaseIdentity } from "./knowledge-bases.js";
|
|
9
|
+
import { RGR_RUNNER_FILENAME, RGR_RUNNER_PROBE_ARG, rgrCommand, } from "./package-manager.js";
|
|
10
|
+
import { VERSION } from "./version.js";
|
|
7
11
|
const PACKAGE_ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
8
12
|
const PRIMARY_SKILL_NAME = "ragmir";
|
|
9
13
|
const AUDIO_SKILL_NAME = "ragmir-audio-summary";
|
|
@@ -11,6 +15,7 @@ const REPORT_SKILL_NAME = "ragmir-markdown-report";
|
|
|
11
15
|
const LEGAL_SKILL_NAME = "ragmir-legal-dossier";
|
|
12
16
|
const DEFAULT_MCP_SERVER_NAME = "ragmir";
|
|
13
17
|
const MCP_SERVER_NAME_PATTERN = /^[A-Za-z0-9_-]+$/u;
|
|
18
|
+
const MANAGED_SKILL_METADATA_FILENAME = ".ragmir-managed.json";
|
|
14
19
|
export const SKILL_NAMES = [
|
|
15
20
|
PRIMARY_SKILL_NAME,
|
|
16
21
|
AUDIO_SKILL_NAME,
|
|
@@ -53,8 +58,8 @@ const AGENT_DESTINATIONS = {
|
|
|
53
58
|
codex: {
|
|
54
59
|
label: "Codex",
|
|
55
60
|
env: "CODEX_SKILLS_DIR",
|
|
56
|
-
projectDir: path.join(".
|
|
57
|
-
userDir: (homeDir) => path.join(homeDir, ".
|
|
61
|
+
projectDir: path.join(".agents", "skills"),
|
|
62
|
+
userDir: (homeDir) => path.join(homeDir, ".agents", "skills"),
|
|
58
63
|
},
|
|
59
64
|
kimi: {
|
|
60
65
|
label: "Kimi Code CLI",
|
|
@@ -105,7 +110,7 @@ export async function installSkill(options = {}) {
|
|
|
105
110
|
const targetDir = path.resolve(cwd, options.targetDir ?? DEFAULT_SKILL_TARGET_DIR);
|
|
106
111
|
const agents = options.agents ? parseAgentTargets(options.agents) : [...SUPPORTED_AGENT_TARGETS];
|
|
107
112
|
const agentSet = new Set(agents);
|
|
108
|
-
const mcpServerName = normalizeMcpServerName(options.mcpServerName);
|
|
113
|
+
const mcpServerName = normalizeMcpServerName(options.mcpServerName ?? suggestedMcpServerName(cwd));
|
|
109
114
|
const skillPath = path.join(targetDir, PRIMARY_SKILL_NAME);
|
|
110
115
|
const audioSkillPath = path.join(targetDir, AUDIO_SKILL_NAME);
|
|
111
116
|
const reportSkillPath = path.join(targetDir, REPORT_SKILL_NAME);
|
|
@@ -126,13 +131,15 @@ export async function installSkill(options = {}) {
|
|
|
126
131
|
const clineConfigPath = agentConfigPaths.cline;
|
|
127
132
|
const agentSetupPath = path.join(ragmirDir, AGENT_SETUP_FILENAME);
|
|
128
133
|
const readmePath = path.join(ragmirDir, "README.md");
|
|
134
|
+
const runnerPath = path.join(ragmirDir, RGR_RUNNER_FILENAME);
|
|
129
135
|
await mkdir(targetDir, { recursive: true });
|
|
130
136
|
await mkdir(ragmirDir, { recursive: true });
|
|
131
137
|
await copyBundledSkills(targetDir);
|
|
138
|
+
await writeFile(runnerPath, ragmirRunnerSource(VERSION, path.join(PACKAGE_ROOT, "dist", "cli.js")), { encoding: "utf8", mode: 0o755 });
|
|
132
139
|
const serveCommand = await resolveMcpCommand(cwd, options);
|
|
133
140
|
const doctorCommand = await rgrCommand(cwd, ["doctor"]);
|
|
134
141
|
const installAgentCommand = await rgrCommand(cwd, ["install-agent", "--agents", agents.join(",")]);
|
|
135
|
-
await writeFile(mcpConfigPath, `${JSON.stringify(mcpConfig(cwd, serveCommand,
|
|
142
|
+
await writeFile(mcpConfigPath, `${JSON.stringify(mcpConfig(cwd, serveCommand, { [RAGMIR_PROJECT_ROOT_ENV]: cwd }, mcpServerName), null, 2)}\n`, "utf8");
|
|
136
143
|
const agentHelpers = [];
|
|
137
144
|
for (const agent of SUPPORTED_AGENT_TARGETS) {
|
|
138
145
|
const helperPath = agentConfigPaths[agent];
|
|
@@ -197,6 +204,7 @@ export async function installSkill(options = {}) {
|
|
|
197
204
|
path.relative(cwd, audioSkillPath),
|
|
198
205
|
path.relative(cwd, reportSkillPath),
|
|
199
206
|
path.relative(cwd, legalSkillPath),
|
|
207
|
+
path.relative(cwd, runnerPath),
|
|
200
208
|
path.relative(cwd, mcpConfigPath),
|
|
201
209
|
...agentHelpers.map((helper) => path.relative(cwd, helper.path)),
|
|
202
210
|
path.relative(cwd, agentSetupPath),
|
|
@@ -218,6 +226,7 @@ export async function installSkill(options = {}) {
|
|
|
218
226
|
clineConfigPath,
|
|
219
227
|
agentSetupPath,
|
|
220
228
|
readmePath,
|
|
229
|
+
runnerPath,
|
|
221
230
|
agentHelpers,
|
|
222
231
|
mcpServerName,
|
|
223
232
|
mcpCommand: serveCommand.command,
|
|
@@ -232,7 +241,16 @@ export async function installAgentSkills(options = {}) {
|
|
|
232
241
|
const homeDir = path.resolve(options.homeDir ?? process.env.HOME ?? process.cwd());
|
|
233
242
|
const env = options.env ?? process.env;
|
|
234
243
|
const agents = options.agents ?? SUPPORTED_AGENT_TARGETS;
|
|
235
|
-
const
|
|
244
|
+
const installOptions = { cwd, agents };
|
|
245
|
+
if (options.targetDir !== undefined)
|
|
246
|
+
installOptions.targetDir = options.targetDir;
|
|
247
|
+
if (options.mcpServerName !== undefined)
|
|
248
|
+
installOptions.mcpServerName = options.mcpServerName;
|
|
249
|
+
if (options.mcpCommand !== undefined)
|
|
250
|
+
installOptions.mcpCommand = options.mcpCommand;
|
|
251
|
+
if (options.mcpArgs !== undefined)
|
|
252
|
+
installOptions.mcpArgs = options.mcpArgs;
|
|
253
|
+
const projectKit = await installSkill(installOptions);
|
|
236
254
|
const sourceDir = path.dirname(projectKit.skillPath);
|
|
237
255
|
const installations = [];
|
|
238
256
|
const written = [];
|
|
@@ -240,7 +258,7 @@ export async function installAgentSkills(options = {}) {
|
|
|
240
258
|
const destination = AGENT_DESTINATIONS[agent];
|
|
241
259
|
const targetDir = agentTargetDir(agent, scope, cwd, homeDir, env);
|
|
242
260
|
await mkdir(targetDir, { recursive: true });
|
|
243
|
-
const { mode, skillPaths } = await exposeAgentSkills(sourceDir, targetDir, requestedMode);
|
|
261
|
+
const { mode, skillPaths } = await exposeAgentSkills(sourceDir, targetDir, requestedMode, options.force ?? false);
|
|
244
262
|
written.push(...skillPaths.map((skillPath) => displayPath(cwd, skillPath)));
|
|
245
263
|
installations.push({
|
|
246
264
|
agent,
|
|
@@ -251,6 +269,15 @@ export async function installAgentSkills(options = {}) {
|
|
|
251
269
|
skillPaths,
|
|
252
270
|
});
|
|
253
271
|
}
|
|
272
|
+
if (scope === "project") {
|
|
273
|
+
const gitignoreEntries = installations.flatMap((installation) => installation.skillPaths.map((skillPath) => posixRelativePath(cwd, skillPath)));
|
|
274
|
+
if (await ensureRagmirGitignore(cwd, gitignoreEntries)) {
|
|
275
|
+
if (!projectKit.written.includes(".gitignore")) {
|
|
276
|
+
projectKit.written.push(".gitignore");
|
|
277
|
+
}
|
|
278
|
+
written.push(".gitignore");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
254
281
|
return {
|
|
255
282
|
projectKit,
|
|
256
283
|
installations,
|
|
@@ -282,10 +309,46 @@ function normalizeMcpServerName(value) {
|
|
|
282
309
|
}
|
|
283
310
|
return name;
|
|
284
311
|
}
|
|
312
|
+
function suggestedMcpServerName(cwd) {
|
|
313
|
+
const identity = knowledgeBaseIdentity(cwd);
|
|
314
|
+
if (!identity || identity.id === ".") {
|
|
315
|
+
return DEFAULT_MCP_SERVER_NAME;
|
|
316
|
+
}
|
|
317
|
+
const suffix = sanitizeMcpServerSuffix(identity.id);
|
|
318
|
+
return suffix ? `${DEFAULT_MCP_SERVER_NAME}-${suffix}` : DEFAULT_MCP_SERVER_NAME;
|
|
319
|
+
}
|
|
320
|
+
function sanitizeMcpServerSuffix(value) {
|
|
321
|
+
let suffix = "";
|
|
322
|
+
let replacingInvalidRun = false;
|
|
323
|
+
for (const character of value.toLowerCase()) {
|
|
324
|
+
const code = character.charCodeAt(0);
|
|
325
|
+
const allowed = (code >= 97 && code <= 122) ||
|
|
326
|
+
(code >= 48 && code <= 57) ||
|
|
327
|
+
character === "_" ||
|
|
328
|
+
character === "-";
|
|
329
|
+
if (allowed) {
|
|
330
|
+
suffix += character;
|
|
331
|
+
replacingInvalidRun = false;
|
|
332
|
+
}
|
|
333
|
+
else if (!replacingInvalidRun) {
|
|
334
|
+
suffix += "-";
|
|
335
|
+
replacingInvalidRun = true;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
let start = 0;
|
|
339
|
+
let end = suffix.length;
|
|
340
|
+
while (start < end && suffix[start] === "-") {
|
|
341
|
+
start += 1;
|
|
342
|
+
}
|
|
343
|
+
while (end > start && suffix[end - 1] === "-") {
|
|
344
|
+
end -= 1;
|
|
345
|
+
}
|
|
346
|
+
return suffix.slice(start, end);
|
|
347
|
+
}
|
|
285
348
|
async function writeAgentMcpHelper(agent, input) {
|
|
286
349
|
switch (agent) {
|
|
287
350
|
case "claude":
|
|
288
|
-
await writeFile(input.claudeConfigPath, `${JSON.stringify(claudeMcpServer(input.serveCommand), null, 2)}\n`, "utf8");
|
|
351
|
+
await writeFile(input.claudeConfigPath, `${JSON.stringify(claudeMcpServer(input.cwd, input.serveCommand), null, 2)}\n`, "utf8");
|
|
289
352
|
return;
|
|
290
353
|
case "codex":
|
|
291
354
|
await writeFile(input.codexConfigPath, codexMcpConfig(input.cwd, input.serveCommand, input.mcpServerName), "utf8");
|
|
@@ -304,45 +367,96 @@ async function copyBundledSkills(targetDir) {
|
|
|
304
367
|
force: true,
|
|
305
368
|
})));
|
|
306
369
|
}
|
|
307
|
-
async function exposeAgentSkills(sourceDir, targetDir, requestedMode) {
|
|
370
|
+
async function exposeAgentSkills(sourceDir, targetDir, requestedMode, force) {
|
|
308
371
|
if (requestedMode === "copy") {
|
|
309
|
-
return copyAgentSkills(sourceDir, targetDir);
|
|
372
|
+
return copyAgentSkills(sourceDir, targetDir, force);
|
|
310
373
|
}
|
|
311
374
|
try {
|
|
312
|
-
return await linkAgentSkills(sourceDir, targetDir);
|
|
375
|
+
return await linkAgentSkills(sourceDir, targetDir, force);
|
|
313
376
|
}
|
|
314
377
|
catch {
|
|
315
|
-
return copyAgentSkills(sourceDir, targetDir);
|
|
378
|
+
return copyAgentSkills(sourceDir, targetDir, force);
|
|
316
379
|
}
|
|
317
380
|
}
|
|
318
|
-
async function linkAgentSkills(sourceDir, targetDir) {
|
|
381
|
+
async function linkAgentSkills(sourceDir, targetDir, force) {
|
|
319
382
|
const skillPaths = [];
|
|
320
383
|
for (const skillName of SKILL_NAMES) {
|
|
321
384
|
const source = path.join(sourceDir, skillName);
|
|
322
385
|
const target = path.join(targetDir, skillName);
|
|
323
|
-
await replaceWithDirectorySymlink(source, target);
|
|
386
|
+
await replaceWithDirectorySymlink(source, target, skillName, force);
|
|
324
387
|
skillPaths.push(target);
|
|
325
388
|
}
|
|
326
389
|
return { mode: "link", skillPaths };
|
|
327
390
|
}
|
|
328
|
-
async function copyAgentSkills(sourceDir, targetDir) {
|
|
391
|
+
async function copyAgentSkills(sourceDir, targetDir, force) {
|
|
329
392
|
const skillPaths = [];
|
|
330
393
|
for (const skillName of SKILL_NAMES) {
|
|
331
394
|
const source = path.join(sourceDir, skillName);
|
|
332
395
|
const target = path.join(targetDir, skillName);
|
|
396
|
+
await assertManagedSkillTarget(source, target, skillName, force);
|
|
333
397
|
await rm(target, { recursive: true, force: true });
|
|
334
398
|
await cp(source, target, { recursive: true, force: true });
|
|
399
|
+
await writeFile(path.join(target, MANAGED_SKILL_METADATA_FILENAME), `${JSON.stringify({ managedBy: "ragmir", skillName }, null, 2)}\n`, "utf8");
|
|
335
400
|
skillPaths.push(target);
|
|
336
401
|
}
|
|
337
402
|
return { mode: "copy", skillPaths };
|
|
338
403
|
}
|
|
339
|
-
async function replaceWithDirectorySymlink(source, target) {
|
|
404
|
+
async function replaceWithDirectorySymlink(source, target, skillName, force) {
|
|
340
405
|
if (path.resolve(source) === path.resolve(target)) {
|
|
341
406
|
return;
|
|
342
407
|
}
|
|
408
|
+
await assertManagedSkillTarget(source, target, skillName, force);
|
|
343
409
|
await rm(target, { recursive: true, force: true });
|
|
344
410
|
await symlink(source, target, process.platform === "win32" ? "junction" : "dir");
|
|
345
411
|
}
|
|
412
|
+
async function assertManagedSkillTarget(source, target, skillName, force) {
|
|
413
|
+
let targetStats;
|
|
414
|
+
try {
|
|
415
|
+
targetStats = await lstat(target);
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
if (hasErrorCode(error, "ENOENT"))
|
|
419
|
+
return;
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
if (force)
|
|
423
|
+
return;
|
|
424
|
+
if (targetStats.isSymbolicLink()) {
|
|
425
|
+
try {
|
|
426
|
+
if ((await realpath(target)) === (await realpath(source)))
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
// A broken or unreadable link is not safe to replace implicitly.
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
else if (targetStats.isDirectory()) {
|
|
434
|
+
const metadata = await readManagedSkillMetadata(target);
|
|
435
|
+
if (metadata?.managedBy === "ragmir" && metadata.skillName === skillName)
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
throw new Error(`Refusing to replace unmanaged agent skill at ${target}. Move it, or rerun with --force after reviewing its contents.`);
|
|
439
|
+
}
|
|
440
|
+
async function readManagedSkillMetadata(target) {
|
|
441
|
+
try {
|
|
442
|
+
const value = JSON.parse(await readFile(path.join(target, MANAGED_SKILL_METADATA_FILENAME), "utf8"));
|
|
443
|
+
if (typeof value === "object" &&
|
|
444
|
+
value !== null &&
|
|
445
|
+
"managedBy" in value &&
|
|
446
|
+
typeof value.managedBy === "string" &&
|
|
447
|
+
"skillName" in value &&
|
|
448
|
+
typeof value.skillName === "string") {
|
|
449
|
+
return { managedBy: value.managedBy, skillName: value.skillName };
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
function hasErrorCode(error, code) {
|
|
458
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
459
|
+
}
|
|
346
460
|
function agentTargetDir(agent, scope, cwd, homeDir, env) {
|
|
347
461
|
const destination = AGENT_DESTINATIONS[agent];
|
|
348
462
|
const override = env[destination.env];
|
|
@@ -370,6 +484,185 @@ function displayPath(cwd, filePath) {
|
|
|
370
484
|
}
|
|
371
485
|
return filePath;
|
|
372
486
|
}
|
|
487
|
+
function posixRelativePath(cwd, filePath) {
|
|
488
|
+
return path.relative(cwd, filePath).split(path.sep).join("/");
|
|
489
|
+
}
|
|
490
|
+
export function inspectAgentIntegration(cwd = process.cwd(), homeDir = process.env.HOME ?? process.cwd(), env = process.env) {
|
|
491
|
+
const projectRoot = path.resolve(cwd);
|
|
492
|
+
const resolvedHome = path.resolve(homeDir);
|
|
493
|
+
const runnerPath = path.join(projectRoot, RAGMIR_DIR, RGR_RUNNER_FILENAME);
|
|
494
|
+
const probe = probeRagmirRunner(projectRoot, runnerPath);
|
|
495
|
+
const projectAgents = detectedAgentTargets("project", projectRoot, resolvedHome, env);
|
|
496
|
+
const userAgents = detectedAgentTargets("user", projectRoot, resolvedHome, env);
|
|
497
|
+
const nativeAgents = [...new Set([...projectAgents, ...userAgents])];
|
|
498
|
+
const warnings = [];
|
|
499
|
+
if (!existsSync(runnerPath)) {
|
|
500
|
+
warnings.push("The generated Ragmir runner is missing. Run `rgr setup` or `rgr doctor --fix`.");
|
|
501
|
+
}
|
|
502
|
+
else if (!probe.runnerReady) {
|
|
503
|
+
warnings.push("The generated Ragmir runner could not verify a local CLI. Install @jcode.labs/ragmir in the project or rebuild the workspace package.");
|
|
504
|
+
}
|
|
505
|
+
if (probe.runnerRequiresDownload) {
|
|
506
|
+
warnings.push("The runner will fall back to the pinned npm package and may need a network download before first use.");
|
|
507
|
+
}
|
|
508
|
+
if (nativeAgents.length === 0) {
|
|
509
|
+
warnings.push("No native agent skill exposure was detected. Run `rgr install-agent --agents <list>`.");
|
|
510
|
+
}
|
|
511
|
+
return {
|
|
512
|
+
runnerPath,
|
|
513
|
+
runnerReady: probe.runnerReady,
|
|
514
|
+
runnerMode: probe.runnerMode,
|
|
515
|
+
runnerRequiresDownload: probe.runnerRequiresDownload,
|
|
516
|
+
projectAgents,
|
|
517
|
+
userAgents,
|
|
518
|
+
nativeAgents,
|
|
519
|
+
ready: probe.runnerReady && nativeAgents.length > 0,
|
|
520
|
+
warnings,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
function detectedAgentTargets(scope, projectRoot, homeDir, env) {
|
|
524
|
+
return SUPPORTED_AGENT_TARGETS.filter((agent) => {
|
|
525
|
+
const targetDir = agentTargetDir(agent, scope, projectRoot, homeDir, env);
|
|
526
|
+
return SKILL_NAMES.every((skillName) => existsSync(path.join(targetDir, skillName, "SKILL.md")));
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
function probeRagmirRunner(projectRoot, runnerPath) {
|
|
530
|
+
if (!existsSync(runnerPath)) {
|
|
531
|
+
return { runnerReady: false, runnerMode: null, runnerRequiresDownload: false };
|
|
532
|
+
}
|
|
533
|
+
const result = spawnSync(process.execPath, [runnerPath, RGR_RUNNER_PROBE_ARG], {
|
|
534
|
+
cwd: projectRoot,
|
|
535
|
+
encoding: "utf8",
|
|
536
|
+
timeout: 5_000,
|
|
537
|
+
env: { ...process.env, [RAGMIR_PROJECT_ROOT_ENV]: projectRoot },
|
|
538
|
+
});
|
|
539
|
+
if (result.status !== 0) {
|
|
540
|
+
return { runnerReady: false, runnerMode: null, runnerRequiresDownload: false };
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
const value = JSON.parse(result.stdout.trim());
|
|
544
|
+
if (typeof value === "object" &&
|
|
545
|
+
value !== null &&
|
|
546
|
+
"verified" in value &&
|
|
547
|
+
typeof value.verified === "boolean" &&
|
|
548
|
+
"mode" in value &&
|
|
549
|
+
isRagmirRunnerMode(value.mode) &&
|
|
550
|
+
"requiresDownload" in value &&
|
|
551
|
+
typeof value.requiresDownload === "boolean") {
|
|
552
|
+
return {
|
|
553
|
+
runnerReady: value.verified,
|
|
554
|
+
runnerMode: value.mode,
|
|
555
|
+
runnerRequiresDownload: value.requiresDownload,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch {
|
|
560
|
+
return { runnerReady: false, runnerMode: null, runnerRequiresDownload: false };
|
|
561
|
+
}
|
|
562
|
+
return { runnerReady: false, runnerMode: null, runnerRequiresDownload: false };
|
|
563
|
+
}
|
|
564
|
+
function isRagmirRunnerMode(value) {
|
|
565
|
+
return (value === "local-bin" ||
|
|
566
|
+
value === "workspace" ||
|
|
567
|
+
value === "installed-package" ||
|
|
568
|
+
value === "npm-cache");
|
|
569
|
+
}
|
|
570
|
+
function ragmirRunnerSource(version, installedCliPath) {
|
|
571
|
+
const packageSpec = `@jcode.labs/ragmir@${version}`;
|
|
572
|
+
return `#!/usr/bin/env node
|
|
573
|
+
const { spawnSync } = require("node:child_process")
|
|
574
|
+
const { existsSync, readFileSync } = require("node:fs")
|
|
575
|
+
const path = require("node:path")
|
|
576
|
+
|
|
577
|
+
const PACKAGE_SPEC = ${JSON.stringify(packageSpec)}
|
|
578
|
+
const INSTALLED_CLI = ${JSON.stringify(installedCliPath)}
|
|
579
|
+
const PROBE_ARG = ${JSON.stringify(RGR_RUNNER_PROBE_ARG)}
|
|
580
|
+
const projectRoot = path.resolve(process.env.${RAGMIR_PROJECT_ROOT_ENV} || process.cwd())
|
|
581
|
+
|
|
582
|
+
function isRagmirWorkspaceCli(cliPath) {
|
|
583
|
+
if (!existsSync(cliPath)) return false
|
|
584
|
+
try {
|
|
585
|
+
const manifestPath = path.join(path.dirname(path.dirname(cliPath)), "package.json")
|
|
586
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"))
|
|
587
|
+
return manifest.name === "@jcode.labs/ragmir"
|
|
588
|
+
} catch {
|
|
589
|
+
return false
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function resolveCommand() {
|
|
594
|
+
const localBin = path.join(
|
|
595
|
+
projectRoot,
|
|
596
|
+
"node_modules",
|
|
597
|
+
".bin",
|
|
598
|
+
process.platform === "win32" ? "rgr.cmd" : "rgr",
|
|
599
|
+
)
|
|
600
|
+
if (existsSync(localBin)) {
|
|
601
|
+
return { mode: "local-bin", command: localBin, args: [], requiresDownload: false }
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const workspaceCli = path.join(projectRoot, "packages", "ragmir-core", "dist", "cli.js")
|
|
605
|
+
if (isRagmirWorkspaceCli(workspaceCli)) {
|
|
606
|
+
return {
|
|
607
|
+
mode: "workspace",
|
|
608
|
+
command: process.execPath,
|
|
609
|
+
args: [workspaceCli],
|
|
610
|
+
requiresDownload: false,
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (isRagmirWorkspaceCli(INSTALLED_CLI)) {
|
|
615
|
+
return {
|
|
616
|
+
mode: "installed-package",
|
|
617
|
+
command: process.execPath,
|
|
618
|
+
args: [INSTALLED_CLI],
|
|
619
|
+
requiresDownload: false,
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return {
|
|
624
|
+
mode: "npm-cache",
|
|
625
|
+
command: process.platform === "win32" ? "npx.cmd" : "npx",
|
|
626
|
+
args: ["--yes", "--package", PACKAGE_SPEC, "rgr"],
|
|
627
|
+
requiresDownload: true,
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
const selected = resolveCommand()
|
|
632
|
+
const commandArgs = process.argv.slice(2)
|
|
633
|
+
|
|
634
|
+
if (commandArgs[0] === PROBE_ARG) {
|
|
635
|
+
const probeArgs = selected.mode === "npm-cache" ? ["--version"] : [...selected.args, "--version"]
|
|
636
|
+
const probe = spawnSync(selected.command, probeArgs, {
|
|
637
|
+
cwd: projectRoot,
|
|
638
|
+
stdio: "ignore",
|
|
639
|
+
env: { ...process.env, ${RAGMIR_PROJECT_ROOT_ENV}: projectRoot },
|
|
640
|
+
})
|
|
641
|
+
const available = probe.status === 0
|
|
642
|
+
console.log(
|
|
643
|
+
JSON.stringify({
|
|
644
|
+
available,
|
|
645
|
+
verified: available && selected.mode !== "npm-cache",
|
|
646
|
+
mode: selected.mode,
|
|
647
|
+
requiresDownload: selected.requiresDownload,
|
|
648
|
+
}),
|
|
649
|
+
)
|
|
650
|
+
process.exitCode = available ? 0 : 1
|
|
651
|
+
} else {
|
|
652
|
+
const result = spawnSync(selected.command, [...selected.args, ...commandArgs], {
|
|
653
|
+
cwd: projectRoot,
|
|
654
|
+
stdio: "inherit",
|
|
655
|
+
env: { ...process.env, ${RAGMIR_PROJECT_ROOT_ENV}: projectRoot },
|
|
656
|
+
})
|
|
657
|
+
if (result.error) {
|
|
658
|
+
console.error(result.error.message)
|
|
659
|
+
process.exitCode = 1
|
|
660
|
+
} else {
|
|
661
|
+
process.exitCode = result.status ?? 1
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
`;
|
|
665
|
+
}
|
|
373
666
|
function mcpConfig(cwd, serveCommand, env, serverName = DEFAULT_MCP_SERVER_NAME) {
|
|
374
667
|
const serverConfig = {
|
|
375
668
|
command: serveCommand.command,
|
|
@@ -386,11 +679,12 @@ function mcpConfig(cwd, serveCommand, env, serverName = DEFAULT_MCP_SERVER_NAME)
|
|
|
386
679
|
}
|
|
387
680
|
return config;
|
|
388
681
|
}
|
|
389
|
-
function claudeMcpServer(serveCommand) {
|
|
682
|
+
function claudeMcpServer(cwd, serveCommand) {
|
|
390
683
|
return {
|
|
391
684
|
type: "stdio",
|
|
392
685
|
command: serveCommand.command,
|
|
393
686
|
args: serveCommand.args,
|
|
687
|
+
env: { [RAGMIR_PROJECT_ROOT_ENV]: cwd },
|
|
394
688
|
};
|
|
395
689
|
}
|
|
396
690
|
function codexMcpConfig(cwd, serveCommand, serverName = DEFAULT_MCP_SERVER_NAME) {
|
|
@@ -461,6 +755,10 @@ ${input.serveCommand}
|
|
|
461
755
|
|
|
462
756
|
Use \`ragmir_route_prompt\` when an agent hook or skill needs to decide whether the current user
|
|
463
757
|
prompt should call Ragmir before answering. The router is local and does not store prompt text.`,
|
|
758
|
+
`This helper is pinned to one knowledge-base root. In a monorepo, keep the generated server name
|
|
759
|
+
\`${input.mcpServerName}\` and generate a separate helper from each nested base. Call
|
|
760
|
+
\`ragmir_status\` and verify \`knowledgeBaseId\` before retrieval when the active base is unclear.`,
|
|
761
|
+
"Read `ragmir://context` for bounded base identity, readiness, freshness, and capabilities. Read `ragmir://sources` only when source coverage or index drift matters.",
|
|
464
762
|
];
|
|
465
763
|
if (hasAgentHelper(input, "claude")) {
|
|
466
764
|
sections.push(`Claude Code local MCP setup:
|
|
@@ -616,7 +914,7 @@ Default project-scope targets:
|
|
|
616
914
|
| Agent | Project skill directory | User skill directory |
|
|
617
915
|
| --- | --- | --- |
|
|
618
916
|
| Claude Code | \`.claude/skills/\` | \`~/.claude/skills/\` |
|
|
619
|
-
| Codex | \`.
|
|
917
|
+
| Codex | \`.agents/skills/\` | \`~/.agents/skills/\` |
|
|
620
918
|
| Kimi Code CLI | \`.kimi/skills/\` | \`~/.kimi/skills/\` |
|
|
621
919
|
| OpenCode | \`.opencode/skills/\` | \`~/.config/opencode/skills/\` |
|
|
622
920
|
| Cline | \`.cline/skills/\` | \`~/.cline/skills/\` |
|
|
@@ -625,7 +923,8 @@ Override paths with \`CLAUDE_SKILLS_DIR\`, \`CODEX_SKILLS_DIR\`, \`KIMI_SKILLS_D
|
|
|
625
923
|
\`OPENCODE_SKILLS_DIR\`, or \`CLINE_SKILLS_DIR\`.
|
|
626
924
|
|
|
627
925
|
Use \`--mode copy\` only when an agent runtime does not follow symlinked skill directories. When using
|
|
628
|
-
copy mode, rerun \`install-agent\` after refreshing \`.ragmir/skills/\`.
|
|
926
|
+
copy mode, rerun \`install-agent\` after refreshing \`.ragmir/skills/\`. Ragmir refuses to replace
|
|
927
|
+
an unmanaged same-name skill by default; use \`--force\` only after reviewing that existing folder.
|
|
629
928
|
|
|
630
929
|
## Skill Folders
|
|
631
930
|
|