left-skills 0.4.0 → 0.6.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/README.md +2 -0
- package/dist/cli.js +149 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,8 @@ left-skills usage # human-readable report
|
|
|
57
57
|
left-skills usage --json # for AI (JSON)
|
|
58
58
|
left-skills usage --since 7 # last 7 days
|
|
59
59
|
left-skills lint # static quality check (0-100 score)
|
|
60
|
+
left-skills evolve <skill> # generate improvement prompt (for AI, human review)
|
|
61
|
+
left-skills inspire # find repeated commands → suggest new skill
|
|
60
62
|
left-skills doctor # diagnose install (✓/✗ + fix)
|
|
61
63
|
left-skills report --markdown > report.md # export report
|
|
62
64
|
```
|
package/dist/cli.js
CHANGED
|
@@ -6918,10 +6918,150 @@ function formatLintHuman(results) {
|
|
|
6918
6918
|
return lines.join("\n");
|
|
6919
6919
|
}
|
|
6920
6920
|
|
|
6921
|
+
// src/evolve.ts
|
|
6922
|
+
var import_node_fs6 = require("fs");
|
|
6923
|
+
var import_node_path6 = require("path");
|
|
6924
|
+
var import_node_os6 = require("os");
|
|
6925
|
+
function findSkillDir(skillName) {
|
|
6926
|
+
const dirs = [
|
|
6927
|
+
(0, import_node_path6.join)(process.cwd(), ".claude/skills"),
|
|
6928
|
+
(0, import_node_path6.join)(process.cwd(), ".codex/skills"),
|
|
6929
|
+
(0, import_node_path6.join)((0, import_node_os6.homedir)(), ".claude/skills"),
|
|
6930
|
+
(0, import_node_path6.join)((0, import_node_os6.homedir)(), ".codex/skills")
|
|
6931
|
+
];
|
|
6932
|
+
for (const d of dirs) {
|
|
6933
|
+
if (!(0, import_node_fs6.existsSync)(d)) continue;
|
|
6934
|
+
const skillDir = (0, import_node_path6.join)(d, skillName);
|
|
6935
|
+
if ((0, import_node_fs6.existsSync)(skillDir)) return skillDir;
|
|
6936
|
+
}
|
|
6937
|
+
return null;
|
|
6938
|
+
}
|
|
6939
|
+
function evolvePrompt(skillName) {
|
|
6940
|
+
const lines = [];
|
|
6941
|
+
lines.push(`# \u6539\u8FDB skill: ${skillName}`);
|
|
6942
|
+
lines.push("");
|
|
6943
|
+
const stats = aggregate(30);
|
|
6944
|
+
const stat = stats.find((s) => s.name === skillName);
|
|
6945
|
+
const total = stat ? stat.manual + stat.ai + stat.mention : 0;
|
|
6946
|
+
lines.push(`## usage \u4FE1\u53F7`);
|
|
6947
|
+
if (!stat || total === 0) {
|
|
6948
|
+
lines.push(`- \u26A0 \u8FD1 30 \u5929\u4ECE\u672A\u8C03\u7528(\u5199\u4E86\u6CA1\u7528?description \u6CA1\u8BF4\u6E05 trigger \u2192 AI \u4E0D\u89E6\u53D1)`);
|
|
6949
|
+
} else {
|
|
6950
|
+
lines.push(`- \u8C03\u7528 ${total} \u6B21(\u624B\u52A8 ${stat.manual} + AI ${stat.ai} + \u63D0\u53CA ${stat.mention})`);
|
|
6951
|
+
if (stat.ai === 0) lines.push(`- \u26A0 AI \u4ECE\u4E0D\u4E3B\u52A8\u8C03\u7528(\u53EA\u624B\u52A8,description \u53EF\u80FD\u6CA1\u8BA9 AI \u89E6\u53D1)`);
|
|
6952
|
+
}
|
|
6953
|
+
const skillDir = findSkillDir(skillName);
|
|
6954
|
+
lines.push("");
|
|
6955
|
+
lines.push(`## lint \u4FE1\u53F7`);
|
|
6956
|
+
let lint = null;
|
|
6957
|
+
if (!skillDir) {
|
|
6958
|
+
lines.push(`- \u26A0 skill \u76EE\u5F55\u627E\u4E0D\u5230(${skillName} \u672A\u88C5?)`);
|
|
6959
|
+
} else {
|
|
6960
|
+
lint = lintSkill(skillDir);
|
|
6961
|
+
if (lint.issues.length === 0) {
|
|
6962
|
+
lines.push(`- \u2713 \u9759\u6001\u8D28\u91CF\u5408\u89C4(0 issue)`);
|
|
6963
|
+
} else {
|
|
6964
|
+
for (const issue of lint.issues) {
|
|
6965
|
+
lines.push(`- ${issue.severity} ${issue.rule}: ${issue.message}`);
|
|
6966
|
+
}
|
|
6967
|
+
}
|
|
6968
|
+
}
|
|
6969
|
+
lines.push("");
|
|
6970
|
+
lines.push(`## \u6539\u8FDB\u6307\u4EE4(\u7ED9 AI)`);
|
|
6971
|
+
lines.push(`\u8BF7\u57FA\u4E8E\u4EE5\u4E0A\u4FE1\u53F7,\u6539\u8FDB skill \`${skillName}\` \u7684 SKILL.md:`);
|
|
6972
|
+
if (!stat || total === 0) {
|
|
6973
|
+
lines.push(`- description \u6CA1\u8BA9 AI \u89E6\u53D1 \u2192 \u6539 description,\u52A0 "Use when..." \u89E6\u53D1\u573A\u666F(\u8BF4\u660E\u80FD\u529B + \u4F55\u65F6\u7528)`);
|
|
6974
|
+
}
|
|
6975
|
+
if (stat && stat.ai === 0) {
|
|
6976
|
+
lines.push(`- AI \u4E0D\u4E3B\u52A8\u8C03\u7528 \u2192 description \u8865 trigger \u5173\u952E\u8BCD(\u8BA9 AI \u81EA\u51B3\u89E6\u53D1)`);
|
|
6977
|
+
}
|
|
6978
|
+
if (lint) {
|
|
6979
|
+
for (const issue of lint.issues) {
|
|
6980
|
+
if (issue.severity === "ERROR") {
|
|
6981
|
+
if (issue.rule === "name-kebab") lines.push(`- name \u4E0D\u5408\u89C4 \u2192 \u6539 name \u4E3A kebab-case(\u5C0F\u5199+\u8FDE\u5B57\u7B26)`);
|
|
6982
|
+
if (issue.rule === "name-dir-match") lines.push(`- name\u2260\u76EE\u5F55 \u2192 \u6539 name \u6216\u76EE\u5F55\u540D(\u4E00\u81F4)`);
|
|
6983
|
+
if (issue.rule === "description-present") lines.push(`- description \u7F3A \u2192 \u52A0 description(\u8BF4\u660E\u80FD\u529B+\u89E6\u53D1)`);
|
|
6984
|
+
}
|
|
6985
|
+
if (issue.severity === "WARN" && issue.rule === "description-len") lines.push(`- description \u957F\u5EA6 \u2192 \u8C03\u5230 20-300 \u5B57\u7B26`);
|
|
6986
|
+
if (issue.severity === "WARN" && issue.rule === "token-budget") lines.push(`- body \u592A\u957F \u2192 \u62C6 references/`);
|
|
6987
|
+
}
|
|
6988
|
+
}
|
|
6989
|
+
lines.push("");
|
|
6990
|
+
lines.push(`\u751F\u6210\u6539\u8FDB diff,\u6211\u5BA1\u8FC7\u540E\u5E94\u7528(\u4E0D\u81EA\u52A8\u6539)\u3002`);
|
|
6991
|
+
return lines.join("\n");
|
|
6992
|
+
}
|
|
6993
|
+
|
|
6994
|
+
// src/inspire.ts
|
|
6995
|
+
var import_node_fs7 = require("fs");
|
|
6996
|
+
var import_node_path7 = require("path");
|
|
6997
|
+
var import_node_os7 = require("os");
|
|
6998
|
+
function scanSessions(sinceDays = 30) {
|
|
6999
|
+
const projectsDir = (0, import_node_path7.join)((0, import_node_os7.homedir)(), ".claude", "projects");
|
|
7000
|
+
const cmdCount = /* @__PURE__ */ new Map();
|
|
7001
|
+
if (!(0, import_node_fs7.existsSync)(projectsDir)) return cmdCount;
|
|
7002
|
+
const cutoff = Date.now() - sinceDays * 864e5;
|
|
7003
|
+
for (const project of (0, import_node_fs7.readdirSync)(projectsDir, { withFileTypes: true })) {
|
|
7004
|
+
if (!project.isDirectory()) continue;
|
|
7005
|
+
const projectDir = (0, import_node_path7.join)(projectsDir, project.name);
|
|
7006
|
+
for (const file of (0, import_node_fs7.readdirSync)(projectDir)) {
|
|
7007
|
+
if (!file.endsWith(".jsonl")) continue;
|
|
7008
|
+
const filePath = (0, import_node_path7.join)(projectDir, file);
|
|
7009
|
+
try {
|
|
7010
|
+
const content = (0, import_node_fs7.readFileSync)(filePath, "utf-8");
|
|
7011
|
+
for (const line of content.split("\n")) {
|
|
7012
|
+
if (!line.trim()) continue;
|
|
7013
|
+
try {
|
|
7014
|
+
const obj = JSON.parse(line);
|
|
7015
|
+
const ts = obj.timestamp;
|
|
7016
|
+
if (ts && new Date(ts).getTime() < cutoff) continue;
|
|
7017
|
+
const msg = obj.message;
|
|
7018
|
+
if (msg && msg.content && Array.isArray(msg.content)) {
|
|
7019
|
+
for (const block of msg.content) {
|
|
7020
|
+
if (block.type === "tool_use" && block.name === "Bash") {
|
|
7021
|
+
const cmd = block.input?.command;
|
|
7022
|
+
if (cmd && cmd.length >= 30) {
|
|
7023
|
+
cmdCount.set(cmd, (cmdCount.get(cmd) || 0) + 1);
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
}
|
|
7027
|
+
}
|
|
7028
|
+
} catch {
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
} catch {
|
|
7032
|
+
}
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
return cmdCount;
|
|
7036
|
+
}
|
|
7037
|
+
function inspirePrompt(sinceDays = 30) {
|
|
7038
|
+
const cmdCount = scanSessions(sinceDays);
|
|
7039
|
+
const repeated = [...cmdCount.entries()].filter(([, count]) => count >= 3).sort((a, b) => b[1] - a[1]);
|
|
7040
|
+
if (repeated.length === 0) {
|
|
7041
|
+
return "\u65E0\u91CD\u590D\u6A21\u5F0F(\u957F\u547D\u4EE4 \u226530 \u5B57\u7B26,\u91CD\u590D \u22653 \u6B21),\u6682\u4E0D\u5EFA\u8BAE\u5199 skill\u3002\n(\u8BD5\u66F4\u591A\u5929?left-skills inspire --since 90)";
|
|
7042
|
+
}
|
|
7043
|
+
const lines = [];
|
|
7044
|
+
lines.push("# inspire:\u4F60\u53CD\u590D\u8DD1\u7684\u547D\u4EE4(\u5EFA\u8BAE\u5199 skill \u81EA\u52A8\u5316)");
|
|
7045
|
+
lines.push("");
|
|
7046
|
+
lines.push("## \u91CD\u590D\u547D\u4EE4(\u957F\u547D\u4EE4 \u226530 \u5B57\u7B26,\u91CD\u590D \u22653 \u6B21)");
|
|
7047
|
+
for (const [cmd, count] of repeated) {
|
|
7048
|
+
lines.push(`- \`${cmd}\`(${count} \u6B21)`);
|
|
7049
|
+
}
|
|
7050
|
+
lines.push("");
|
|
7051
|
+
lines.push("## \u6539\u8FDB\u6307\u4EE4(\u7ED9 AI)");
|
|
7052
|
+
lines.push("\u8BF7\u57FA\u4E8E\u4EE5\u4E0A\u91CD\u590D\u547D\u4EE4,\u751F\u6210 SKILL.md \u8349\u7A3F:");
|
|
7053
|
+
lines.push("- \u6311 1-2 \u4E2A\u6700\u9891\u7E41\u7684\u547D\u4EE4\u5E8F\u5217,\u8BBE\u8BA1 skill(name / description / body)");
|
|
7054
|
+
lines.push('- description \u8BF4\u660E"\u4F55\u65F6\u7528"(\u8BA9 AI \u81EA\u51B3\u89E6\u53D1)');
|
|
7055
|
+
lines.push("- body \u542B\u8BE5\u547D\u4EE4\u5E8F\u5217(\u81EA\u52A8\u5316)");
|
|
7056
|
+
lines.push("");
|
|
7057
|
+
lines.push("\u751F\u6210\u8349\u7A3F,\u6211\u5BA1\u8FC7\u540E\u4E22\u8FDB .claude/skills/(\u4E0D\u81EA\u52A8\u521B\u5EFA)\u3002");
|
|
7058
|
+
return lines.join("\n");
|
|
7059
|
+
}
|
|
7060
|
+
|
|
6921
7061
|
// package.json
|
|
6922
7062
|
var package_default = {
|
|
6923
7063
|
name: "left-skills",
|
|
6924
|
-
version: "0.
|
|
7064
|
+
version: "0.6.0",
|
|
6925
7065
|
description: "\u7ED9 AI \u7528\u7684 skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u5DE5\u5177 \u2014 MVP: skill \u8C03\u7528\u4F7F\u7528\u7EDF\u8BA1",
|
|
6926
7066
|
bin: {
|
|
6927
7067
|
"left-skills": "./dist/cli.js"
|
|
@@ -6965,7 +7105,7 @@ var package_default = {
|
|
|
6965
7105
|
|
|
6966
7106
|
// src/cli.ts
|
|
6967
7107
|
var program2 = new Command();
|
|
6968
|
-
program2.name("left-skills").description("\u7ED9 AI \u7528\u7684 skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u5DE5\u5177 \u2014
|
|
7108
|
+
program2.name("left-skills").description("\u7ED9 AI \u7528\u7684 skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u5DE5\u5177 \u2014 skill \u8C03\u7528\u4F7F\u7528\u7EDF\u8BA1").version(package_default.version);
|
|
6969
7109
|
program2.command("usage").description("skill \u8C03\u7528\u4F7F\u7528\u62A5\u544A").option("--json", "\u8F93\u51FA JSON(AI \u7528)").option("--since <days>", "\u65F6\u95F4\u7A97\u53E3(\u5929,\u9ED8\u8BA4 30)", "30").action((opts) => {
|
|
6970
7110
|
const since = parseInt(opts.since, 10) || 30;
|
|
6971
7111
|
const report = buildReport(since);
|
|
@@ -6979,6 +7119,13 @@ program2.command("lint").description("\u9759\u6001\u8D28\u91CF\u68C0\u67E5 SKILL
|
|
|
6979
7119
|
const results = lintAll();
|
|
6980
7120
|
console.log(formatLintHuman(results));
|
|
6981
7121
|
});
|
|
7122
|
+
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
|
+
console.log(evolvePrompt(skill));
|
|
7124
|
+
});
|
|
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) => {
|
|
7126
|
+
const since = parseInt(opts.since, 10) || 30;
|
|
7127
|
+
console.log(inspirePrompt(since));
|
|
7128
|
+
});
|
|
6982
7129
|
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) => {
|
|
6983
7130
|
const since = parseInt(opts.since, 10) || 30;
|
|
6984
7131
|
const report = buildReport(since);
|