kenmark-skills 1.1.4 → 1.1.5
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/package.json
CHANGED
package/scripts/interactive.js
CHANGED
|
@@ -140,6 +140,70 @@ async function confirmPlan(lines, dryRun = false) {
|
|
|
140
140
|
return false;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* @param {Array<{id: string, name: string, defaultSelected?: boolean}>} packs
|
|
145
|
+
* @returns {Promise<string[]>} selected pack ids
|
|
146
|
+
*/
|
|
147
|
+
async function promptSelectPacks(packs) {
|
|
148
|
+
const rl = createRl();
|
|
149
|
+
console.log("\nSelect packs to install:\n");
|
|
150
|
+
packs.forEach((p, i) => {
|
|
151
|
+
const mark = p.defaultSelected ? " [default]" : "";
|
|
152
|
+
console.log(` ${i + 1}) ${p.id}${mark} — ${p.name}`);
|
|
153
|
+
});
|
|
154
|
+
console.log("\nEnter: number(s) 1,2 · ids impeccable,ecc · all · defaults · Enter for defaults\n");
|
|
155
|
+
const answer = await ask(rl, "Choice> ");
|
|
156
|
+
rl.close();
|
|
157
|
+
if (!answer) {
|
|
158
|
+
return packs.filter((p) => p.defaultSelected).map((p) => p.id);
|
|
159
|
+
}
|
|
160
|
+
const lower = answer.toLowerCase();
|
|
161
|
+
if (lower === "all") return packs.map((p) => p.id);
|
|
162
|
+
if (lower === "defaults" || lower === "default" || lower === "d") {
|
|
163
|
+
return packs.filter((p) => p.defaultSelected).map((p) => p.id);
|
|
164
|
+
}
|
|
165
|
+
const nums = lower.split(/[\s,]+/).filter(Boolean);
|
|
166
|
+
const byNum = [];
|
|
167
|
+
for (const part of nums) {
|
|
168
|
+
const n = parseInt(part, 10);
|
|
169
|
+
if (!Number.isNaN(n) && n >= 1 && n <= packs.length) {
|
|
170
|
+
byNum.push(packs[n - 1].id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (byNum.length > 0) return [...new Set(byNum)];
|
|
174
|
+
return answer.split(",").map((s) => s.trim()).filter(Boolean);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {{install?: {profiles?: Array<{id: string, description: string}>, defaultProfile?: string}}} pack
|
|
179
|
+
* @param {string|null} preset
|
|
180
|
+
* @returns {Promise<string>}
|
|
181
|
+
*/
|
|
182
|
+
async function promptEccProfile(pack, preset) {
|
|
183
|
+
if (preset) return preset;
|
|
184
|
+
const profiles = pack.install?.profiles;
|
|
185
|
+
if (!profiles?.length) {
|
|
186
|
+
return pack.install?.defaultProfile || "core";
|
|
187
|
+
}
|
|
188
|
+
const rl = createRl();
|
|
189
|
+
console.log("\nECC install profile:");
|
|
190
|
+
profiles.forEach((p, i) => {
|
|
191
|
+
console.log(` ${i + 1}) ${p.id} — ${p.description}`);
|
|
192
|
+
});
|
|
193
|
+
const defaultId = pack.install.defaultProfile || "core";
|
|
194
|
+
const answer = await ask(rl, `Profile [1-${profiles.length} or id] (default ${defaultId}): `);
|
|
195
|
+
rl.close();
|
|
196
|
+
if (!answer) return defaultId;
|
|
197
|
+
const num = parseInt(answer, 10);
|
|
198
|
+
if (!Number.isNaN(num) && num >= 1 && num <= profiles.length) {
|
|
199
|
+
return profiles[num - 1].id;
|
|
200
|
+
}
|
|
201
|
+
const byId = profiles.find((p) => p.id === answer);
|
|
202
|
+
if (byId) return byId.id;
|
|
203
|
+
console.error(`Unknown profile "${answer}", using ${defaultId}.`);
|
|
204
|
+
return defaultId;
|
|
205
|
+
}
|
|
206
|
+
|
|
143
207
|
function banner(title, subtitle) {
|
|
144
208
|
console.log(`\n${"═".repeat(60)}`);
|
|
145
209
|
console.log(` ${title}`);
|
|
@@ -156,6 +220,8 @@ module.exports = {
|
|
|
156
220
|
promptScope,
|
|
157
221
|
promptAction,
|
|
158
222
|
promptIde,
|
|
223
|
+
promptSelectPacks,
|
|
224
|
+
promptEccProfile,
|
|
159
225
|
confirmPlan,
|
|
160
226
|
banner
|
|
161
227
|
};
|
package/scripts/skills-init.js
CHANGED
|
@@ -7,9 +7,12 @@ const {
|
|
|
7
7
|
promptScope,
|
|
8
8
|
promptIde,
|
|
9
9
|
promptYesNo,
|
|
10
|
+
promptSelectPacks,
|
|
11
|
+
promptEccProfile,
|
|
10
12
|
confirmPlan,
|
|
11
13
|
banner
|
|
12
14
|
} = require("./interactive");
|
|
15
|
+
const { loadCatalog } = require("./recommended-catalog");
|
|
13
16
|
|
|
14
17
|
const repoRoot = path.resolve(__dirname, "..");
|
|
15
18
|
const setupScript = path.join(__dirname, "setup-skills.js");
|
|
@@ -135,6 +138,8 @@ async function run() {
|
|
|
135
138
|
let ideArg = args.ide;
|
|
136
139
|
let installKenmark = !args.recommendedOnly;
|
|
137
140
|
let installRecommended = !args.skipRecommended;
|
|
141
|
+
let selectedPacks = [];
|
|
142
|
+
let eccProfile = null;
|
|
138
143
|
|
|
139
144
|
if (interactive) {
|
|
140
145
|
if (!args.recommendedOnly && !args.skipRecommended) {
|
|
@@ -148,6 +153,25 @@ async function run() {
|
|
|
148
153
|
installRecommended = await promptYesNo("Install only curated recommended packs?", true);
|
|
149
154
|
}
|
|
150
155
|
}
|
|
156
|
+
if (installRecommended) {
|
|
157
|
+
const catalog = loadCatalog();
|
|
158
|
+
const packs = catalog.packs || [];
|
|
159
|
+
if (packs.length === 0) {
|
|
160
|
+
console.log("No curated packs available; skipping recommended step.");
|
|
161
|
+
installRecommended = false;
|
|
162
|
+
} else {
|
|
163
|
+
selectedPacks = await promptSelectPacks(packs);
|
|
164
|
+
if (selectedPacks.length === 0) {
|
|
165
|
+
console.log("No packs chosen; skipping recommended step.");
|
|
166
|
+
installRecommended = false;
|
|
167
|
+
} else {
|
|
168
|
+
const eccPack = packs.find((p) => p.id === "ecc");
|
|
169
|
+
if (eccPack && selectedPacks.includes("ecc")) {
|
|
170
|
+
eccProfile = await promptEccProfile(eccPack, null);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
151
175
|
if (installKenmark || installRecommended) {
|
|
152
176
|
if (!scope) scope = await promptScope("global");
|
|
153
177
|
}
|
|
@@ -170,7 +194,9 @@ async function run() {
|
|
|
170
194
|
plan.push(`Kenmark skills → ${scope} (${ideLabel})`);
|
|
171
195
|
}
|
|
172
196
|
if (installRecommended) {
|
|
173
|
-
|
|
197
|
+
const label = selectedPacks.length > 0 ? selectedPacks.join(", ") : "defaults";
|
|
198
|
+
plan.push(`Recommended packs → ${scope}: ${label}`);
|
|
199
|
+
if (eccProfile) plan.push(` ECC profile: ${eccProfile}`);
|
|
174
200
|
}
|
|
175
201
|
plan.push("Tip: run init-brain in your agent chat to bootstrap brain/ in a repo");
|
|
176
202
|
|
|
@@ -212,8 +238,15 @@ async function run() {
|
|
|
212
238
|
}
|
|
213
239
|
|
|
214
240
|
if (installRecommended) {
|
|
215
|
-
const recArgs = [scope === "project" ? "--project" : "--global"
|
|
241
|
+
const recArgs = [scope === "project" ? "--project" : "--global"];
|
|
242
|
+
if (selectedPacks.length > 0) {
|
|
243
|
+
recArgs.push("--ids", selectedPacks.join(","));
|
|
244
|
+
} else {
|
|
245
|
+
recArgs.push("--all");
|
|
246
|
+
}
|
|
247
|
+
if (eccProfile) recArgs.push("--ecc-profile", eccProfile);
|
|
216
248
|
if (args.dryRun) recArgs.push("--dry-run");
|
|
249
|
+
recArgs.push("-y");
|
|
217
250
|
const result = runNode(recommendedScript, recArgs, args.dryRun, "Recommended packs");
|
|
218
251
|
if (!args.dryRun && result.status !== 0) process.exit(result.status || 1);
|
|
219
252
|
}
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
3
|
const { spawnSync } = require("child_process");
|
|
6
4
|
const {
|
|
7
5
|
wantsInteractive,
|
|
8
6
|
promptScope,
|
|
7
|
+
promptSelectPacks,
|
|
8
|
+
promptEccProfile,
|
|
9
9
|
confirmPlan,
|
|
10
10
|
banner
|
|
11
11
|
} = require("./interactive");
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const repoRoot = path.resolve(__dirname, "..");
|
|
15
|
-
const catalogPath = path.join(
|
|
16
|
-
repoRoot,
|
|
17
|
-
"skills",
|
|
18
|
-
"user-skills",
|
|
19
|
-
"recommended-catalog.json"
|
|
20
|
-
);
|
|
12
|
+
const { loadCatalog } = require("./recommended-catalog");
|
|
21
13
|
|
|
22
14
|
function printUsage() {
|
|
23
15
|
console.log("Usage: node scripts/skills-install-recommended.js [options]");
|
|
@@ -87,14 +79,6 @@ function parseArgs(argv) {
|
|
|
87
79
|
return args;
|
|
88
80
|
}
|
|
89
81
|
|
|
90
|
-
function loadCatalog() {
|
|
91
|
-
if (!fs.existsSync(catalogPath)) {
|
|
92
|
-
console.error(`Catalog not found: ${catalogPath}`);
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
95
|
-
return JSON.parse(fs.readFileSync(catalogPath, "utf8"));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
82
|
function resolveInstallCommand(pack, scope, eccProfile) {
|
|
99
83
|
const block = pack.install?.[scope];
|
|
100
84
|
if (!block?.command) {
|
|
@@ -169,72 +153,6 @@ function verifyPack(pack, scope) {
|
|
|
169
153
|
return result.status === 0;
|
|
170
154
|
}
|
|
171
155
|
|
|
172
|
-
function createRl() {
|
|
173
|
-
return readline.createInterface({
|
|
174
|
-
input: process.stdin,
|
|
175
|
-
output: process.stdout
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function ask(rl, question) {
|
|
180
|
-
return new Promise((resolve) => rl.question(question, (ans) => resolve(ans.trim())));
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async function promptEccProfile(pack, preset) {
|
|
184
|
-
if (preset) return preset;
|
|
185
|
-
const profiles = pack.install?.profiles;
|
|
186
|
-
if (!profiles?.length) {
|
|
187
|
-
return pack.install?.defaultProfile || "core";
|
|
188
|
-
}
|
|
189
|
-
const rl = createRl();
|
|
190
|
-
console.log("\nECC install profile:");
|
|
191
|
-
profiles.forEach((p, i) => {
|
|
192
|
-
console.log(` ${i + 1}) ${p.id} — ${p.description}`);
|
|
193
|
-
});
|
|
194
|
-
const defaultId = pack.install.defaultProfile || "core";
|
|
195
|
-
const answer = await ask(rl, `Profile [1-${profiles.length} or id] (default ${defaultId}): `);
|
|
196
|
-
rl.close();
|
|
197
|
-
if (!answer) return defaultId;
|
|
198
|
-
const num = parseInt(answer, 10);
|
|
199
|
-
if (!Number.isNaN(num) && num >= 1 && num <= profiles.length) {
|
|
200
|
-
return profiles[num - 1].id;
|
|
201
|
-
}
|
|
202
|
-
const byId = profiles.find((p) => p.id === answer);
|
|
203
|
-
if (byId) return byId.id;
|
|
204
|
-
console.error(`Unknown profile "${answer}", using ${defaultId}.`);
|
|
205
|
-
return defaultId;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async function promptSelectPacks(packs) {
|
|
209
|
-
const rl = createRl();
|
|
210
|
-
console.log("\nSelect packs to install:\n");
|
|
211
|
-
packs.forEach((p, i) => {
|
|
212
|
-
const mark = p.defaultSelected ? " [default]" : "";
|
|
213
|
-
console.log(` ${i + 1}) ${p.id}${mark} — ${p.name}`);
|
|
214
|
-
});
|
|
215
|
-
console.log("\nEnter: number(s) 1,2 · ids impeccable,ecc · all · defaults · Enter for defaults\n");
|
|
216
|
-
const answer = await ask(rl, "Choice> ");
|
|
217
|
-
rl.close();
|
|
218
|
-
if (!answer) {
|
|
219
|
-
return packs.filter((p) => p.defaultSelected).map((p) => p.id);
|
|
220
|
-
}
|
|
221
|
-
const lower = answer.toLowerCase();
|
|
222
|
-
if (lower === "all") return packs.map((p) => p.id);
|
|
223
|
-
if (lower === "defaults" || lower === "default" || lower === "d") {
|
|
224
|
-
return packs.filter((p) => p.defaultSelected).map((p) => p.id);
|
|
225
|
-
}
|
|
226
|
-
const nums = lower.split(/[\s,]+/).filter(Boolean);
|
|
227
|
-
const byNum = [];
|
|
228
|
-
for (const part of nums) {
|
|
229
|
-
const n = parseInt(part, 10);
|
|
230
|
-
if (!Number.isNaN(n) && n >= 1 && n <= packs.length) {
|
|
231
|
-
byNum.push(packs[n - 1].id);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (byNum.length > 0) return [...new Set(byNum)];
|
|
235
|
-
return answer.split(",").map((s) => s.trim()).filter(Boolean);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
156
|
async function run() {
|
|
239
157
|
const args = parseArgs(process.argv.slice(2));
|
|
240
158
|
if (args.help) {
|