@cryptiklemur/lattice 5.10.0 → 5.11.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/client/assets/{angular-html-BDIcxkJq.js → angular-html-BoFzmWT8.js} +1 -1
- package/dist/client/assets/{angular-ts-Bt22ouNH.js → angular-ts-DZnI8rKE.js} +1 -1
- package/dist/client/assets/{apl-p8qkxzEK.js → apl-DstVmncE.js} +1 -1
- package/dist/client/assets/{astro-CIaMc49M.js → astro-DTPCjzEx.js} +1 -1
- package/dist/client/assets/{blade-BR56EAMD.js → blade-6q42Ss3F.js} +1 -1
- package/dist/client/assets/{c-Dli0HzAh.js → c-BQDGJ-nQ.js} +1 -1
- package/dist/client/assets/{cobol-Cad15ECy.js → cobol-Dlh0WvsZ.js} +1 -1
- package/dist/client/assets/{coffee-DpyATEbF.js → coffee-DdQv129j.js} +1 -1
- package/dist/client/assets/{cpp-KN8_NFsf.js → cpp-DhbQJIv4.js} +1 -1
- package/dist/client/assets/{crystal-CuyGv0kh.js → crystal-C22kERUB.js} +1 -1
- package/dist/client/assets/{css-Cm3q4bxn.js → css-n31O5kHj.js} +1 -1
- package/dist/client/assets/{dist-BjxsMc4u.js → dist-D8okl7lw.js} +2 -2
- package/dist/client/assets/{edge-B6S7CSbx.js → edge-Cgwx-o_7.js} +1 -1
- package/dist/client/assets/{elixir-CNUy9H8T.js → elixir-DAGM2WKD.js} +1 -1
- package/dist/client/assets/{elm-CNfcWmb9.js → elm-BLw_7oO9.js} +1 -1
- package/dist/client/assets/{erb-DWebzDaI.js → erb-DCaNhYa7.js} +1 -1
- package/dist/client/assets/{git-rebase-B_Pt2ZBK.js → git-rebase-CNNhb8-g.js} +1 -1
- package/dist/client/assets/{glimmer-js-CVwoOd72.js → glimmer-js-BnZd88Wi.js} +1 -1
- package/dist/client/assets/{glimmer-ts-CjtFSxjz.js → glimmer-ts-DvFNbZu-.js} +1 -1
- package/dist/client/assets/{glsl-CP4rggAA.js → glsl-Dnrk_Jnx.js} +1 -1
- package/dist/client/assets/{graphql-Dbm6sAtp.js → graphql-DlWTPvCG.js} +1 -1
- package/dist/client/assets/{hack-Bj9y3SGf.js → hack-DQg1Ek33.js} +1 -1
- package/dist/client/assets/{haml-DRGrdf3f.js → haml-DSk45qIE.js} +1 -1
- package/dist/client/assets/{handlebars-CFKjcBMg.js → handlebars-DuLvATB2.js} +1 -1
- package/dist/client/assets/{html-Vcd4eHHg.js → html-D4DiUnLg.js} +1 -1
- package/dist/client/assets/{html-derivative-BF0YbD4L.js → html-derivative-CS5MZ6d9.js} +1 -1
- package/dist/client/assets/{http-CGVTa2NT.js → http-CkDncfer.js} +1 -1
- package/dist/client/assets/{hurl-B0GrsGqd.js → hurl-DU39oO3U.js} +1 -1
- package/dist/client/assets/{index-CX1tudsF.js → index-CHPfE1Zl.js} +129 -129
- package/dist/client/assets/index-DHUKmLLC.css +2 -0
- package/dist/client/assets/{java-BJHQqHsm.js → java-lntACKEu.js} +1 -1
- package/dist/client/assets/{javascript-CmuMsKrc.js → javascript-CxkFc6nV.js} +1 -1
- package/dist/client/assets/{jinja-JxCLeq1j.js → jinja-DolO2zO7.js} +1 -1
- package/dist/client/assets/{jison-BdgAUhei.js → jison-Cok5FPev.js} +1 -1
- package/dist/client/assets/{json-DtPissHL.js → json-BebuQPrq.js} +1 -1
- package/dist/client/assets/{jsx-DUAxxDkP.js → jsx-iLBaUyXr.js} +1 -1
- package/dist/client/assets/{julia-DxDlbL6e.js → julia-C5Dsc7cH.js} +1 -1
- package/dist/client/assets/{just-CVmAAx2R.js → just-DJYqq_9R.js} +1 -1
- package/dist/client/assets/{latex-uwxggTWA.js → latex-BTTYiKj1.js} +1 -1
- package/dist/client/assets/{liquid-xsETAJJy.js → liquid-DpAKCrOB.js} +1 -1
- package/dist/client/assets/{lua-B2Hh8PgD.js → lua-BZ6b1hko.js} +1 -1
- package/dist/client/assets/{marko-yDeGxD87.js → marko-D8VK6iGt.js} +1 -1
- package/dist/client/assets/{mdc-QMp4ieYR.js → mdc-Paa3XzwY.js} +1 -1
- package/dist/client/assets/{nginx-7gmRmcqz.js → nginx-C5k9mWtJ.js} +1 -1
- package/dist/client/assets/{nim-CA8SNY_7.js → nim-Dst6YSnE.js} +1 -1
- package/dist/client/assets/{perl-lx5nW4VC.js → perl-XhiCjgBp.js} +1 -1
- package/dist/client/assets/{php-DgHiW953.js → php-BcsPLnLU.js} +1 -1
- package/dist/client/assets/{pug-CbbB1vwb.js → pug-GLH9-eAJ.js} +1 -1
- package/dist/client/assets/{qml-COrzwCIh.js → qml-Cj_lJioE.js} +1 -1
- package/dist/client/assets/{r-Dv7pZJDH.js → r-B70aGYK5.js} +1 -1
- package/dist/client/assets/{razor-D2m8EDP5.js → razor-R3gub_zy.js} +1 -1
- package/dist/client/assets/{regexp-BXLT-jPc.js → regexp-itC0dIUJ.js} +1 -1
- package/dist/client/assets/{rst-_S6rrUYh.js → rst-DdyoV8E2.js} +1 -1
- package/dist/client/assets/{ruby-C3XO7tYY.js → ruby-BYBZsv66.js} +1 -1
- package/dist/client/assets/{sas-DP2k4iuN.js → sas-fqfqXqj1.js} +1 -1
- package/dist/client/assets/{scss-lhLFMXGn.js → scss-B-ELv6mu.js} +1 -1
- package/dist/client/assets/{shellscript-BYlBPHen.js → shellscript-BgB8TNw6.js} +1 -1
- package/dist/client/assets/{shellsession-CbVyQKWZ.js → shellsession-BLK2Dgkm.js} +1 -1
- package/dist/client/assets/{soy-Be8a0lHq.js → soy-C7_RmNrp.js} +1 -1
- package/dist/client/assets/{sql-2KxvU9YS.js → sql-AUgbUJq4.js} +1 -1
- package/dist/client/assets/{stata-BxlWftTS.js → stata-CIVqSIOr.js} +1 -1
- package/dist/client/assets/{surrealql-CJ-q86nR.js → surrealql-BzRQzc5S.js} +1 -1
- package/dist/client/assets/{svelte-Q1ml0OiY.js → svelte-BCIwEwtb.js} +1 -1
- package/dist/client/assets/{templ-BbfPZhtu.js → templ-C1hbwe4u.js} +1 -1
- package/dist/client/assets/{tex-Dcth4Gi6.js → tex-CI4tIsaP.js} +1 -1
- package/dist/client/assets/{ts-tags-BKhSOXI3.js → ts-tags-SUeikhEp.js} +1 -1
- package/dist/client/assets/{tsx-CS6iQ0XH.js → tsx-xkp7aIZs.js} +1 -1
- package/dist/client/assets/{twig-BHp31ZxS.js → twig-CGgBSAyc.js} +1 -1
- package/dist/client/assets/{typescript-16YJBTaO.js → typescript-O2YMTl_s.js} +1 -1
- package/dist/client/assets/{vue-CMKwTi4r.js → vue-DsNRxos1.js} +1 -1
- package/dist/client/assets/{vue-html-Dr8VUA2G.js → vue-html-CuY3t7bs.js} +1 -1
- package/dist/client/assets/{vue-vine-DZUqDerl.js → vue-vine-C6kSCKwY.js} +1 -1
- package/dist/client/assets/{xml-CBbBKKDC.js → xml-DafwzOLY.js} +1 -1
- package/dist/client/assets/{xsl-DWEX6PKX.js → xsl-1SGGZibr.js} +1 -1
- package/dist/client/assets/{yaml-DvKvvh3X.js → yaml-DSVhzmhr.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/sw.js +1 -1
- package/dist/server/analytics/engine.js +241 -241
- package/dist/server/assets.js +4 -4
- package/dist/server/auth/passphrase.js +13 -13
- package/dist/server/config.js +7 -7
- package/dist/server/daemon.js +93 -93
- package/dist/server/features/brainstorm.js +42 -42
- package/dist/server/features/ralph-loop.js +33 -33
- package/dist/server/features/scheduler.js +53 -53
- package/dist/server/features/specs.js +54 -54
- package/dist/server/features/sticky-notes.js +17 -17
- package/dist/server/features/superpowers.js +24 -24
- package/dist/server/handlers/analytics.js +1 -1
- package/dist/server/handlers/attachment.js +32 -32
- package/dist/server/handlers/bookmarks.js +4 -4
- package/dist/server/handlers/brainstorm.js +4 -4
- package/dist/server/handlers/chat.js +54 -54
- package/dist/server/handlers/editor.js +13 -13
- package/dist/server/handlers/fs.js +51 -51
- package/dist/server/handlers/hooks.js +20 -20
- package/dist/server/handlers/loop.js +6 -6
- package/dist/server/handlers/memory.js +44 -44
- package/dist/server/handlers/mesh.js +60 -60
- package/dist/server/handlers/notes.js +7 -7
- package/dist/server/handlers/plugins.js +174 -174
- package/dist/server/handlers/project-settings.js +26 -26
- package/dist/server/handlers/scheduler.js +6 -6
- package/dist/server/handlers/session.js +24 -24
- package/dist/server/handlers/settings.js +21 -21
- package/dist/server/handlers/skills.js +91 -91
- package/dist/server/handlers/specs.js +51 -28
- package/dist/server/handlers/terminal.js +13 -13
- package/dist/server/handlers/themes.js +21 -21
- package/dist/server/handlers/update.js +17 -17
- package/dist/server/hooks/event_forward.sh +34 -0
- package/dist/server/hooks/post_tool_use.sh +26 -0
- package/dist/server/hooks/statusline.sh +26 -0
- package/dist/server/identity.js +6 -6
- package/dist/server/index.js +111 -111
- package/dist/server/logger.js +1 -1
- package/dist/server/mesh/connector.js +78 -78
- package/dist/server/mesh/crypto.js +20 -20
- package/dist/server/mesh/discovery.js +14 -14
- package/dist/server/mesh/pairing.js +30 -30
- package/dist/server/mesh/peers.js +10 -10
- package/dist/server/mesh/proxy.js +14 -14
- package/dist/server/mesh/session-sync.js +23 -23
- package/dist/server/project/bookmarks.js +11 -11
- package/dist/server/project/context-breakdown.js +70 -70
- package/dist/server/project/file-browser.js +17 -17
- package/dist/server/project/project-files.js +68 -68
- package/dist/server/project/registry.js +10 -10
- package/dist/server/project/sdk-bridge.js +157 -157
- package/dist/server/project/session.js +201 -199
- package/dist/server/project/terminal.js +15 -15
- package/dist/server/project/warmup.js +37 -37
- package/dist/server/push.js +11 -11
- package/dist/server/runtime.js +1 -1
- package/dist/server/tls.js +15 -15
- package/dist/server/tui.js +15 -15
- package/dist/server/update-checker.js +21 -21
- package/dist/server/ws/broadcast.js +18 -18
- package/dist/server/ws/router.js +17 -17
- package/dist/shared/constants.js +8 -8
- package/package.json +2 -2
- package/dist/client/assets/index-DlfI20Gn.css +0 -2
|
@@ -4,10 +4,10 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { execSync, spawn } from "node:child_process";
|
|
5
5
|
import { registerHandler } from "../ws/router.js";
|
|
6
6
|
import { sendTo } from "../ws/broadcast.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const PLUGINS_DIR = join(homedir(), ".claude", "plugins");
|
|
8
|
+
const INSTALLED_FILE = join(PLUGINS_DIR, "installed_plugins.json");
|
|
9
|
+
const MARKETPLACES_FILE = join(PLUGINS_DIR, "known_marketplaces.json");
|
|
10
|
+
const INSTALL_COUNTS_FILE = join(PLUGINS_DIR, "install-counts-cache.json");
|
|
11
11
|
function readJsonFile(path) {
|
|
12
12
|
try {
|
|
13
13
|
if (!existsSync(path))
|
|
@@ -19,27 +19,27 @@ function readJsonFile(path) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
function getInstallCounts() {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const data = readJsonFile(INSTALL_COUNTS_FILE);
|
|
23
|
+
const map = new Map();
|
|
24
24
|
if (!data || !data.counts)
|
|
25
25
|
return map;
|
|
26
|
-
for (
|
|
26
|
+
for (let i = 0; i < data.counts.length; i++) {
|
|
27
27
|
map.set(data.counts[i].plugin, data.counts[i].unique_installs);
|
|
28
28
|
}
|
|
29
29
|
return map;
|
|
30
30
|
}
|
|
31
31
|
function readPluginJson(installPath) {
|
|
32
|
-
|
|
32
|
+
const pluginJsonPath = join(installPath, ".claude-plugin", "plugin.json");
|
|
33
33
|
return readJsonFile(pluginJsonPath);
|
|
34
34
|
}
|
|
35
35
|
function countSkills(installPath) {
|
|
36
|
-
|
|
36
|
+
const skillsDir = join(installPath, "skills");
|
|
37
37
|
if (!existsSync(skillsDir))
|
|
38
38
|
return 0;
|
|
39
39
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
for (
|
|
40
|
+
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
41
|
+
let count = 0;
|
|
42
|
+
for (let i = 0; i < entries.length; i++) {
|
|
43
43
|
if (entries[i].isDirectory())
|
|
44
44
|
count++;
|
|
45
45
|
}
|
|
@@ -50,20 +50,20 @@ function countSkills(installPath) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
function countHooks(installPath) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const hooksPath = join(installPath, "hooks", "hooks.json");
|
|
54
|
+
const data = readJsonFile(hooksPath);
|
|
55
55
|
if (!data || !data.hooks)
|
|
56
56
|
return 0;
|
|
57
57
|
return Object.keys(data.hooks).length;
|
|
58
58
|
}
|
|
59
59
|
function countRules(installPath) {
|
|
60
|
-
|
|
60
|
+
const rulesDir = join(installPath, "rules");
|
|
61
61
|
if (!existsSync(rulesDir))
|
|
62
62
|
return 0;
|
|
63
63
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
for (
|
|
64
|
+
const entries = readdirSync(rulesDir);
|
|
65
|
+
let count = 0;
|
|
66
|
+
for (let i = 0; i < entries.length; i++) {
|
|
67
67
|
if (entries[i].endsWith(".md"))
|
|
68
68
|
count++;
|
|
69
69
|
}
|
|
@@ -74,21 +74,21 @@ function countRules(installPath) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
function getInstalledPlugins() {
|
|
77
|
-
|
|
77
|
+
const data = readJsonFile(INSTALLED_FILE);
|
|
78
78
|
if (!data || !data.plugins)
|
|
79
79
|
return [];
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
for (
|
|
90
|
-
|
|
91
|
-
|
|
80
|
+
const installCounts = getInstallCounts();
|
|
81
|
+
const plugins = [];
|
|
82
|
+
const keys = Object.keys(data.plugins);
|
|
83
|
+
for (let k = 0; k < keys.length; k++) {
|
|
84
|
+
const key = keys[k];
|
|
85
|
+
const entries = data.plugins[key];
|
|
86
|
+
const atIdx = key.lastIndexOf("@");
|
|
87
|
+
const pluginName = atIdx > 0 ? key.slice(0, atIdx) : key;
|
|
88
|
+
const marketplace = atIdx > 0 ? key.slice(atIdx + 1) : "";
|
|
89
|
+
for (let e = 0; e < entries.length; e++) {
|
|
90
|
+
const entry = entries[e];
|
|
91
|
+
const meta = readPluginJson(entry.installPath);
|
|
92
92
|
plugins.push({
|
|
93
93
|
name: pluginName,
|
|
94
94
|
marketplace: marketplace,
|
|
@@ -111,13 +111,13 @@ function getInstalledPlugins() {
|
|
|
111
111
|
return plugins;
|
|
112
112
|
}
|
|
113
113
|
function getMarketplaces() {
|
|
114
|
-
|
|
114
|
+
const data = readJsonFile(MARKETPLACES_FILE);
|
|
115
115
|
if (!data)
|
|
116
116
|
return [];
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
for (
|
|
120
|
-
|
|
117
|
+
const result = [];
|
|
118
|
+
const keys = Object.keys(data);
|
|
119
|
+
for (let i = 0; i < keys.length; i++) {
|
|
120
|
+
const entry = data[keys[i]];
|
|
121
121
|
result.push({
|
|
122
122
|
name: keys[i],
|
|
123
123
|
source: entry.source,
|
|
@@ -128,48 +128,48 @@ function getMarketplaces() {
|
|
|
128
128
|
return result;
|
|
129
129
|
}
|
|
130
130
|
function searchMarketplacePlugins(query, marketplaceFilter) {
|
|
131
|
-
|
|
131
|
+
const marketplaces = readJsonFile(MARKETPLACES_FILE);
|
|
132
132
|
if (!marketplaces)
|
|
133
133
|
return [];
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
const installCounts = getInstallCounts();
|
|
135
|
+
const installedData = readJsonFile(INSTALLED_FILE);
|
|
136
|
+
const installedKeys = new Set();
|
|
137
|
+
const installedVersions = new Map();
|
|
138
138
|
if (installedData && installedData.plugins) {
|
|
139
|
-
|
|
140
|
-
for (
|
|
139
|
+
const iKeys = Object.keys(installedData.plugins);
|
|
140
|
+
for (let ik = 0; ik < iKeys.length; ik++) {
|
|
141
141
|
installedKeys.add(iKeys[ik]);
|
|
142
|
-
|
|
142
|
+
const versions = installedData.plugins[iKeys[ik]];
|
|
143
143
|
if (versions.length > 0) {
|
|
144
144
|
installedVersions.set(iKeys[ik], versions[0].version);
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
for (
|
|
152
|
-
|
|
148
|
+
const results = [];
|
|
149
|
+
const lowerQuery = query.toLowerCase();
|
|
150
|
+
const mKeys = Object.keys(marketplaces);
|
|
151
|
+
for (let m = 0; m < mKeys.length; m++) {
|
|
152
|
+
const mName = mKeys[m];
|
|
153
153
|
if (marketplaceFilter && mName !== marketplaceFilter)
|
|
154
154
|
continue;
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
const mkt = marketplaces[mName];
|
|
156
|
+
const pluginsDir = join(mkt.installLocation, "plugins");
|
|
157
157
|
if (!existsSync(pluginsDir))
|
|
158
158
|
continue;
|
|
159
159
|
try {
|
|
160
|
-
|
|
161
|
-
for (
|
|
160
|
+
const pluginDirs = readdirSync(pluginsDir, { withFileTypes: true });
|
|
161
|
+
for (let p = 0; p < pluginDirs.length; p++) {
|
|
162
162
|
if (!pluginDirs[p].isDirectory())
|
|
163
163
|
continue;
|
|
164
|
-
|
|
164
|
+
const dirName = pluginDirs[p].name;
|
|
165
165
|
if (dirName.toLowerCase().indexOf(lowerQuery) === -1) {
|
|
166
|
-
|
|
166
|
+
const meta = readPluginJson(join(pluginsDir, dirName));
|
|
167
167
|
if (!meta || meta.description.toLowerCase().indexOf(lowerQuery) === -1) {
|
|
168
168
|
continue;
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
const pluginMeta = readPluginJson(join(pluginsDir, dirName));
|
|
172
|
+
const key = dirName + "@" + mName;
|
|
173
173
|
results.push({
|
|
174
174
|
name: dirName,
|
|
175
175
|
marketplace: mName,
|
|
@@ -184,71 +184,71 @@ function searchMarketplacePlugins(query, marketplaceFilter) {
|
|
|
184
184
|
catch { }
|
|
185
185
|
}
|
|
186
186
|
results.sort(function (a, b) {
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
const ai = a.installs ?? 0;
|
|
188
|
+
const bi = b.installs ?? 0;
|
|
189
189
|
return bi - ai;
|
|
190
190
|
});
|
|
191
191
|
return results;
|
|
192
192
|
}
|
|
193
193
|
function parseFrontmatter(content) {
|
|
194
|
-
|
|
194
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
195
195
|
if (!match)
|
|
196
196
|
return { name: "", description: "" };
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
for (
|
|
202
|
-
|
|
203
|
-
|
|
197
|
+
const yaml = match[1];
|
|
198
|
+
let name = "";
|
|
199
|
+
let desc = "";
|
|
200
|
+
const lines = yaml.split(/\r?\n/);
|
|
201
|
+
for (let i = 0; i < lines.length; i++) {
|
|
202
|
+
const line = lines[i];
|
|
203
|
+
const nameMatch = line.match(/^name:\s*(.+)/);
|
|
204
204
|
if (nameMatch)
|
|
205
205
|
name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
206
|
-
|
|
206
|
+
const descMatch = line.match(/^description:\s*(.+)/);
|
|
207
207
|
if (descMatch)
|
|
208
208
|
desc = descMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
209
209
|
}
|
|
210
210
|
return { name, description: desc };
|
|
211
211
|
}
|
|
212
212
|
function getPluginDetails(pluginName, marketplace) {
|
|
213
|
-
|
|
213
|
+
const data = readJsonFile(INSTALLED_FILE);
|
|
214
214
|
if (!data || !data.plugins)
|
|
215
215
|
return null;
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
const key = pluginName + "@" + marketplace;
|
|
217
|
+
const entries = data.plugins[key];
|
|
218
218
|
if (!entries || entries.length === 0)
|
|
219
219
|
return null;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
const entry = entries[0];
|
|
221
|
+
const meta = readPluginJson(entry.installPath);
|
|
222
|
+
const skills = [];
|
|
223
|
+
const skillsDir = join(entry.installPath, "skills");
|
|
224
224
|
if (existsSync(skillsDir)) {
|
|
225
225
|
try {
|
|
226
|
-
|
|
227
|
-
for (
|
|
226
|
+
const skillDirs = readdirSync(skillsDir, { withFileTypes: true });
|
|
227
|
+
for (let s = 0; s < skillDirs.length; s++) {
|
|
228
228
|
if (!skillDirs[s].isDirectory())
|
|
229
229
|
continue;
|
|
230
|
-
|
|
230
|
+
const skillFile = join(skillsDir, skillDirs[s].name, "SKILL.md");
|
|
231
231
|
if (existsSync(skillFile)) {
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
const content = readFileSync(skillFile, "utf-8");
|
|
233
|
+
const fm = parseFrontmatter(content);
|
|
234
234
|
skills.push({ name: fm.name || skillDirs[s].name, description: fm.description });
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
catch { }
|
|
239
239
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
let hooks = {};
|
|
241
|
+
const hooksPath = join(entry.installPath, "hooks", "hooks.json");
|
|
242
|
+
const hooksData = readJsonFile(hooksPath);
|
|
243
243
|
if (hooksData && hooksData.hooks) {
|
|
244
244
|
hooks = hooksData.hooks;
|
|
245
245
|
}
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
const rules = [];
|
|
247
|
+
const rulesDir = join(entry.installPath, "rules");
|
|
248
248
|
if (existsSync(rulesDir)) {
|
|
249
249
|
try {
|
|
250
|
-
|
|
251
|
-
for (
|
|
250
|
+
const ruleFiles = readdirSync(rulesDir);
|
|
251
|
+
for (let r = 0; r < ruleFiles.length; r++) {
|
|
252
252
|
if (ruleFiles[r].endsWith(".md")) {
|
|
253
253
|
rules.push(ruleFiles[r]);
|
|
254
254
|
}
|
|
@@ -275,19 +275,19 @@ function getPluginDetails(pluginName, marketplace) {
|
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
277
|
export function getPluginMcpServers() {
|
|
278
|
-
|
|
278
|
+
const data = readJsonFile(INSTALLED_FILE);
|
|
279
279
|
if (!data || !data.plugins)
|
|
280
280
|
return {};
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
for (
|
|
284
|
-
|
|
285
|
-
for (
|
|
286
|
-
|
|
287
|
-
|
|
281
|
+
const servers = {};
|
|
282
|
+
const keys = Object.keys(data.plugins);
|
|
283
|
+
for (let k = 0; k < keys.length; k++) {
|
|
284
|
+
const entries = data.plugins[keys[k]];
|
|
285
|
+
for (let e = 0; e < entries.length; e++) {
|
|
286
|
+
const mcpPath = join(entries[e].installPath, ".mcp.json");
|
|
287
|
+
const mcpData = readJsonFile(mcpPath);
|
|
288
288
|
if (mcpData && mcpData.mcpServers) {
|
|
289
|
-
|
|
290
|
-
for (
|
|
289
|
+
const sKeys = Object.keys(mcpData.mcpServers);
|
|
290
|
+
for (let s = 0; s < sKeys.length; s++) {
|
|
291
291
|
servers[sKeys[s]] = mcpData.mcpServers[sKeys[s]];
|
|
292
292
|
}
|
|
293
293
|
}
|
|
@@ -296,28 +296,28 @@ export function getPluginMcpServers() {
|
|
|
296
296
|
return servers;
|
|
297
297
|
}
|
|
298
298
|
export function getInstalledPluginCount() {
|
|
299
|
-
|
|
299
|
+
const data = readJsonFile(INSTALLED_FILE);
|
|
300
300
|
if (!data || !data.plugins)
|
|
301
301
|
return 0;
|
|
302
302
|
return Object.keys(data.plugins).length;
|
|
303
303
|
}
|
|
304
304
|
export function getPluginSkillRuleTokenEstimate() {
|
|
305
|
-
|
|
305
|
+
const data = readJsonFile(INSTALLED_FILE);
|
|
306
306
|
if (!data || !data.plugins)
|
|
307
307
|
return 0;
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
for (
|
|
311
|
-
|
|
312
|
-
for (
|
|
313
|
-
|
|
308
|
+
let totalChars = 0;
|
|
309
|
+
const keys = Object.keys(data.plugins);
|
|
310
|
+
for (let k = 0; k < keys.length; k++) {
|
|
311
|
+
const entries = data.plugins[keys[k]];
|
|
312
|
+
for (let e = 0; e < entries.length; e++) {
|
|
313
|
+
const skillsDir = join(entries[e].installPath, "skills");
|
|
314
314
|
if (existsSync(skillsDir)) {
|
|
315
315
|
try {
|
|
316
|
-
|
|
317
|
-
for (
|
|
316
|
+
const dirs = readdirSync(skillsDir, { withFileTypes: true });
|
|
317
|
+
for (let d = 0; d < dirs.length; d++) {
|
|
318
318
|
if (!dirs[d].isDirectory())
|
|
319
319
|
continue;
|
|
320
|
-
|
|
320
|
+
const skillFile = join(skillsDir, dirs[d].name, "SKILL.md");
|
|
321
321
|
if (existsSync(skillFile)) {
|
|
322
322
|
totalChars += readFileSync(skillFile, "utf-8").length;
|
|
323
323
|
}
|
|
@@ -325,11 +325,11 @@ export function getPluginSkillRuleTokenEstimate() {
|
|
|
325
325
|
}
|
|
326
326
|
catch { }
|
|
327
327
|
}
|
|
328
|
-
|
|
328
|
+
const rulesDir = join(entries[e].installPath, "rules");
|
|
329
329
|
if (existsSync(rulesDir)) {
|
|
330
330
|
try {
|
|
331
|
-
|
|
332
|
-
for (
|
|
331
|
+
const ruleFiles = readdirSync(rulesDir);
|
|
332
|
+
for (let r = 0; r < ruleFiles.length; r++) {
|
|
333
333
|
if (ruleFiles[r].endsWith(".md")) {
|
|
334
334
|
totalChars += readFileSync(join(rulesDir, ruleFiles[r]), "utf-8").length;
|
|
335
335
|
}
|
|
@@ -350,7 +350,7 @@ function whichBinary(name) {
|
|
|
350
350
|
return false;
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
|
-
|
|
353
|
+
const LSP_BINARY_MAP = {
|
|
354
354
|
"typescript-lsp": "typescript-language-server",
|
|
355
355
|
"pyright-lsp": "pyright-langserver",
|
|
356
356
|
"gopls-lsp": "gopls",
|
|
@@ -365,42 +365,42 @@ var LSP_BINARY_MAP = {
|
|
|
365
365
|
"jdtls-lsp": "jdtls",
|
|
366
366
|
};
|
|
367
367
|
function getPluginErrors() {
|
|
368
|
-
|
|
368
|
+
const data = readJsonFile(INSTALLED_FILE);
|
|
369
369
|
if (!data || !data.plugins)
|
|
370
370
|
return [];
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
for (
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
for (
|
|
380
|
-
|
|
381
|
-
|
|
371
|
+
const errors = [];
|
|
372
|
+
const keys = Object.keys(data.plugins);
|
|
373
|
+
for (let k = 0; k < keys.length; k++) {
|
|
374
|
+
const key = keys[k];
|
|
375
|
+
const entries = data.plugins[key];
|
|
376
|
+
const atIdx = key.lastIndexOf("@");
|
|
377
|
+
const pluginName = atIdx > 0 ? key.slice(0, atIdx) : key;
|
|
378
|
+
const marketplace = atIdx > 0 ? key.slice(atIdx + 1) : "";
|
|
379
|
+
for (let e = 0; e < entries.length; e++) {
|
|
380
|
+
const entry = entries[e];
|
|
381
|
+
const errs = [];
|
|
382
382
|
if (!existsSync(entry.installPath)) {
|
|
383
383
|
errs.push("Install path does not exist: " + entry.installPath);
|
|
384
384
|
}
|
|
385
385
|
else {
|
|
386
386
|
try {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
for (
|
|
390
|
-
|
|
387
|
+
const output = execSync("claude plugin validate " + JSON.stringify(entry.installPath) + " 2>&1", { encoding: "utf-8", timeout: 10000 });
|
|
388
|
+
const errorLines = output.split("\n").filter(function (l) { return l.trim().startsWith("❯") || l.trim().startsWith("✘"); });
|
|
389
|
+
for (let el = 0; el < errorLines.length; el++) {
|
|
390
|
+
const line = errorLines[el].trim();
|
|
391
391
|
if (line.startsWith("❯")) {
|
|
392
392
|
errs.push(line.slice(1).trim());
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
catch (validateErr) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
for (
|
|
397
|
+
const stderr = String(validateErr);
|
|
398
|
+
const stderrLines = stderr.split("\n").filter(function (l) { return l.trim().startsWith("❯"); });
|
|
399
|
+
for (let sl = 0; sl < stderrLines.length; sl++) {
|
|
400
400
|
errs.push(stderrLines[sl].trim().slice(1).trim());
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
|
-
|
|
403
|
+
const lspBinary = LSP_BINARY_MAP[pluginName];
|
|
404
404
|
if (lspBinary && !whichBinary(lspBinary)) {
|
|
405
405
|
errs.push("Executable not found in $PATH: \"" + lspBinary + "\"");
|
|
406
406
|
}
|
|
@@ -413,39 +413,39 @@ function getPluginErrors() {
|
|
|
413
413
|
return errors;
|
|
414
414
|
}
|
|
415
415
|
function discoverPlugins() {
|
|
416
|
-
|
|
416
|
+
const marketplaces = readJsonFile(MARKETPLACES_FILE);
|
|
417
417
|
if (!marketplaces)
|
|
418
418
|
return [];
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
419
|
+
const installCounts = getInstallCounts();
|
|
420
|
+
const installedData = readJsonFile(INSTALLED_FILE);
|
|
421
|
+
const installedKeys = new Set();
|
|
422
|
+
const installedVersions = new Map();
|
|
423
423
|
if (installedData && installedData.plugins) {
|
|
424
|
-
|
|
425
|
-
for (
|
|
424
|
+
const iKeys = Object.keys(installedData.plugins);
|
|
425
|
+
for (let ik = 0; ik < iKeys.length; ik++) {
|
|
426
426
|
installedKeys.add(iKeys[ik]);
|
|
427
|
-
|
|
427
|
+
const versions = installedData.plugins[iKeys[ik]];
|
|
428
428
|
if (versions.length > 0) {
|
|
429
429
|
installedVersions.set(iKeys[ik], versions[0].version);
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
for (
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
433
|
+
const results = [];
|
|
434
|
+
const mKeys = Object.keys(marketplaces);
|
|
435
|
+
for (let m = 0; m < mKeys.length; m++) {
|
|
436
|
+
const mName = mKeys[m];
|
|
437
|
+
const mkt = marketplaces[mName];
|
|
438
|
+
const pluginsDir = join(mkt.installLocation, "plugins");
|
|
439
439
|
if (!existsSync(pluginsDir))
|
|
440
440
|
continue;
|
|
441
441
|
try {
|
|
442
|
-
|
|
443
|
-
for (
|
|
442
|
+
const pluginDirs = readdirSync(pluginsDir, { withFileTypes: true });
|
|
443
|
+
for (let p = 0; p < pluginDirs.length; p++) {
|
|
444
444
|
if (!pluginDirs[p].isDirectory())
|
|
445
445
|
continue;
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
446
|
+
const dirName = pluginDirs[p].name;
|
|
447
|
+
const meta = readPluginJson(join(pluginsDir, dirName));
|
|
448
|
+
const key = dirName + "@" + mName;
|
|
449
449
|
results.push({
|
|
450
450
|
name: dirName,
|
|
451
451
|
marketplace: mName,
|
|
@@ -460,43 +460,43 @@ function discoverPlugins() {
|
|
|
460
460
|
catch { }
|
|
461
461
|
}
|
|
462
462
|
results.sort(function (a, b) {
|
|
463
|
-
|
|
464
|
-
|
|
463
|
+
const ai = a.installs ?? 0;
|
|
464
|
+
const bi = b.installs ?? 0;
|
|
465
465
|
return bi - ai;
|
|
466
466
|
});
|
|
467
467
|
return results;
|
|
468
468
|
}
|
|
469
469
|
registerHandler("plugin", function (clientId, message) {
|
|
470
470
|
if (message.type === "plugin:list") {
|
|
471
|
-
|
|
471
|
+
const plugins = getInstalledPlugins();
|
|
472
472
|
sendTo(clientId, { type: "plugin:list_result", plugins: plugins });
|
|
473
473
|
return;
|
|
474
474
|
}
|
|
475
475
|
if (message.type === "plugin:marketplaces") {
|
|
476
|
-
|
|
476
|
+
const marketplaces = getMarketplaces();
|
|
477
477
|
sendTo(clientId, { type: "plugin:marketplaces_result", marketplaces: marketplaces });
|
|
478
478
|
return;
|
|
479
479
|
}
|
|
480
480
|
if (message.type === "plugin:search") {
|
|
481
|
-
|
|
482
|
-
|
|
481
|
+
const searchMsg = message;
|
|
482
|
+
const query = searchMsg.query.trim();
|
|
483
483
|
if (!query) {
|
|
484
484
|
sendTo(clientId, { type: "plugin:search_result", query: query, plugins: [], count: 0 });
|
|
485
485
|
return;
|
|
486
486
|
}
|
|
487
|
-
|
|
487
|
+
const found = searchMarketplacePlugins(query, searchMsg.marketplace);
|
|
488
488
|
sendTo(clientId, { type: "plugin:search_result", query: query, plugins: found, count: found.length });
|
|
489
489
|
return;
|
|
490
490
|
}
|
|
491
491
|
if (message.type === "plugin:install") {
|
|
492
|
-
|
|
493
|
-
|
|
492
|
+
const installMsg = message;
|
|
493
|
+
const installArg = installMsg.name + "@" + installMsg.marketplace;
|
|
494
494
|
try {
|
|
495
|
-
|
|
495
|
+
const proc = spawn("claude", ["plugin", "install", installArg], {
|
|
496
496
|
cwd: homedir(),
|
|
497
497
|
stdio: ["ignore", "pipe", "pipe"],
|
|
498
498
|
});
|
|
499
|
-
|
|
499
|
+
const timeout = setTimeout(function () {
|
|
500
500
|
proc.kill();
|
|
501
501
|
}, 120000);
|
|
502
502
|
proc.on("close", function (code) {
|
|
@@ -516,14 +516,14 @@ registerHandler("plugin", function (clientId, message) {
|
|
|
516
516
|
return;
|
|
517
517
|
}
|
|
518
518
|
if (message.type === "plugin:uninstall") {
|
|
519
|
-
|
|
520
|
-
|
|
519
|
+
const uninstallMsg = message;
|
|
520
|
+
const uninstallArg = uninstallMsg.name + "@" + uninstallMsg.marketplace;
|
|
521
521
|
try {
|
|
522
|
-
|
|
522
|
+
const uninstallProc = spawn("claude", ["plugin", "uninstall", uninstallArg], {
|
|
523
523
|
cwd: homedir(),
|
|
524
524
|
stdio: ["ignore", "pipe", "pipe"],
|
|
525
525
|
});
|
|
526
|
-
|
|
526
|
+
const uninstallTimeout = setTimeout(function () {
|
|
527
527
|
uninstallProc.kill();
|
|
528
528
|
}, 60000);
|
|
529
529
|
uninstallProc.on("close", function (code) {
|
|
@@ -543,14 +543,14 @@ registerHandler("plugin", function (clientId, message) {
|
|
|
543
543
|
return;
|
|
544
544
|
}
|
|
545
545
|
if (message.type === "plugin:update") {
|
|
546
|
-
|
|
547
|
-
|
|
546
|
+
const updateMsg = message;
|
|
547
|
+
const updateArg = updateMsg.name + "@" + updateMsg.marketplace;
|
|
548
548
|
try {
|
|
549
|
-
|
|
549
|
+
const updateProc = spawn("claude", ["plugin", "update", updateArg], {
|
|
550
550
|
cwd: homedir(),
|
|
551
551
|
stdio: ["ignore", "pipe", "pipe"],
|
|
552
552
|
});
|
|
553
|
-
|
|
553
|
+
const updateTimeout = setTimeout(function () {
|
|
554
554
|
updateProc.kill();
|
|
555
555
|
}, 120000);
|
|
556
556
|
updateProc.on("close", function (code) {
|
|
@@ -570,8 +570,8 @@ registerHandler("plugin", function (clientId, message) {
|
|
|
570
570
|
return;
|
|
571
571
|
}
|
|
572
572
|
if (message.type === "plugin:details") {
|
|
573
|
-
|
|
574
|
-
|
|
573
|
+
const detailsMsg = message;
|
|
574
|
+
const details = getPluginDetails(detailsMsg.name, detailsMsg.marketplace);
|
|
575
575
|
if (details) {
|
|
576
576
|
sendTo(clientId, { type: "plugin:details_result", plugin: details });
|
|
577
577
|
}
|
|
@@ -581,12 +581,12 @@ registerHandler("plugin", function (clientId, message) {
|
|
|
581
581
|
return;
|
|
582
582
|
}
|
|
583
583
|
if (message.type === "plugin:discover") {
|
|
584
|
-
|
|
584
|
+
const allPlugins = discoverPlugins();
|
|
585
585
|
sendTo(clientId, { type: "plugin:discover_result", plugins: allPlugins });
|
|
586
586
|
return;
|
|
587
587
|
}
|
|
588
588
|
if (message.type === "plugin:errors") {
|
|
589
|
-
|
|
589
|
+
const pluginErrors = getPluginErrors();
|
|
590
590
|
sendTo(clientId, { type: "plugin:errors_result", errors: pluginErrors });
|
|
591
591
|
return;
|
|
592
592
|
}
|