@plaud-ai/mcp 0.3.2 → 0.3.4
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/{chunk-4QBEOJPX.js → chunk-242FRP4P.js} +6 -1
- package/dist/chunk-D2JZW2TW.js +832 -0
- package/dist/{chunk-QJV4OLZI.js → chunk-LOGKF7DL.js} +1 -1
- package/dist/{chunk-QT25MKZJ.js → chunk-VHTXWQUE.js} +34 -27
- package/dist/{chunk-XA77WLYF.js → chunk-XWDA3G2U.js} +15 -2
- package/dist/index.js +14 -15
- package/dist/{install-UUXHA6WE.js → install-ETBOS6SA.js} +65 -21
- package/dist/{server-BOR5EZLF.js → server-NKCNUA6P.js} +0 -1
- package/dist/{server-D3JKIARR.js → server-VVQEILKC.js} +497 -26
- package/dist/{setup-GLWZYNRW.js → setup-SMS45JC5.js} +8 -9
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/dist/chunk-MCKGQKYU.js +0 -15
- package/dist/chunk-R5G6UXSI.js +0 -20687
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
loadSkills,
|
|
3
|
+
skillsSourceDir
|
|
4
|
+
} from "./chunk-242FRP4P.js";
|
|
4
5
|
|
|
5
6
|
// src/install-utils.ts
|
|
6
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
7
|
+
import { readFile, writeFile, mkdir, cp, rm } from "fs/promises";
|
|
7
8
|
import { existsSync } from "fs";
|
|
8
9
|
import { join, dirname } from "path";
|
|
9
10
|
import { homedir, platform } from "os";
|
|
@@ -12,11 +13,12 @@ var SKILLS_MARKER_START = "<!-- plaud-skills:start -->";
|
|
|
12
13
|
var SKILLS_MARKER_END = "<!-- plaud-skills:end -->";
|
|
13
14
|
function findNodeBinCommand(command) {
|
|
14
15
|
const commandName = platform() === "win32" ? `${command}.cmd` : command;
|
|
16
|
+
const sibling = join(dirname(process.execPath), commandName);
|
|
17
|
+
if (existsSync(sibling)) return sibling;
|
|
15
18
|
const found = spawnSync(platform() === "win32" ? "where" : "which", [commandName], { encoding: "utf-8" });
|
|
16
19
|
const firstMatch = found.status === 0 ? found.stdout.split(/\r?\n/).find((line) => line.trim())?.trim() : void 0;
|
|
17
20
|
if (firstMatch) return firstMatch;
|
|
18
|
-
|
|
19
|
-
return existsSync(sibling) ? sibling : commandName;
|
|
21
|
+
return commandName;
|
|
20
22
|
}
|
|
21
23
|
function isLocalPackageSpec(spec) {
|
|
22
24
|
return spec.endsWith(".tgz") || spec.startsWith(".") || spec.startsWith("/") || /^[A-Za-z]:[\\/]/.test(spec);
|
|
@@ -34,6 +36,12 @@ function getMcpEntry() {
|
|
|
34
36
|
args: ["-y", packageSpec]
|
|
35
37
|
};
|
|
36
38
|
}
|
|
39
|
+
function commandPathIsStale(command) {
|
|
40
|
+
if (!command) return false;
|
|
41
|
+
if (command.includes("fnm_multishells")) return true;
|
|
42
|
+
const isAbsolute = command.startsWith("/") || /^[A-Za-z]:[\\/]/.test(command);
|
|
43
|
+
return isAbsolute && !existsSync(command);
|
|
44
|
+
}
|
|
37
45
|
function copyToClipboard(content) {
|
|
38
46
|
if (platform() === "win32") {
|
|
39
47
|
return spawnSync("clip", [], { input: content }).status === 0;
|
|
@@ -43,30 +51,28 @@ function copyToClipboard(content) {
|
|
|
43
51
|
}
|
|
44
52
|
return false;
|
|
45
53
|
}
|
|
46
|
-
async function
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} catch {
|
|
56
|
-
}
|
|
57
|
-
if (existing.includes(SKILLS_MARKER_START)) {
|
|
58
|
-
const updated = existing.replace(
|
|
59
|
-
new RegExp(`${SKILLS_MARKER_START}[\\s\\S]*?${SKILLS_MARKER_END}`),
|
|
60
|
-
block
|
|
61
|
-
);
|
|
62
|
-
await mkdir(dirname(claudeMdPath), { recursive: true });
|
|
63
|
-
await writeFile(claudeMdPath, updated, "utf-8");
|
|
64
|
-
} else {
|
|
65
|
-
await mkdir(dirname(claudeMdPath), { recursive: true });
|
|
66
|
-
await writeFile(claudeMdPath, existing + (existing.endsWith("\n") ? "" : "\n") + block + "\n", "utf-8");
|
|
54
|
+
async function installSkillsToClaudeCode() {
|
|
55
|
+
const sourceDir = skillsSourceDir();
|
|
56
|
+
const skills = await loadSkills();
|
|
57
|
+
const destRoot = join(homedir(), ".claude", "skills");
|
|
58
|
+
await mkdir(destRoot, { recursive: true });
|
|
59
|
+
const installed = [];
|
|
60
|
+
for (const skill of skills) {
|
|
61
|
+
await cp(join(sourceDir, skill.dir), join(destRoot, skill.dir), { recursive: true, force: true });
|
|
62
|
+
installed.push(skill.name);
|
|
67
63
|
}
|
|
64
|
+
await removeLegacySkillsBlock();
|
|
65
|
+
return installed;
|
|
68
66
|
}
|
|
69
67
|
async function removeSkillsFromClaudeCode() {
|
|
68
|
+
const destRoot = join(homedir(), ".claude", "skills");
|
|
69
|
+
const skills = await loadSkills();
|
|
70
|
+
for (const skill of skills) {
|
|
71
|
+
await rm(join(destRoot, skill.dir), { recursive: true, force: true }).catch(() => void 0);
|
|
72
|
+
}
|
|
73
|
+
await removeLegacySkillsBlock();
|
|
74
|
+
}
|
|
75
|
+
async function removeLegacySkillsBlock() {
|
|
70
76
|
const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
|
|
71
77
|
let existing = "";
|
|
72
78
|
try {
|
|
@@ -83,7 +89,8 @@ async function removeSkillsFromClaudeCode() {
|
|
|
83
89
|
|
|
84
90
|
export {
|
|
85
91
|
getMcpEntry,
|
|
92
|
+
commandPathIsStale,
|
|
86
93
|
copyToClipboard,
|
|
87
|
-
|
|
94
|
+
installSkillsToClaudeCode,
|
|
88
95
|
removeSkillsFromClaudeCode
|
|
89
96
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
capture,
|
|
3
3
|
classifyError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-D2JZW2TW.js";
|
|
5
5
|
import {
|
|
6
6
|
logger
|
|
7
7
|
} from "./chunk-NPCCDRWQ.js";
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
// src/tools/index.ts
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
import { randomUUID } from "crypto";
|
|
16
|
+
var toolHooks = null;
|
|
16
17
|
var MAX_FILTER_PAGES = 5;
|
|
17
18
|
var FILTER_PAGE_SIZE = 100;
|
|
18
19
|
function parseDate(s) {
|
|
@@ -37,6 +38,10 @@ function normalizeMcpHost(name) {
|
|
|
37
38
|
function emitToolClick(tool, props = {}) {
|
|
38
39
|
const requestId = randomUUID();
|
|
39
40
|
capture("mcp:tool:click", { tool_name: tool, request_id: requestId, passive: false, ...props });
|
|
41
|
+
toolHooks?.onToolClick({
|
|
42
|
+
tool,
|
|
43
|
+
fileId: typeof props.file_id === "string" ? props.file_id : void 0
|
|
44
|
+
});
|
|
40
45
|
return requestId;
|
|
41
46
|
}
|
|
42
47
|
function recordToolMetric(tool, status, durationMs, requestId, props = {}, err) {
|
|
@@ -52,8 +57,16 @@ function recordToolMetric(tool, status, durationMs, requestId, props = {}, err)
|
|
|
52
57
|
if (status === "success") evProps.duration_ms = durationMs;
|
|
53
58
|
else evProps.error_type = classifyError(err);
|
|
54
59
|
capture(event, evProps);
|
|
60
|
+
toolHooks?.onToolResult({
|
|
61
|
+
tool,
|
|
62
|
+
status,
|
|
63
|
+
durationMs,
|
|
64
|
+
fileId: typeof props.file_id === "string" ? props.file_id : void 0,
|
|
65
|
+
failureKind: status === "error" ? classifyError(err) : void 0
|
|
66
|
+
});
|
|
55
67
|
}
|
|
56
|
-
function registerTools(server, client) {
|
|
68
|
+
function registerTools(server, client, hooks) {
|
|
69
|
+
toolHooks = hooks ?? null;
|
|
57
70
|
server.registerTool(
|
|
58
71
|
"list_files",
|
|
59
72
|
{
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getClient
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LOGKF7DL.js";
|
|
5
5
|
import {
|
|
6
6
|
loadSkills
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-242FRP4P.js";
|
|
8
8
|
import {
|
|
9
9
|
normalizeMcpHost,
|
|
10
10
|
registerTools
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XWDA3G2U.js";
|
|
12
12
|
import {
|
|
13
13
|
capture,
|
|
14
14
|
classifyError,
|
|
@@ -20,10 +20,9 @@ import {
|
|
|
20
20
|
setMcpHost,
|
|
21
21
|
setUser,
|
|
22
22
|
shutdown
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-D2JZW2TW.js";
|
|
24
24
|
import "./chunk-NPCCDRWQ.js";
|
|
25
25
|
import "./chunk-RUFCT6DQ.js";
|
|
26
|
-
import "./chunk-MCKGQKYU.js";
|
|
27
26
|
|
|
28
27
|
// src/index.ts
|
|
29
28
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -31,7 +30,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
31
30
|
import open from "open";
|
|
32
31
|
var server = new McpServer({
|
|
33
32
|
name: "plaud",
|
|
34
|
-
version: "0.3.
|
|
33
|
+
version: "0.3.4"
|
|
35
34
|
});
|
|
36
35
|
var CALLBACK_PORT = 8199;
|
|
37
36
|
var LOGIN_TIMEOUT_MS = 12e4;
|
|
@@ -154,7 +153,7 @@ async function main() {
|
|
|
154
153
|
const sub = process.argv[2];
|
|
155
154
|
const sub2 = process.argv[3];
|
|
156
155
|
if (sub === "install") {
|
|
157
|
-
const { runInstall } = await import("./install-
|
|
156
|
+
const { runInstall } = await import("./install-ETBOS6SA.js");
|
|
158
157
|
const args = process.argv.slice(3);
|
|
159
158
|
const yes = args.some((a) => a === "--yes" || a === "-y");
|
|
160
159
|
const noLogin = args.some((a) => a === "--no-login");
|
|
@@ -162,33 +161,33 @@ async function main() {
|
|
|
162
161
|
return;
|
|
163
162
|
}
|
|
164
163
|
if (sub === "clean-plugin") {
|
|
165
|
-
const { runCleanPlugin } = await import("./setup-
|
|
164
|
+
const { runCleanPlugin } = await import("./setup-SMS45JC5.js");
|
|
166
165
|
await runCleanPlugin();
|
|
167
166
|
return;
|
|
168
167
|
}
|
|
169
168
|
if (sub === "setup" && sub2 === "codex") {
|
|
170
|
-
const { runSetupCodex } = await import("./setup-
|
|
169
|
+
const { runSetupCodex } = await import("./setup-SMS45JC5.js");
|
|
171
170
|
await runSetupCodex();
|
|
172
171
|
return;
|
|
173
172
|
}
|
|
174
173
|
if (sub === "unsetup" && sub2 === "codex") {
|
|
175
|
-
const { runUnsetupCodex } = await import("./setup-
|
|
174
|
+
const { runUnsetupCodex } = await import("./setup-SMS45JC5.js");
|
|
176
175
|
await runUnsetupCodex();
|
|
177
176
|
return;
|
|
178
177
|
}
|
|
179
178
|
if (sub === "setup") {
|
|
180
|
-
const { runSetup } = await import("./setup-
|
|
179
|
+
const { runSetup } = await import("./setup-SMS45JC5.js");
|
|
181
180
|
await runSetup();
|
|
182
181
|
return;
|
|
183
182
|
}
|
|
184
183
|
if (sub === "unsetup") {
|
|
185
|
-
const { runUnsetup } = await import("./setup-
|
|
184
|
+
const { runUnsetup } = await import("./setup-SMS45JC5.js");
|
|
186
185
|
await runUnsetup();
|
|
187
186
|
return;
|
|
188
187
|
}
|
|
189
188
|
if (sub === "http") {
|
|
190
|
-
const { startHttpServer } = await import("./server-
|
|
191
|
-
const { startMetricsServer } = await import("./server-
|
|
189
|
+
const { startHttpServer } = await import("./server-VVQEILKC.js");
|
|
190
|
+
const { startMetricsServer } = await import("./server-NKCNUA6P.js");
|
|
192
191
|
startMetricsServer();
|
|
193
192
|
startHttpServer();
|
|
194
193
|
return;
|
|
@@ -213,7 +212,7 @@ Usage:
|
|
|
213
212
|
try {
|
|
214
213
|
await initTelemetry({
|
|
215
214
|
surface: "mcp",
|
|
216
|
-
appVersion: "0.3.
|
|
215
|
+
appVersion: "0.3.4",
|
|
217
216
|
transport: "stdio"
|
|
218
217
|
});
|
|
219
218
|
} catch {
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getClient
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LOGKF7DL.js";
|
|
4
4
|
import {
|
|
5
|
+
commandPathIsStale,
|
|
5
6
|
copyToClipboard,
|
|
6
7
|
getMcpEntry,
|
|
7
|
-
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
installSkillsToClaudeCode
|
|
9
|
+
} from "./chunk-VHTXWQUE.js";
|
|
9
10
|
import {
|
|
10
11
|
skillsCombined
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-242FRP4P.js";
|
|
12
13
|
import {
|
|
13
14
|
runOAuthCallback
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-D2JZW2TW.js";
|
|
15
16
|
import "./chunk-RUFCT6DQ.js";
|
|
16
|
-
import "./chunk-MCKGQKYU.js";
|
|
17
17
|
|
|
18
18
|
// src/install.ts
|
|
19
19
|
import { createInterface } from "readline/promises";
|
|
@@ -85,12 +85,38 @@ import { existsSync as existsSync2 } from "fs";
|
|
|
85
85
|
import { homedir as homedir2 } from "os";
|
|
86
86
|
import { dirname, join as join2 } from "path";
|
|
87
87
|
var RESTART_HINT2 = "Quit Codex Desktop and reopen it.";
|
|
88
|
+
var PLAUD_HEADER = "[mcp_servers.plaud]";
|
|
88
89
|
function codexConfigPath() {
|
|
89
90
|
return join2(homedir2(), ".codex", "config.toml");
|
|
90
91
|
}
|
|
91
92
|
function quoteTomlString(value) {
|
|
92
93
|
return JSON.stringify(value);
|
|
93
94
|
}
|
|
95
|
+
function plaudBlockRange(lines) {
|
|
96
|
+
const start = lines.findIndex((l) => l.trim() === PLAUD_HEADER);
|
|
97
|
+
if (start === -1) return null;
|
|
98
|
+
let end = lines.length;
|
|
99
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
100
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
101
|
+
end = i;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { start, end };
|
|
106
|
+
}
|
|
107
|
+
function extractCommand(blockLines) {
|
|
108
|
+
for (const line of blockLines) {
|
|
109
|
+
const m = line.match(/^\s*command\s*=\s*("(?:[^"\\]|\\.)*")\s*$/);
|
|
110
|
+
if (m) {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(m[1]);
|
|
113
|
+
} catch {
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
94
120
|
function codexAdapter() {
|
|
95
121
|
return {
|
|
96
122
|
id: "codex",
|
|
@@ -102,25 +128,38 @@ function codexAdapter() {
|
|
|
102
128
|
async install({ entry }) {
|
|
103
129
|
const configPath = codexConfigPath();
|
|
104
130
|
const argsStr = entry.args.map(quoteTomlString).join(", ");
|
|
105
|
-
const
|
|
106
|
-
[mcp_servers.plaud]
|
|
131
|
+
const blockBody = `${PLAUD_HEADER}
|
|
107
132
|
command = ${quoteTomlString(entry.command)}
|
|
108
|
-
args = [${argsStr}]
|
|
109
|
-
`;
|
|
133
|
+
args = [${argsStr}]`;
|
|
110
134
|
let content = "";
|
|
111
135
|
try {
|
|
112
136
|
content = await readFile(configPath, "utf-8");
|
|
113
137
|
} catch {
|
|
114
138
|
}
|
|
115
|
-
|
|
139
|
+
const lines = content.split("\n");
|
|
140
|
+
const range = plaudBlockRange(lines);
|
|
141
|
+
if (range) {
|
|
142
|
+
const existingCommand = extractCommand(lines.slice(range.start, range.end));
|
|
143
|
+
if (!commandPathIsStale(existingCommand)) {
|
|
144
|
+
return {
|
|
145
|
+
status: "already-configured",
|
|
146
|
+
message: "already configured",
|
|
147
|
+
restartHint: RESTART_HINT2
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const rebuilt = [...lines.slice(0, range.start), ...blockBody.split("\n"), ...lines.slice(range.end)].join("\n");
|
|
151
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
152
|
+
await writeFile(configPath, rebuilt, "utf-8");
|
|
116
153
|
return {
|
|
117
|
-
status: "
|
|
118
|
-
message: "
|
|
154
|
+
status: "configured",
|
|
155
|
+
message: "repaired stale launch path (now stable npx @latest)",
|
|
119
156
|
restartHint: RESTART_HINT2
|
|
120
157
|
};
|
|
121
158
|
}
|
|
122
159
|
await mkdir(dirname(configPath), { recursive: true });
|
|
123
|
-
await writeFile(configPath, content +
|
|
160
|
+
await writeFile(configPath, content + `
|
|
161
|
+
${blockBody}
|
|
162
|
+
`, "utf-8");
|
|
124
163
|
const combined = await skillsCombined();
|
|
125
164
|
const copied = copyToClipboard(combined);
|
|
126
165
|
return {
|
|
@@ -186,19 +225,21 @@ function jsonMcpServersAdapter(spec) {
|
|
|
186
225
|
const servers = existingServers ?? {};
|
|
187
226
|
const existing = servers[serverKey];
|
|
188
227
|
if (existing) {
|
|
189
|
-
|
|
228
|
+
const existingCommand = isJsonObject(existing) && typeof existing.command === "string" ? existing.command : void 0;
|
|
229
|
+
if (entryAutoUpdates(existing) && !commandPathIsStale(existingCommand)) {
|
|
190
230
|
return {
|
|
191
231
|
status: "already-configured",
|
|
192
232
|
message: "already configured (npx @latest \u2014 auto-updates)",
|
|
193
233
|
restartHint: spec.restartHint
|
|
194
234
|
};
|
|
195
235
|
}
|
|
236
|
+
const repairing = entryAutoUpdates(existing);
|
|
196
237
|
config[rootKey] = { ...servers, [serverKey]: toEntry(ctx.entry) };
|
|
197
238
|
await mkdir2(dirname2(configPath), { recursive: true });
|
|
198
239
|
await writeFile2(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
199
240
|
return {
|
|
200
241
|
status: "configured",
|
|
201
|
-
message: "migrated to npx @latest (was pinned/local \u2014 now auto-updates)",
|
|
242
|
+
message: repairing ? "repaired stale launch path (now stable npx @latest)" : "migrated to npx @latest (was pinned/local \u2014 now auto-updates)",
|
|
202
243
|
restartHint: spec.restartHint
|
|
203
244
|
};
|
|
204
245
|
}
|
|
@@ -298,10 +339,13 @@ function zedAdapter() {
|
|
|
298
339
|
return { status: "failed", message: `failed: ${configPath} field context_servers must be a JSON object.` };
|
|
299
340
|
}
|
|
300
341
|
const servers = existingServers ?? {};
|
|
301
|
-
|
|
342
|
+
const existingPlaud = servers.plaud;
|
|
343
|
+
const existingPath = isJsonObject2(existingPlaud) && isJsonObject2(existingPlaud.command) && typeof existingPlaud.command.path === "string" ? existingPlaud.command.path : void 0;
|
|
344
|
+
if (existingPlaud && entryAutoUpdates2(existingPlaud) && !commandPathIsStale(existingPath)) {
|
|
302
345
|
return { status: "already-configured", message: "already configured (npx @latest \u2014 auto-updates)", restartHint: RESTART_HINT3 };
|
|
303
346
|
}
|
|
304
|
-
const
|
|
347
|
+
const repairing = Boolean(existingPlaud) && entryAutoUpdates2(existingPlaud);
|
|
348
|
+
const migrating = Boolean(existingPlaud);
|
|
305
349
|
config.context_servers = {
|
|
306
350
|
...servers,
|
|
307
351
|
plaud: { command: { path: entry.command, args: entry.args } }
|
|
@@ -310,7 +354,7 @@ function zedAdapter() {
|
|
|
310
354
|
await writeFile3(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
311
355
|
return {
|
|
312
356
|
status: "configured",
|
|
313
|
-
message: migrating ? "migrated to npx @latest (was pinned/local \u2014 now auto-updates). Restart Zed." : "configured. Restart Zed to load the Plaud MCP.",
|
|
357
|
+
message: repairing ? "repaired stale launch path (now stable npx @latest). Restart Zed." : migrating ? "migrated to npx @latest (was pinned/local \u2014 now auto-updates). Restart Zed." : "configured. Restart Zed to load the Plaud MCP.",
|
|
314
358
|
restartHint: RESTART_HINT3
|
|
315
359
|
};
|
|
316
360
|
}
|
|
@@ -537,8 +581,8 @@ async function runInstall(opts = {}) {
|
|
|
537
581
|
if (succeeded.some((c) => c.id === "claude-code")) {
|
|
538
582
|
process.stdout.write("\u2192 Claude Code skills... ");
|
|
539
583
|
try {
|
|
540
|
-
await
|
|
541
|
-
console.log("
|
|
584
|
+
const installed = await installSkillsToClaudeCode();
|
|
585
|
+
console.log(`installed ${installed.length} skill${installed.length === 1 ? "" : "s"} to ~/.claude/skills/.`);
|
|
542
586
|
} catch (err) {
|
|
543
587
|
console.log(`failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
544
588
|
}
|