@ritualai/cli 0.7.10 → 0.7.12
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/doctor.js +246 -18
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +139 -9
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/agents/configure-mcp.js +40 -10
- package/dist/lib/agents/configure-mcp.js.map +1 -1
- package/dist/lib/claude-code-scopes.js +140 -0
- package/dist/lib/claude-code-scopes.js.map +1 -0
- package/dist/lib/node-managers.js +114 -0
- package/dist/lib/node-managers.js.map +1 -0
- package/dist/lib/npm-registry.js +107 -0
- package/dist/lib/npm-registry.js.map +1 -0
- package/dist/lib/skill-bundles.js +62 -0
- package/dist/lib/skill-bundles.js.map +1 -0
- package/dist/lib/skill-manifest.js +53 -0
- package/dist/lib/skill-manifest.js.map +1 -0
- package/package.json +74 -73
- package/skills/claude-code/ritual/.ritual-bundle.json +4 -0
- package/skills/claude-code/ritual/references/build-flow.md +75 -12
- package/skills/codex/ritual/.ritual-bundle.json +4 -0
- package/skills/codex/ritual/references/build-flow.md +75 -12
- package/skills/cursor/ritual/.ritual-bundle.json +4 -0
- package/skills/cursor/ritual/references/build-flow.md +75 -12
- package/skills/gemini/ritual/.ritual-bundle.json +4 -0
- package/skills/gemini/ritual/references/build-flow.md +75 -12
- package/skills/kiro/ritual/.ritual-bundle.json +4 -0
- package/skills/kiro/ritual/references/build-flow.md +75 -12
- package/skills/vscode/ritual/.ritual-bundle.json +4 -0
- package/skills/vscode/ritual/references/build-flow.md +75 -12
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,4CAAgD;AAChD,8CAAkD;AAClD,8CAAkD;AAClD,gDAAoD;AACpD,0CAA8C;AAC9C,8CAAkD;AAClD,4CAAsD;AACtD,qDAA4D;AAE5D,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACL,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CACX,yDAAyD;IACxD,yDAAyD,CAC1D;KACA,OAAO,CAAC,IAAA,qCAAsB,GAAE,CAAC,CAAC;AAEpC,oEAAoE;AACpE,+DAA+D;AAC/D,OAAO;KACL,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kFAAkF,CAAC;KAC/F,MAAM,CAAC,cAAc,EAAE,wDAAwD,CAAC;KAChF,MAAM,CAAC,QAAQ,EAAE,4BAA4B,CAAC;KAC9C,MAAM,CACN,gBAAgB,EAChB,kFAAkF,CAClF;KACA,MAAM,CAAC,kBAAkB,EAAE,2CAA2C,CAAC;KACvE,MAAM,CAAC,OAAO,EAAE,iFAAiF,CAAC;KAClG,MAAM,CACN,gBAAgB,EAChB,wHAAwH,CACxH;KACA,MAAM,CACN,kBAAkB,EAClB,kMAAkM,CAClM;KACA,MAAM,CACN,OAAO,EACP,wFAAwF,CACxF;KACA,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEtB,OAAO;KACL,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CACN,gBAAgB,EAChB,iGAAiG,CACjG;KACA,MAAM,CACN,kBAAkB,EAClB,4EAA4E,CAC5E;KACA,MAAM,CAAC,OAAO,EAAE,iFAAiF,CAAC;KAClG,MAAM,CACN,kBAAkB,EAClB,oIAAoI,CACpI;KACA,MAAM,CACN,OAAO,EACP,wFAAwF,CACxF;KACA,MAAM,CAAC,oBAAY,CAAC,CAAC;AAEvB,OAAO;KACL,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iFAAiF,CAAC;KAC9F,MAAM,CACN,OAAO,EACP,6IAA6I,CAC7I;KACA,MAAM,CAAC,sBAAa,CAAC,CAAC;AAExB,OAAO;KACL,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,MAAM,CAAC,sBAAa,CAAC,CAAC;AAExB,OAAO;KACL,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,sEAAsE,CAAC;KACnF,MAAM,CAAC,wBAAc,CAAC,CAAC;AAEzB,OAAO;KACL,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,2EAA2E,CAAC;KACxF,MAAM,CAAC,sBAAa,CAAC,CAAC;AAExB,iEAAiE;AACjE,+DAA+D;AAC/D,kDAAkD;AAClD,MAAM,KAAK,GAAG,OAAO;KACnB,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,oEAAoE,CAAC,CAAC;AAEpF,KAAK;KACH,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,mEAAmE,CAAC;KAChF,MAAM,CACN,kBAAkB,EAClB,0FAA0F,CAC1F;KACA,MAAM,CAAC,aAAa,EAAE,8DAA8D,CAAC;KACrF,MAAM,CAAC,0BAAkB,CAAC,CAAC;AAE7B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IACrD,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,4CAAgD;AAChD,8CAAkD;AAClD,8CAAkD;AAClD,gDAAoD;AACpD,0CAA8C;AAC9C,8CAAkD;AAClD,4CAAsD;AACtD,qDAA4D;AAE5D,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACL,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CACX,yDAAyD;IACxD,yDAAyD,CAC1D;KACA,OAAO,CAAC,IAAA,qCAAsB,GAAE,CAAC,CAAC;AAEpC,oEAAoE;AACpE,+DAA+D;AAC/D,OAAO;KACL,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kFAAkF,CAAC;KAC/F,MAAM,CAAC,cAAc,EAAE,wDAAwD,CAAC;KAChF,MAAM,CAAC,QAAQ,EAAE,4BAA4B,CAAC;KAC9C,MAAM,CACN,gBAAgB,EAChB,kFAAkF,CAClF;KACA,MAAM,CAAC,kBAAkB,EAAE,2CAA2C,CAAC;KACvE,MAAM,CAAC,OAAO,EAAE,iFAAiF,CAAC;KAClG,MAAM,CACN,gBAAgB,EAChB,wHAAwH,CACxH;KACA,MAAM,CACN,kBAAkB,EAClB,kMAAkM,CAClM;KACA,MAAM,CACN,OAAO,EACP,wFAAwF,CACxF;KACA,MAAM,CACN,eAAe,EACf,oOAAoO,CACpO;KACA,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEtB,OAAO;KACL,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CACN,gBAAgB,EAChB,iGAAiG,CACjG;KACA,MAAM,CACN,kBAAkB,EAClB,4EAA4E,CAC5E;KACA,MAAM,CAAC,OAAO,EAAE,iFAAiF,CAAC;KAClG,MAAM,CACN,kBAAkB,EAClB,oIAAoI,CACpI;KACA,MAAM,CACN,OAAO,EACP,wFAAwF,CACxF;KACA,MAAM,CAAC,oBAAY,CAAC,CAAC;AAEvB,OAAO;KACL,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iFAAiF,CAAC;KAC9F,MAAM,CACN,OAAO,EACP,6IAA6I,CAC7I;KACA,MAAM,CAAC,sBAAa,CAAC,CAAC;AAExB,OAAO;KACL,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,MAAM,CAAC,sBAAa,CAAC,CAAC;AAExB,OAAO;KACL,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,sEAAsE,CAAC;KACnF,MAAM,CAAC,wBAAc,CAAC,CAAC;AAEzB,OAAO;KACL,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,2EAA2E,CAAC;KACxF,MAAM,CAAC,sBAAa,CAAC,CAAC;AAExB,iEAAiE;AACjE,+DAA+D;AAC/D,kDAAkD;AAClD,MAAM,KAAK,GAAG,OAAO;KACnB,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,oEAAoE,CAAC,CAAC;AAEpF,KAAK;KACH,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,mEAAmE,CAAC;KAChF,MAAM,CACN,kBAAkB,EAClB,0FAA0F,CAC1F;KACA,MAAM,CAAC,aAAa,EAAE,8DAA8D,CAAC;KACrF,MAAM,CAAC,0BAAkB,CAAC,CAAC;AAE7B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IACrD,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
|
@@ -55,6 +55,33 @@ function configureMcpForAgent(provider, registration) {
|
|
|
55
55
|
* We re-register idempotently by removing-then-adding (the CLI errors
|
|
56
56
|
* on a duplicate name). The `try/catch` around remove is intentional —
|
|
57
57
|
* "not found" is fine; we just want a clean slate.
|
|
58
|
+
*
|
|
59
|
+
* Scope reconciliation (added 2026-05-14, CLI 0.7.12):
|
|
60
|
+
*
|
|
61
|
+
* Claude Code stores MCP entries in three scopes:
|
|
62
|
+
* - `user` → top-level `mcpServers.<name>` in ~/.claude.json
|
|
63
|
+
* - `local` → `projects["<cwd>"].mcpServers.<name>` in ~/.claude.json
|
|
64
|
+
* - `project` → a separate `.mcp.json` file in the project root
|
|
65
|
+
* (typically checked into git)
|
|
66
|
+
*
|
|
67
|
+
* Claude Code's in-session lookup prefers `local` over `user` when
|
|
68
|
+
* working inside a project. Before this commit we only removed from
|
|
69
|
+
* `--scope user` before re-adding — which meant any stale `local`
|
|
70
|
+
* entry (left behind by a manual `claude mcp add` or by an older
|
|
71
|
+
* version of this CLI) would survive every `ritual init`, silently
|
|
72
|
+
* shadow the fresh user-scope entry, and leave in-project sessions
|
|
73
|
+
* 401-ing on a revoked token. Mike hit this on 2026-05-14: a fresh
|
|
74
|
+
* `ritual init` minted a working user-scope token, but his
|
|
75
|
+
* django-oscar Claude Code session kept failing because the local
|
|
76
|
+
* scope still held the revoked predecessor.
|
|
77
|
+
*
|
|
78
|
+
* We now sweep BOTH writable scopes (`local` + `user`) before adding.
|
|
79
|
+
* `project` scope (the on-disk `.mcp.json`) is deliberately left
|
|
80
|
+
* alone — that file is often committed to the repo, and silently
|
|
81
|
+
* deleting from it would be a surprise change to a tracked file. If
|
|
82
|
+
* a project-scoped entry exists, `ritual doctor` surfaces it (see
|
|
83
|
+
* lib/claude-code-scopes.ts + the doctor sections that consume it)
|
|
84
|
+
* so the user knows where to look manually.
|
|
58
85
|
*/
|
|
59
86
|
function configureViaCliCommand(_provider, registration) {
|
|
60
87
|
const config = {
|
|
@@ -62,17 +89,20 @@ function configureViaCliCommand(_provider, registration) {
|
|
|
62
89
|
url: registration.url,
|
|
63
90
|
headers: { Authorization: `Bearer ${registration.token}` },
|
|
64
91
|
};
|
|
65
|
-
// 1. Remove
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
92
|
+
// 1. Remove from every writable scope. Skip `project` scope —
|
|
93
|
+
// .mcp.json is typically a tracked file.
|
|
94
|
+
for (const scope of ['local', 'user']) {
|
|
95
|
+
try {
|
|
96
|
+
(0, node_child_process_1.execSync)(`claude mcp remove ${SERVER_NAME} --scope ${scope}`, { stdio: 'pipe' });
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
/* not found in that scope — fine */
|
|
100
|
+
}
|
|
71
101
|
}
|
|
72
|
-
// 2. Add the fresh entry. Escape the JSON for
|
|
73
|
-
// Using single-quote wrap is safe because the JSON
|
|
74
|
-
// single quotes (object keys + string values are all
|
|
75
|
-
// in JSON-stringify output).
|
|
102
|
+
// 2. Add the fresh entry under user scope. Escape the JSON for
|
|
103
|
+
// the shell. Using single-quote wrap is safe because the JSON
|
|
104
|
+
// contains no single quotes (object keys + string values are all
|
|
105
|
+
// double-quoted in JSON-stringify output).
|
|
76
106
|
const json = JSON.stringify(config);
|
|
77
107
|
(0, node_child_process_1.execSync)(`claude mcp add-json --scope user ${SERVER_NAME} '${json}'`, {
|
|
78
108
|
stdio: 'pipe',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure-mcp.js","sourceRoot":"","sources":["../../../src/lib/agents/configure-mcp.ts"],"names":[],"mappings":";;AA0DA,oDAkBC;AA5ED,qCAMiB;AACjB,yCAAoC;AACpC,2DAA8C;AAG9C;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,GAAG,QAAQ,CAAC;AAoB7B;;;;;;GAMG;AACH,SAAgB,oBAAoB,CACnC,QAAuB,EACvB,YAA6B;IAE7B,IAAI,CAAC;QACJ,IAAI,QAAQ,CAAC,eAAe,KAAK,aAAa,EAAE,CAAC;YAChD,sBAAsB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACP,oBAAoB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,OAAO;YACN,QAAQ;YACR,OAAO,EAAE,KAAK;YACd,MAAM,EAAG,GAAa,CAAC,OAAO;SAC9B,CAAC;IACH,CAAC;AACF,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"configure-mcp.js","sourceRoot":"","sources":["../../../src/lib/agents/configure-mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RITUAL_SERVER_NAME = void 0;
|
|
4
|
+
exports.findRitualScopeEntries = findRitualScopeEntries;
|
|
5
|
+
exports.findShadowingEntries = findShadowingEntries;
|
|
6
|
+
exports.fixCommandFor = fixCommandFor;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
/**
|
|
11
|
+
* Server name used by `ritual init`. Kept in sync with
|
|
12
|
+
* `agents/configure-mcp.ts`'s SERVER_NAME constant.
|
|
13
|
+
*/
|
|
14
|
+
exports.RITUAL_SERVER_NAME = 'ritual';
|
|
15
|
+
/**
|
|
16
|
+
* Pull a Bearer token out of an MCP entry's Authorization header.
|
|
17
|
+
* Defensive — entries can have absent / lower-cased / mis-prefixed
|
|
18
|
+
* headers; we return null and let the caller surface "non-bearer".
|
|
19
|
+
*/
|
|
20
|
+
function extractBearer(entry) {
|
|
21
|
+
const headers = entry.headers ?? {};
|
|
22
|
+
// Try the conventional casing first, then case-insensitive fallback.
|
|
23
|
+
const authRaw = headers['Authorization'] ??
|
|
24
|
+
Object.entries(headers).find(([k]) => k.toLowerCase() === 'authorization')?.[1];
|
|
25
|
+
if (typeof authRaw !== 'string')
|
|
26
|
+
return null;
|
|
27
|
+
const m = authRaw.match(/^Bearer\s+(\S+)$/);
|
|
28
|
+
return m ? m[1] : null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read and JSON.parse a file, returning null on absent/corrupt.
|
|
32
|
+
* Doctor's job is to surface state, not to be the file repair tool —
|
|
33
|
+
* if `~/.claude.json` is corrupt the user has bigger problems and
|
|
34
|
+
* Claude Code itself would be broken; we just report nothing here.
|
|
35
|
+
*/
|
|
36
|
+
function readJsonSafely(path) {
|
|
37
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
38
|
+
return null;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse((0, node_fs_1.readFileSync)(path, 'utf-8'));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build the full list of ritual entries across all three scopes for
|
|
48
|
+
* a given project context. `cwd` is the project we want `local` and
|
|
49
|
+
* `project` scopes resolved against — usually `process.cwd()` from
|
|
50
|
+
* the caller, but parameterized for testability.
|
|
51
|
+
*
|
|
52
|
+
* Returned in precedence order: `project` first, then `local`, then
|
|
53
|
+
* `user`. Callers that just want "what's actually being used right
|
|
54
|
+
* now" can take the first entry. Callers that want to detect drift
|
|
55
|
+
* (doctor) iterate all of them.
|
|
56
|
+
*/
|
|
57
|
+
function findRitualScopeEntries(cwd = process.cwd(), home = (0, node_os_1.homedir)()) {
|
|
58
|
+
const out = [];
|
|
59
|
+
// 1. Project scope — .mcp.json at the project root.
|
|
60
|
+
const projectMcpPath = (0, node_path_1.join)(cwd, '.mcp.json');
|
|
61
|
+
const projectMcp = readJsonSafely(projectMcpPath);
|
|
62
|
+
const projectEntry = projectMcp?.mcpServers?.[exports.RITUAL_SERVER_NAME];
|
|
63
|
+
if (projectEntry?.url) {
|
|
64
|
+
out.push({
|
|
65
|
+
scope: 'project',
|
|
66
|
+
configPath: projectMcpPath,
|
|
67
|
+
projectPath: cwd,
|
|
68
|
+
url: projectEntry.url,
|
|
69
|
+
bearerToken: extractBearer(projectEntry),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// 2. Local + user scope — both live inside ~/.claude.json.
|
|
73
|
+
const claudeJsonPath = (0, node_path_1.join)(home, '.claude.json');
|
|
74
|
+
const claudeJson = readJsonSafely(claudeJsonPath);
|
|
75
|
+
// On macOS, `process.cwd()` may return a symlink-resolved path
|
|
76
|
+
// (`/private/var/...`) while Claude Code's stored project key may
|
|
77
|
+
// be the user-facing form (`/var/...`) — or vice versa. Try both
|
|
78
|
+
// forms before giving up. In production this almost never matters
|
|
79
|
+
// (real project paths like `/Users/<name>/Development/<repo>` have
|
|
80
|
+
// no symlinks in the prefix) but tempdir-based tests exercise it.
|
|
81
|
+
let realCwd = cwd;
|
|
82
|
+
try {
|
|
83
|
+
realCwd = (0, node_fs_1.realpathSync)(cwd);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
/* cwd doesn't exist or unreadable — fall back to literal */
|
|
87
|
+
}
|
|
88
|
+
const localEntry = claudeJson?.projects?.[cwd]?.mcpServers?.[exports.RITUAL_SERVER_NAME] ??
|
|
89
|
+
(realCwd !== cwd
|
|
90
|
+
? claudeJson?.projects?.[realCwd]?.mcpServers?.[exports.RITUAL_SERVER_NAME]
|
|
91
|
+
: undefined);
|
|
92
|
+
if (localEntry?.url) {
|
|
93
|
+
out.push({
|
|
94
|
+
scope: 'local',
|
|
95
|
+
configPath: claudeJsonPath,
|
|
96
|
+
projectPath: cwd,
|
|
97
|
+
url: localEntry.url,
|
|
98
|
+
bearerToken: extractBearer(localEntry),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const userEntry = claudeJson?.mcpServers?.[exports.RITUAL_SERVER_NAME];
|
|
102
|
+
if (userEntry?.url) {
|
|
103
|
+
out.push({
|
|
104
|
+
scope: 'user',
|
|
105
|
+
configPath: claudeJsonPath,
|
|
106
|
+
url: userEntry.url,
|
|
107
|
+
bearerToken: extractBearer(userEntry),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Detect shadow drift: more than one entry exists across scopes AND
|
|
114
|
+
* the higher-precedence entry's bearer differs from the user-scope
|
|
115
|
+
* entry's. Returns the offending higher-precedence entries (which
|
|
116
|
+
* is what doctor surfaces as actionable).
|
|
117
|
+
*
|
|
118
|
+
* If only `user` is present, returns []. If `project` or `local`
|
|
119
|
+
* holds the SAME token as `user`, returns [] (no drift — just a
|
|
120
|
+
* scope-redundancy, harmless). If they hold different tokens, the
|
|
121
|
+
* shadowing entry is returned for cleanup.
|
|
122
|
+
*/
|
|
123
|
+
function findShadowingEntries(entries) {
|
|
124
|
+
const userEntry = entries.find((e) => e.scope === 'user');
|
|
125
|
+
if (!userEntry || !userEntry.bearerToken)
|
|
126
|
+
return [];
|
|
127
|
+
return entries.filter((e) => e.scope !== 'user' &&
|
|
128
|
+
e.bearerToken !== null &&
|
|
129
|
+
e.bearerToken !== userEntry.bearerToken);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Convenience: the `claude mcp remove ritual -s <scope>` line a user
|
|
133
|
+
* should run to clean up a specific entry. Returns the literal
|
|
134
|
+
* command string so doctor can render it inline in the actionable
|
|
135
|
+
* fix-it text.
|
|
136
|
+
*/
|
|
137
|
+
function fixCommandFor(entry) {
|
|
138
|
+
return `claude mcp remove ${exports.RITUAL_SERVER_NAME} -s ${entry.scope}`;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=claude-code-scopes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-scopes.js","sourceRoot":"","sources":["../../src/lib/claude-code-scopes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reportNodeManagers = reportNodeManagers;
|
|
4
|
+
exports.findDeadHyphenatedInstalls = findDeadHyphenatedInstalls;
|
|
5
|
+
exports.findShadowedInstalls = findShadowedInstalls;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_os_1 = require("node:os");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
/**
|
|
10
|
+
* Read a single `package.json` and extract `{ name, version }`.
|
|
11
|
+
* Returns null on any read/parse failure — caller treats absence as
|
|
12
|
+
* "no install at this path", not as an error.
|
|
13
|
+
*/
|
|
14
|
+
function readPackageInfo(path) {
|
|
15
|
+
try {
|
|
16
|
+
const raw = (0, node_fs_1.readFileSync)(path, 'utf-8');
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
if (typeof parsed.name !== 'string' || typeof parsed.version !== 'string')
|
|
19
|
+
return null;
|
|
20
|
+
return { name: parsed.name, version: parsed.version };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Given a directory we believe contains one or more Node version
|
|
28
|
+
* installations as immediate subdirectories, probe each for the two
|
|
29
|
+
* ritual packages. `nodeVersionDirPattern` describes how to derive the
|
|
30
|
+
* `lib/node_modules` location from each version dir.
|
|
31
|
+
*
|
|
32
|
+
* fnm layout: ~/.local/share/fnm/node-versions/v20.19.2/installation/lib/node_modules
|
|
33
|
+
* nvm layout: ~/.nvm/versions/node/v20.19.2/lib/node_modules
|
|
34
|
+
* asdf layout: ~/.asdf/installs/nodejs/20.19.2/.npm/lib/node_modules
|
|
35
|
+
*/
|
|
36
|
+
function scanVersionRoot(manager, versionsRoot, libPathFromVersion) {
|
|
37
|
+
if (!(0, node_fs_1.existsSync)(versionsRoot))
|
|
38
|
+
return [];
|
|
39
|
+
let versionDirs;
|
|
40
|
+
try {
|
|
41
|
+
versionDirs = (0, node_fs_1.readdirSync)(versionsRoot, { withFileTypes: true })
|
|
42
|
+
.filter((d) => d.isDirectory())
|
|
43
|
+
.map((d) => d.name);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const out = [];
|
|
49
|
+
const packageNames = ['@ritualai/cli', '@ritual-ai/cli'];
|
|
50
|
+
for (const versionDir of versionDirs) {
|
|
51
|
+
const nodeModules = libPathFromVersion((0, node_path_1.join)(versionsRoot, versionDir));
|
|
52
|
+
for (const pkg of packageNames) {
|
|
53
|
+
const pkgJson = (0, node_path_1.join)(nodeModules, ...pkg.split('/'), 'package.json');
|
|
54
|
+
const info = readPackageInfo(pkgJson);
|
|
55
|
+
if (!info)
|
|
56
|
+
continue;
|
|
57
|
+
if (info.name !== pkg)
|
|
58
|
+
continue;
|
|
59
|
+
out.push({
|
|
60
|
+
manager,
|
|
61
|
+
nodeVersion: versionDir,
|
|
62
|
+
packageName: pkg,
|
|
63
|
+
version: info.version,
|
|
64
|
+
packageJsonPath: pkgJson,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build the full report. Each manager is probed at its canonical
|
|
72
|
+
* install root; absence of a root is treated as "manager not used,"
|
|
73
|
+
* not an error. The aggregate `anyManagerPresent` is true if at least
|
|
74
|
+
* one root existed (whether or not it had ritual installs).
|
|
75
|
+
*
|
|
76
|
+
* NB: this does NOT probe the currently-active Node's global path —
|
|
77
|
+
* that's already reflected in `process.version` and the doctor reports
|
|
78
|
+
* it separately. The point of this report is shadowing detection: what
|
|
79
|
+
* other Node versions exist that you might silently fall through to.
|
|
80
|
+
*/
|
|
81
|
+
function reportNodeManagers(home = (0, node_os_1.homedir)()) {
|
|
82
|
+
const fnmRoot = (0, node_path_1.join)(home, '.local', 'share', 'fnm', 'node-versions');
|
|
83
|
+
const nvmRoot = (0, node_path_1.join)(home, '.nvm', 'versions', 'node');
|
|
84
|
+
const asdfRoot = (0, node_path_1.join)(home, '.asdf', 'installs', 'nodejs');
|
|
85
|
+
const anyManagerPresent = (0, node_fs_1.existsSync)(fnmRoot) || (0, node_fs_1.existsSync)(nvmRoot) || (0, node_fs_1.existsSync)(asdfRoot);
|
|
86
|
+
const installs = [
|
|
87
|
+
...scanVersionRoot('fnm', fnmRoot, (v) => (0, node_path_1.join)(v, 'installation', 'lib', 'node_modules')),
|
|
88
|
+
...scanVersionRoot('nvm', nvmRoot, (v) => (0, node_path_1.join)(v, 'lib', 'node_modules')),
|
|
89
|
+
// asdf's node plugin uses npm's per-version prefix under `.npm`.
|
|
90
|
+
// This is the path npm itself writes to when you `npm i -g`
|
|
91
|
+
// under an asdf-managed Node.
|
|
92
|
+
...scanVersionRoot('asdf', asdfRoot, (v) => (0, node_path_1.join)(v, '.npm', 'lib', 'node_modules')),
|
|
93
|
+
];
|
|
94
|
+
return { anyManagerPresent, installs };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Pull just the dead-package installs out of a report. Used by doctor
|
|
98
|
+
* to render a louder warning — having `@ritual-ai/cli` installed
|
|
99
|
+
* anywhere is always a problem (it's the dead 0.1.x legacy), regardless
|
|
100
|
+
* of whether the *current* shell picks it up.
|
|
101
|
+
*/
|
|
102
|
+
function findDeadHyphenatedInstalls(report) {
|
|
103
|
+
return report.installs.filter((i) => i.packageName === '@ritual-ai/cli');
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Pull installs that are NOT the version of `currentVersion` (and not
|
|
107
|
+
* the dead hyphenated package — that's a separate, louder warning).
|
|
108
|
+
* These are "you've got a stale install on another Node version that
|
|
109
|
+
* will surface when fnm switches under you" candidates.
|
|
110
|
+
*/
|
|
111
|
+
function findShadowedInstalls(report, currentVersion) {
|
|
112
|
+
return report.installs.filter((i) => i.packageName === '@ritualai/cli' && i.version !== currentVersion);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=node-managers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-managers.js","sourceRoot":"","sources":["../../src/lib/node-managers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLatestNpmVersion = getLatestNpmVersion;
|
|
4
|
+
exports.isNewerVersion = isNewerVersion;
|
|
5
|
+
const node_https_1 = require("node:https");
|
|
6
|
+
/**
|
|
7
|
+
* Fetch the latest published version of an npm package from the public
|
|
8
|
+
* registry. Used by `ritual doctor` to surface "you're on 0.7.10 but
|
|
9
|
+
* 0.7.11 is available."
|
|
10
|
+
*
|
|
11
|
+
* Pure HTTPS — no dependency on a registry client library. We hit the
|
|
12
|
+
* package metadata endpoint and read `dist-tags.latest`, which is what
|
|
13
|
+
* `npm view <pkg> version` returns.
|
|
14
|
+
*
|
|
15
|
+
* Hard timeout because `ritual doctor` runs synchronously in the user's
|
|
16
|
+
* terminal and a hung network call would hang the diagnostic. Caller
|
|
17
|
+
* should treat null as "couldn't determine" (e.g. offline, registry
|
|
18
|
+
* down, corporate proxy) rather than "package doesn't exist."
|
|
19
|
+
*
|
|
20
|
+
* Why we don't use `child_process.execSync('npm view ...')`:
|
|
21
|
+
* - Shells out to `npm`, which loads ~600ms of Node startup just for
|
|
22
|
+
* the registry round-trip.
|
|
23
|
+
* - Adds an implicit dependency on `npm` being on PATH (we don't
|
|
24
|
+
* enforce that — a user could be on pnpm or yarn).
|
|
25
|
+
* - Surfaces npm's stderr noise (deprecation warnings, etc.) to the
|
|
26
|
+
* diagnostic output.
|
|
27
|
+
*/
|
|
28
|
+
async function getLatestNpmVersion(packageName, timeoutMs = 2000) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
// Encode scoped package names (`@scope/name`) for the URL path.
|
|
31
|
+
// `encodeURIComponent` turns `@` into `%40` and `/` into `%2F`,
|
|
32
|
+
// which is the registry's expected form for scoped packages.
|
|
33
|
+
const encoded = encodeURIComponent(packageName);
|
|
34
|
+
const url = `https://registry.npmjs.org/${encoded}`;
|
|
35
|
+
const req = (0, node_https_1.request)(url, {
|
|
36
|
+
method: 'GET',
|
|
37
|
+
headers: {
|
|
38
|
+
// Slim metadata response — full doc is megabytes for
|
|
39
|
+
// packages with long publish histories. `abbreviated`
|
|
40
|
+
// returns only the fields we need (~5KB).
|
|
41
|
+
Accept: 'application/vnd.npm.install-v1+json',
|
|
42
|
+
'User-Agent': '@ritualai/cli (doctor)',
|
|
43
|
+
},
|
|
44
|
+
}, (res) => {
|
|
45
|
+
if (res.statusCode !== 200) {
|
|
46
|
+
res.resume(); // drain and discard
|
|
47
|
+
resolve(null);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const chunks = [];
|
|
51
|
+
res.on('data', (c) => chunks.push(c));
|
|
52
|
+
res.on('end', () => {
|
|
53
|
+
try {
|
|
54
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
55
|
+
const parsed = JSON.parse(body);
|
|
56
|
+
const latest = parsed['dist-tags']?.latest;
|
|
57
|
+
resolve(typeof latest === 'string' ? latest : null);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
resolve(null);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
res.on('error', () => resolve(null));
|
|
64
|
+
});
|
|
65
|
+
req.setTimeout(timeoutMs, () => {
|
|
66
|
+
req.destroy();
|
|
67
|
+
resolve(null);
|
|
68
|
+
});
|
|
69
|
+
req.on('error', () => resolve(null));
|
|
70
|
+
req.end();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Loose semver compare: return true iff `latest` is strictly newer than
|
|
75
|
+
* `installed`. Tolerates `0.0.0-unknown` (used when we can't read our
|
|
76
|
+
* own version) by treating it as "always outdated" — which surfaces a
|
|
77
|
+
* loud error in doctor rather than silently passing.
|
|
78
|
+
*
|
|
79
|
+
* We deliberately don't pull in `semver` as a dep here — the cost
|
|
80
|
+
* (parse error handling, prerelease semantics, range syntax) isn't
|
|
81
|
+
* justified for a one-call compare. Splitting on '.' and comparing as
|
|
82
|
+
* numeric tuples is sufficient for our 0.X.Y release line.
|
|
83
|
+
*/
|
|
84
|
+
function isNewerVersion(installed, latest) {
|
|
85
|
+
if (installed === latest)
|
|
86
|
+
return false;
|
|
87
|
+
if (installed === '0.0.0-unknown')
|
|
88
|
+
return true;
|
|
89
|
+
const parse = (v) => v
|
|
90
|
+
.split('-')[0] // strip prerelease (e.g. -beta.1)
|
|
91
|
+
.split('.')
|
|
92
|
+
.map((s) => Number.parseInt(s, 10))
|
|
93
|
+
.map((n) => (Number.isFinite(n) ? n : 0));
|
|
94
|
+
const a = parse(installed);
|
|
95
|
+
const b = parse(latest);
|
|
96
|
+
const len = Math.max(a.length, b.length);
|
|
97
|
+
for (let i = 0; i < len; i++) {
|
|
98
|
+
const ai = a[i] ?? 0;
|
|
99
|
+
const bi = b[i] ?? 0;
|
|
100
|
+
if (bi > ai)
|
|
101
|
+
return true;
|
|
102
|
+
if (bi < ai)
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=npm-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-registry.js","sourceRoot":"","sources":["../../src/lib/npm-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findLocalSkillBundles = findLocalSkillBundles;
|
|
4
|
+
exports.findStaleBundles = findStaleBundles;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const providers_1 = require("./agents/providers");
|
|
8
|
+
const skill_manifest_1 = require("./skill-manifest");
|
|
9
|
+
/**
|
|
10
|
+
* Walk every known provider's `projectSkillDir` under `projectDir` and
|
|
11
|
+
* collect each child directory as a candidate skill bundle. Reads each
|
|
12
|
+
* manifest and compares to `cliVersion`.
|
|
13
|
+
*
|
|
14
|
+
* Hidden directories (those starting with `.`) are skipped — they're
|
|
15
|
+
* either dotfiles or our own manifest companions, never skill dirs.
|
|
16
|
+
*
|
|
17
|
+
* `cliVersion` is passed in (rather than read from package-info here)
|
|
18
|
+
* so tests can inject a fixed value.
|
|
19
|
+
*/
|
|
20
|
+
function findLocalSkillBundles(projectDir, cliVersion) {
|
|
21
|
+
const found = [];
|
|
22
|
+
for (const provider of providers_1.PROVIDERS) {
|
|
23
|
+
const skillRoot = (0, node_path_1.join)(projectDir, provider.projectSkillDir);
|
|
24
|
+
if (!(0, node_fs_1.existsSync)(skillRoot))
|
|
25
|
+
continue;
|
|
26
|
+
let entries;
|
|
27
|
+
try {
|
|
28
|
+
entries = (0, node_fs_1.readdirSync)(skillRoot, { withFileTypes: true })
|
|
29
|
+
.filter((d) => d.isDirectory() && !d.name.startsWith('.'))
|
|
30
|
+
.map((d) => d.name);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
for (const skillName of entries) {
|
|
36
|
+
const path = (0, node_path_1.join)(skillRoot, skillName);
|
|
37
|
+
// Defensive: a non-directory slipping through (race, symlink
|
|
38
|
+
// loop) just gets skipped.
|
|
39
|
+
try {
|
|
40
|
+
if (!(0, node_fs_1.statSync)(path).isDirectory())
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const manifest = (0, skill_manifest_1.readSkillManifest)(path);
|
|
47
|
+
const drift = (0, skill_manifest_1.compareToCliVersion)(manifest, cliVersion);
|
|
48
|
+
found.push({ provider, skillName, path, drift });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Subset of bundles whose drift status indicates a refresh would help.
|
|
55
|
+
* Both `drift` (manifest present, version mismatch) AND `unknown`
|
|
56
|
+
* (manifest missing — pre-0.7.11 bundle) are considered actionable:
|
|
57
|
+
* running `ritual init --skills-only` is the same fix for either case.
|
|
58
|
+
*/
|
|
59
|
+
function findStaleBundles(bundles) {
|
|
60
|
+
return bundles.filter((b) => b.drift.kind === 'drift' || b.drift.kind === 'unknown');
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=skill-bundles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-bundles.js","sourceRoot":"","sources":["../../src/lib/skill-bundles.ts"],"names":[],"mappings":";;AAqCA,sDAgCC;AAQD,4CAEC;AA/ED,qCAA4D;AAC5D,yCAAiC;AACjC,kDAAmE;AACnE,qDAA4F;AAuB5F;;;;;;;;;;GAUG;AACH,SAAgB,qBAAqB,CAAC,UAAkB,EAAE,UAAkB;IAC3E,MAAM,KAAK,GAAuB,EAAE,CAAC;IAErC,KAAK,MAAM,QAAQ,IAAI,qBAAS,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAA,gBAAI,EAAC,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAA,oBAAU,EAAC,SAAS,CAAC;YAAE,SAAS;QAErC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACJ,OAAO,GAAG,IAAA,qBAAW,EAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;iBACvD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;iBACzD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACR,SAAS;QACV,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACxC,6DAA6D;YAC7D,2BAA2B;YAC3B,IAAI,CAAC;gBACJ,IAAI,CAAC,IAAA,kBAAQ,EAAC,IAAI,CAAC,CAAC,WAAW,EAAE;oBAAE,SAAS;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;YACD,MAAM,QAAQ,GAAG,IAAA,kCAAiB,EAAC,IAAI,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,IAAA,oCAAmB,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,OAA2B;IAC3D,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MANIFEST_FILENAME = void 0;
|
|
4
|
+
exports.writeSkillManifest = writeSkillManifest;
|
|
5
|
+
exports.readSkillManifest = readSkillManifest;
|
|
6
|
+
exports.compareToCliVersion = compareToCliVersion;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
exports.MANIFEST_FILENAME = '.ritual-bundle.json';
|
|
10
|
+
/**
|
|
11
|
+
* Write a manifest into `dir`. Used by the build-skills script.
|
|
12
|
+
*
|
|
13
|
+
* Always overwrites. `dir` must exist — caller is responsible for
|
|
14
|
+
* mkdir.
|
|
15
|
+
*/
|
|
16
|
+
function writeSkillManifest(dir, manifest) {
|
|
17
|
+
const path = (0, node_path_1.join)(dir, exports.MANIFEST_FILENAME);
|
|
18
|
+
(0, node_fs_1.writeFileSync)(path, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read a manifest from `dir`. Returns `null` if absent or unparseable.
|
|
22
|
+
*
|
|
23
|
+
* Never throws — drift checks are best-effort and an unreadable
|
|
24
|
+
* manifest just means "we can't tell," not "crash the doctor."
|
|
25
|
+
*/
|
|
26
|
+
function readSkillManifest(dir) {
|
|
27
|
+
const path = (0, node_path_1.join)(dir, exports.MANIFEST_FILENAME);
|
|
28
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
29
|
+
return null;
|
|
30
|
+
try {
|
|
31
|
+
const raw = (0, node_fs_1.readFileSync)(path, 'utf-8');
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
if (typeof parsed.cliVersion !== 'string' || parsed.cliVersion.length === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if (typeof parsed.builtAt !== 'string' || parsed.builtAt.length === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return { cliVersion: parsed.cliVersion, builtAt: parsed.builtAt };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function compareToCliVersion(manifest, cliVersion) {
|
|
46
|
+
if (!manifest)
|
|
47
|
+
return { kind: 'unknown' };
|
|
48
|
+
if (manifest.cliVersion === cliVersion) {
|
|
49
|
+
return { kind: 'in-sync', bundleVersion: manifest.cliVersion };
|
|
50
|
+
}
|
|
51
|
+
return { kind: 'drift', bundleVersion: manifest.cliVersion, cliVersion };
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=skill-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-manifest.js","sourceRoot":"","sources":["../../src/lib/skill-manifest.ts"],"names":[],"mappings":";;;AA0CA,gDAGC;AAQD,8CAgBC;AAkBD,kDASC;AAhGD,qCAAkE;AAClE,yCAAiC;AAiCpB,QAAA,iBAAiB,GAAG,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,GAAW,EAAE,QAA6B;IAC5E,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,yBAAiB,CAAC,CAAC;IAC1C,IAAA,uBAAa,EAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,GAAW;IAC5C,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,yBAAiB,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAA,oBAAU,EAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,IAAA,sBAAY,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiC,CAAC;QAC/D,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7E,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvE,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAkBD,SAAgB,mBAAmB,CAClC,QAAoC,EACpC,UAAkB;IAElB,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1C,IAAI,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC;AAC1E,CAAC"}
|