left-skills 0.6.0 → 0.7.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/cli.js +148 -30
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6992,22 +6992,67 @@ function evolvePrompt(skillName) {
|
|
|
6992
6992
|
}
|
|
6993
6993
|
|
|
6994
6994
|
// src/inspire.ts
|
|
6995
|
+
var import_node_fs8 = require("fs");
|
|
6996
|
+
var import_node_path8 = require("path");
|
|
6997
|
+
var import_node_os8 = require("os");
|
|
6998
|
+
|
|
6999
|
+
// src/llm.ts
|
|
6995
7000
|
var import_node_fs7 = require("fs");
|
|
6996
|
-
var import_node_path7 = require("path");
|
|
6997
7001
|
var import_node_os7 = require("os");
|
|
7002
|
+
var import_node_path7 = require("path");
|
|
7003
|
+
var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
|
|
7004
|
+
function getApiKey() {
|
|
7005
|
+
const env = process.env.ANTHROPIC_API_KEY;
|
|
7006
|
+
if (env) return env;
|
|
7007
|
+
try {
|
|
7008
|
+
const settings = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path7.join)((0, import_node_os7.homedir)(), ".claude", "settings.json"), "utf-8"));
|
|
7009
|
+
return settings.env?.ANTHROPIC_API_KEY || null;
|
|
7010
|
+
} catch {
|
|
7011
|
+
return null;
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
async function llmAnalyze(prompt, system) {
|
|
7015
|
+
const apiKey = getApiKey();
|
|
7016
|
+
if (!apiKey) return null;
|
|
7017
|
+
const model = process.env.ANTHROPIC_MODEL || "claude-sonnet-4-6";
|
|
7018
|
+
try {
|
|
7019
|
+
const response = await fetch(ANTHROPIC_API_URL, {
|
|
7020
|
+
method: "POST",
|
|
7021
|
+
headers: {
|
|
7022
|
+
"Content-Type": "application/json",
|
|
7023
|
+
"x-api-key": apiKey,
|
|
7024
|
+
"anthropic-version": "2023-06-01"
|
|
7025
|
+
},
|
|
7026
|
+
body: JSON.stringify({
|
|
7027
|
+
model,
|
|
7028
|
+
max_tokens: 1024,
|
|
7029
|
+
system,
|
|
7030
|
+
messages: [{ role: "user", content: prompt }]
|
|
7031
|
+
})
|
|
7032
|
+
});
|
|
7033
|
+
if (!response.ok) return null;
|
|
7034
|
+
const data = await response.json();
|
|
7035
|
+
return data.content?.[0]?.text || null;
|
|
7036
|
+
} catch {
|
|
7037
|
+
return null;
|
|
7038
|
+
}
|
|
7039
|
+
}
|
|
7040
|
+
|
|
7041
|
+
// src/inspire.ts
|
|
6998
7042
|
function scanSessions(sinceDays = 30) {
|
|
6999
|
-
const projectsDir = (0,
|
|
7043
|
+
const projectsDir = (0, import_node_path8.join)((0, import_node_os8.homedir)(), ".claude", "projects");
|
|
7000
7044
|
const cmdCount = /* @__PURE__ */ new Map();
|
|
7001
|
-
|
|
7045
|
+
const seqCount = /* @__PURE__ */ new Map();
|
|
7046
|
+
if (!(0, import_node_fs8.existsSync)(projectsDir)) return { cmdCount, seqCount };
|
|
7002
7047
|
const cutoff = Date.now() - sinceDays * 864e5;
|
|
7003
|
-
for (const project of (0,
|
|
7048
|
+
for (const project of (0, import_node_fs8.readdirSync)(projectsDir, { withFileTypes: true })) {
|
|
7004
7049
|
if (!project.isDirectory()) continue;
|
|
7005
|
-
const projectDir = (0,
|
|
7006
|
-
for (const file of (0,
|
|
7050
|
+
const projectDir = (0, import_node_path8.join)(projectsDir, project.name);
|
|
7051
|
+
for (const file of (0, import_node_fs8.readdirSync)(projectDir)) {
|
|
7007
7052
|
if (!file.endsWith(".jsonl")) continue;
|
|
7008
|
-
const filePath = (0, import_node_path7.join)(projectDir, file);
|
|
7009
7053
|
try {
|
|
7010
|
-
const content = (0,
|
|
7054
|
+
const content = (0, import_node_fs8.readFileSync)((0, import_node_path8.join)(projectDir, file), "utf-8");
|
|
7055
|
+
const toolNames = [];
|
|
7011
7056
|
for (const line of content.split("\n")) {
|
|
7012
7057
|
if (!line.trim()) continue;
|
|
7013
7058
|
try {
|
|
@@ -7017,10 +7062,13 @@ function scanSessions(sinceDays = 30) {
|
|
|
7017
7062
|
const msg = obj.message;
|
|
7018
7063
|
if (msg && msg.content && Array.isArray(msg.content)) {
|
|
7019
7064
|
for (const block of msg.content) {
|
|
7020
|
-
if (block.type === "tool_use"
|
|
7021
|
-
|
|
7022
|
-
if (
|
|
7023
|
-
|
|
7065
|
+
if (block.type === "tool_use") {
|
|
7066
|
+
toolNames.push(block.name);
|
|
7067
|
+
if (block.name === "Bash") {
|
|
7068
|
+
const cmd = block.input?.command;
|
|
7069
|
+
if (cmd && cmd.length >= 30) {
|
|
7070
|
+
cmdCount.set(cmd, (cmdCount.get(cmd) || 0) + 1);
|
|
7071
|
+
}
|
|
7024
7072
|
}
|
|
7025
7073
|
}
|
|
7026
7074
|
}
|
|
@@ -7028,31 +7076,101 @@ function scanSessions(sinceDays = 30) {
|
|
|
7028
7076
|
} catch {
|
|
7029
7077
|
}
|
|
7030
7078
|
}
|
|
7079
|
+
for (let i = 0; i + 2 < toolNames.length; i++) {
|
|
7080
|
+
const seq = toolNames.slice(i, i + 3).join(",");
|
|
7081
|
+
seqCount.set(seq, (seqCount.get(seq) || 0) + 1);
|
|
7082
|
+
}
|
|
7031
7083
|
} catch {
|
|
7032
7084
|
}
|
|
7033
7085
|
}
|
|
7034
7086
|
}
|
|
7035
|
-
return cmdCount;
|
|
7087
|
+
return { cmdCount, seqCount };
|
|
7088
|
+
}
|
|
7089
|
+
function skeletonize(cmd) {
|
|
7090
|
+
return cmd.replace(/"[^"]*"/g, "*").replace(/'[^']*'/g, "*").replace(/\/[^\s"']+/g, "/*").replace(/\s+/g, " ").trim();
|
|
7036
7091
|
}
|
|
7037
|
-
function
|
|
7038
|
-
const
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7092
|
+
function isNoise(skeleton) {
|
|
7093
|
+
const simple = /^(echo|ls|cat|cd|pwd|clear|exit|which|whoami|date|uptime)\b/i;
|
|
7094
|
+
return simple.test(skeleton) || skeleton.length < 10;
|
|
7095
|
+
}
|
|
7096
|
+
function isSeqNoise(seq) {
|
|
7097
|
+
const parts = seq.split(",");
|
|
7098
|
+
if (parts.every((p) => p === parts[0])) return true;
|
|
7099
|
+
return false;
|
|
7100
|
+
}
|
|
7101
|
+
async function inspirePrompt(sinceDays = 30) {
|
|
7102
|
+
const { cmdCount, seqCount } = scanSessions(sinceDays);
|
|
7103
|
+
const skeletonCount = /* @__PURE__ */ new Map();
|
|
7104
|
+
for (const [cmd, count] of cmdCount) {
|
|
7105
|
+
const skeleton = skeletonize(cmd);
|
|
7106
|
+
if (isNoise(skeleton)) continue;
|
|
7107
|
+
const existing = skeletonCount.get(skeleton);
|
|
7108
|
+
if (existing) {
|
|
7109
|
+
existing.count += count;
|
|
7110
|
+
if (existing.examples.length < 2) existing.examples.push(cmd.slice(0, 80));
|
|
7111
|
+
} else {
|
|
7112
|
+
skeletonCount.set(skeleton, { count, examples: [cmd.slice(0, 80)] });
|
|
7113
|
+
}
|
|
7114
|
+
}
|
|
7115
|
+
const cmdCandidates = [...skeletonCount.entries()].filter(([, info]) => info.count >= 3).sort((a, b) => b[1].count - a[1].count);
|
|
7116
|
+
const seqCandidates = [...seqCount.entries()].filter(([seq, count]) => count >= 3 && !isSeqNoise(seq)).sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
7117
|
+
if (cmdCandidates.length === 0 && seqCandidates.length === 0) {
|
|
7118
|
+
return "\u65E0\u91CD\u590D\u6A21\u5F0F(Bash \u9AA8\u67B6 \u22653 \u6216 tool \u5E8F\u5217 \u22653),\u6682\u4E0D\u5EFA\u8BAE\u5199 skill\u3002\n(\u8BD5\u66F4\u591A\u5929?left-skills inspire --since 90)";
|
|
7042
7119
|
}
|
|
7120
|
+
const installed = listInstalledSkills();
|
|
7121
|
+
const llmPrompt = `\u4F60\u53CD\u590D\u8DD1\u8FD9\u4E9B(${cmdCandidates.length} \u4E2A Bash \u9AA8\u67B6 + ${seqCandidates.length} \u4E2A tool \u5E8F\u5217):
|
|
7122
|
+
|
|
7123
|
+
## Bash \u9AA8\u67B6\u5019\u9009
|
|
7124
|
+
${cmdCandidates.slice(0, 10).map(([sk, info]) => `- ${sk}(${info.count} \u6B21,\u4F8B: ${info.examples[0]})`).join("\n") || "(\u65E0)"}
|
|
7125
|
+
|
|
7126
|
+
## tool \u5E8F\u5217\u5019\u9009(all tools,\u5DE5\u4F5C\u6D41)
|
|
7127
|
+
${seqCandidates.map(([seq, count]) => `- ${seq}(${count} \u6B21)`).join("\n") || "(\u65E0)"}
|
|
7128
|
+
|
|
7129
|
+
\u5DF2\u88C5 skill(\u907F\u514D\u91CD\u590D\u63D0\u8BAE):
|
|
7130
|
+
${installed.length > 0 ? installed.map((s) => "- " + s).join("\n") : "(\u65E0)"}
|
|
7131
|
+
|
|
7132
|
+
\u8BF7\u5224\u65AD:\u54EA\u4E9B\u8BE5\u5199 skill(\u81EA\u52A8\u5316)?\u6311 1-2 \u4E2A\u6700\u9891\u7E41\u7684,\u751F\u6210 SKILL.md \u8349\u7A3F\u6307\u4EE4\u3002
|
|
7133
|
+
- description \u8BF4\u660E"\u4F55\u65F6\u7528"(\u8BA9 AI \u81EA\u51B3\u89E6\u53D1)
|
|
7134
|
+
- body \u542B\u8BE5\u547D\u4EE4/\u5DE5\u4F5C\u6D41(\u81EA\u52A8\u5316)
|
|
7135
|
+
- **\u542B test cases(Happy/Edge/Error 3 \u573A\u666F)**(\u7ED9\u4EBA\u5BA1\u9A8C)
|
|
7136
|
+
- \u4E0D\u8981\u63D0\u8BAE\u5DF2\u88C5 skill \u91CD\u590D\u7684`;
|
|
7137
|
+
const system = "\u4F60\u662F skill \u67B6\u6784\u5E08\u3002\u4ECE\u91CD\u590D\u547D\u4EE4/\u5DE5\u4F5C\u6D41\u5224\u65AD\u8BE5\u4E0D\u8BE5\u5199 skill,\u907F\u514D\u91CD\u590D\u5DF2\u88C5\u7684\u3002\u8F93\u51FA\u542B test cases \u7684\u6539\u8FDB\u6307\u4EE4(\u7ED9\u4EBA\u5BA1,\u4E0D\u81EA\u52A8\u521B\u5EFA)\u3002";
|
|
7138
|
+
const llmResult = await llmAnalyze(llmPrompt, system);
|
|
7043
7139
|
const lines = [];
|
|
7044
|
-
lines.push("# inspire:\u4F60\u53CD\u590D\u8DD1\u7684\u547D\u4EE4(\u5EFA\u8BAE\u5199 skill \u81EA\u52A8\u5316)");
|
|
7140
|
+
lines.push("# inspire:\u4F60\u53CD\u590D\u8DD1\u7684\u547D\u4EE4 + \u5DE5\u4F5C\u6D41(\u5EFA\u8BAE\u5199 skill \u81EA\u52A8\u5316)");
|
|
7045
7141
|
lines.push("");
|
|
7046
|
-
lines.push("## \
|
|
7047
|
-
|
|
7048
|
-
lines.push(`-
|
|
7142
|
+
lines.push("## Bash \u9AA8\u67B6\u5019\u9009(\u6B63\u5219\u7C97\u7B5B \u22653)");
|
|
7143
|
+
if (cmdCandidates.length > 0) {
|
|
7144
|
+
for (const [sk, info] of cmdCandidates) lines.push(`- ${sk}(${info.count} \u6B21)`);
|
|
7145
|
+
} else {
|
|
7146
|
+
lines.push("(\u65E0)");
|
|
7049
7147
|
}
|
|
7050
7148
|
lines.push("");
|
|
7051
|
-
lines.push("## \
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7149
|
+
lines.push("## tool \u5E8F\u5217\u5019\u9009(all tools,\u5DE5\u4F5C\u6D41 \u22653)");
|
|
7150
|
+
if (seqCandidates.length > 0) {
|
|
7151
|
+
for (const [seq, count] of seqCandidates) lines.push(`- ${seq}(${count} \u6B21)`);
|
|
7152
|
+
} else {
|
|
7153
|
+
lines.push("(\u65E0)");
|
|
7154
|
+
}
|
|
7155
|
+
lines.push("");
|
|
7156
|
+
lines.push("## \u5DF2\u88C5 skill(OBSERVE,\u907F\u514D\u91CD\u590D)");
|
|
7157
|
+
if (installed.length > 0) {
|
|
7158
|
+
for (const s of installed) lines.push(`- ${s}`);
|
|
7159
|
+
} else {
|
|
7160
|
+
lines.push("(\u65E0)");
|
|
7161
|
+
}
|
|
7162
|
+
lines.push("");
|
|
7163
|
+
if (llmResult) {
|
|
7164
|
+
lines.push("## LLM \u7CBE\u63D0(\u542B test cases \u6307\u4EE4,\u4EBA\u5BA1)");
|
|
7165
|
+
lines.push(llmResult);
|
|
7166
|
+
} else {
|
|
7167
|
+
lines.push("## \u6539\u8FDB\u6307\u4EE4(\u7ED9 AI,\u65E0 LLM \u964D\u7EA7\u7EAF\u6B63\u5219)");
|
|
7168
|
+
lines.push("\u8BF7\u57FA\u4E8E\u4EE5\u4E0A\u5019\u9009,\u6311 1-2 \u4E2A\u6700\u9891\u7E41\u7684,\u751F\u6210 SKILL.md \u8349\u7A3F:");
|
|
7169
|
+
lines.push('- description \u8BF4\u660E"\u4F55\u65F6\u7528"');
|
|
7170
|
+
lines.push("- body \u542B\u8BE5\u547D\u4EE4/\u5DE5\u4F5C\u6D41");
|
|
7171
|
+
lines.push("- **\u542B test cases(Happy/Edge/Error)**");
|
|
7172
|
+
lines.push("- \u4E0D\u8981\u63D0\u8BAE\u5DF2\u88C5 skill \u91CD\u590D\u7684");
|
|
7173
|
+
}
|
|
7056
7174
|
lines.push("");
|
|
7057
7175
|
lines.push("\u751F\u6210\u8349\u7A3F,\u6211\u5BA1\u8FC7\u540E\u4E22\u8FDB .claude/skills/(\u4E0D\u81EA\u52A8\u521B\u5EFA)\u3002");
|
|
7058
7176
|
return lines.join("\n");
|
|
@@ -7061,7 +7179,7 @@ function inspirePrompt(sinceDays = 30) {
|
|
|
7061
7179
|
// package.json
|
|
7062
7180
|
var package_default = {
|
|
7063
7181
|
name: "left-skills",
|
|
7064
|
-
version: "0.
|
|
7182
|
+
version: "0.7.0",
|
|
7065
7183
|
description: "\u7ED9 AI \u7528\u7684 skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u5DE5\u5177 \u2014 MVP: skill \u8C03\u7528\u4F7F\u7528\u7EDF\u8BA1",
|
|
7066
7184
|
bin: {
|
|
7067
7185
|
"left-skills": "./dist/cli.js"
|
|
@@ -7122,9 +7240,9 @@ program2.command("lint").description("\u9759\u6001\u8D28\u91CF\u68C0\u67E5 SKILL
|
|
|
7122
7240
|
program2.command("evolve <skill>").description("\u6536\u96C6 usage+lint \u4FE1\u53F7,\u8F93\u51FA\u6539\u8FDB prompt(\u7ED9 AI,\u4EBA\u5BA1,\u4E0D\u81EA\u52A8\u6539)").action((skill) => {
|
|
7123
7241
|
console.log(evolvePrompt(skill));
|
|
7124
7242
|
});
|
|
7125
|
-
program2.command("inspire").description("\u626B\u4F1A\u8BDD\u627E\u91CD\u590D\u547D\u4EE4,\u63D0\u8BAE\u5199 skill(\u7ED9 AI,\u4EBA\u5BA1,\u4E0D\u81EA\u52A8\u521B\u5EFA)").option("--since <days>", "\u65F6\u95F4\u7A97\u53E3(\u5929,\u9ED8\u8BA4 30)", "30").action((opts) => {
|
|
7243
|
+
program2.command("inspire").description("\u626B\u4F1A\u8BDD\u627E\u91CD\u590D\u547D\u4EE4,\u63D0\u8BAE\u5199 skill(hybrid \u6B63\u5219+LLM,\u7ED9 AI,\u4EBA\u5BA1,\u4E0D\u81EA\u52A8\u521B\u5EFA)").option("--since <days>", "\u65F6\u95F4\u7A97\u53E3(\u5929,\u9ED8\u8BA4 30)", "30").action(async (opts) => {
|
|
7126
7244
|
const since = parseInt(opts.since, 10) || 30;
|
|
7127
|
-
console.log(inspirePrompt(since));
|
|
7245
|
+
console.log(await inspirePrompt(since));
|
|
7128
7246
|
});
|
|
7129
7247
|
program2.command("report").description("\u5BFC\u51FA usage \u62A5\u544A markdown(\u53EF > report.md \u5206\u4EAB)").option("--markdown", "\u8F93\u51FA markdown(\u9ED8\u8BA4\u5373 markdown)").option("--since <days>", "\u65F6\u95F4\u7A97\u53E3(\u5929,\u9ED8\u8BA4 30)", "30").action((opts) => {
|
|
7130
7248
|
const since = parseInt(opts.since, 10) || 30;
|