left-skills 0.8.0 → 0.9.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.
Files changed (2) hide show
  1. package/dist/cli.js +64 -222
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -6778,29 +6778,31 @@ function globalSettingsPath() {
6778
6778
  }
6779
6779
  var SKILL_MD_CONTENT = `---
6780
6780
  name: left-skills
6781
- description: \u7BA1\u7406 AI skill \u751F\u547D\u5468\u671F(lint \u68C0\u67E5\u8D28\u91CF / usage \u7EDF\u8BA1\u7528\u9891 / evolve \u6539\u8FDB / inspire \u53D1\u73B0\u65B0 skill)\u3002\u7528\u6237\u60F3\u7BA1 skill \u8D28\u91CF\u65F6\u89E6\u53D1\u3002
6781
+ description: \u7BA1\u7406 AI skill \u751F\u547D\u5468\u671F\u3002\u7528\u6237\u60F3\u68C0\u67E5/\u6539\u8FDB/\u53D1\u73B0 skill \u65F6\u89E6\u53D1\u3002
6782
6782
  ---
6783
6783
 
6784
6784
  # left-skills
6785
6785
 
6786
- left-skills \u662F skill \u751F\u547D\u5468\u671F\u7BA1\u7406 CLI\u3002\u901A\u8FC7\u8FD9\u4E2A skill,\u4F60\u53EF\u4EE5\u5728\u5BF9\u8BDD\u91CC\u89E6\u53D1 left-skills \u547D\u4EE4\u3002
6786
+ \u4F60\u662F skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u52A9\u624B\u3002\u901A\u8FC7 left-skills CLI \u91C7\u96C6\u6570\u636E(--json),\u4F60\u505A\u5206\u6790\u5224\u65AD\u3002
6787
6787
 
6788
- ## \u5B50\u547D\u4EE4
6788
+ ## \u6D41\u7A0B
6789
+ 1. \u8DD1 \`left-skills <\u547D\u4EE4> --json\`(Bash,\u91C7\u96C6\u6570\u636E)
6790
+ 2. \u8BFB JSON,\u4F60\u5206\u6790\u5224\u65AD(\u8BED\u4E49)
6791
+ 3. \u8F93\u51FA\u5EFA\u8BAE/\u8349\u7A3F\u7ED9\u7528\u6237\u5BA1(\u4E0D\u81EA\u52A8\u6539)
6789
6792
 
6790
- - \`left-skills lint\` \u2014 \u9759\u6001\u8D28\u91CF\u68C0\u67E5 SKILL.md(0-100 \u5206)
6791
- - \`left-skills usage\` \u2014 skill \u8C03\u7528\u4F7F\u7528\u62A5\u544A
6792
- - \`left-skills evolve <skill>\` \u2014 \u6536\u96C6 usage+lint \u4FE1\u53F7,\u8F93\u51FA\u6539\u8FDB prompt(\u7ED9 AI,\u4EBA\u5BA1)
6793
- - \`left-skills inspire\` \u2014 \u626B\u4F1A\u8BDD\u627E\u91CD\u590D\u547D\u4EE4,\u63D0\u8BAE\u5199 skill
6794
- - \`left-skills doctor\` \u2014 \u8BCA\u65AD\u5B89\u88C5/hook \u914D\u7F6E
6795
- - \`left-skills report --markdown\` \u2014 \u5BFC\u51FA usage \u62A5\u544A
6796
- - \`left-skills install --write\` \u2014 \u914D hook + \u653E\u8FD9\u4E2A skill
6797
- - \`left-skills uninstall\` \u2014 \u5220 hook + \u5220\u8FD9\u4E2A skill
6793
+ ## \u5165\u53E3 \u2192 CLI \u7EC4\u5408
6798
6794
 
6799
- ## \u600E\u4E48\u7528
6795
+ | \u7528\u6237\u610F\u56FE | \u8DD1\u4EC0\u4E48 | \u4F60\u505A\u4EC0\u4E48 |
6796
+ |---|---|---|
6797
+ | \u68C0\u67E5\u8D28\u91CF | \`left-skills lint --json\` | \u8BFB\u62A5\u544A,\u5EFA\u8BAE\u600E\u4E48\u4FEE |
6798
+ | \u770B\u7528\u6CA1\u7528 | \`left-skills usage --json\` | \u8BFB\u62A5\u544A,\u5EFA\u8BAE\u6539/\u5220 |
6799
+ | \u8BE5\u5199\u4EC0\u4E48 | \`left-skills scan --json\` + \`left-skills list-skills --json\` | \u8BFB\u5019\u9009+\u540D\u5355,\u5224\u65AD,\u751F\u6210\u8349\u7A3F |
6800
+ | \u6539\u8FDB skill | \`left-skills usage --json\` + \`left-skills lint --json\`(\u8FC7\u6EE4 skill) | \u8BFB\u4FE1\u53F7,\u751F\u6210 diff |
6801
+ | \u8BCA\u65AD | \`left-skills doctor\` | \u8F93\u51FA\u7ED9\u7528\u6237 |
6800
6802
 
6801
- \u7528\u6237\u60F3\u7BA1 skill \u8D28\u91CF\u65F6,\u8DD1\u5BF9\u5E94 \`left-skills <\u547D\u4EE4>\`(\u7528 Bash \u5DE5\u5177),\u628A\u8F93\u51FA\u7ED9\u7528\u6237\u3002\u4E0D\u77E5\u9053\u54EA\u4E2A\u547D\u4EE4\u65F6\u8DD1 \`left-skills --help\`\u3002
6802
-
6803
- \u8DD1\u5B8C\u8F93\u51FA\u662F prompt/\u62A5\u544A,\u4EBA\u5BA1\u540E\u5E94\u7528(\u4E0D\u81EA\u52A8\u6539 skill)\u3002
6803
+ ## \u7EA2\u7EBF
6804
+ - \u4E0D\u81EA\u52A8\u6539 skill(\u4EBA\u5BA1)
6805
+ - \u4E0D\u81EA\u52A8\u521B\u5EFA skill(\u4EBA\u5BA1)
6804
6806
  `;
6805
6807
  function writeSkillWrapper() {
6806
6808
  const skillDir = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".claude", "skills", "left-skills");
@@ -6954,141 +6956,27 @@ function formatLintHuman(results) {
6954
6956
  }
6955
6957
  return lines.join("\n");
6956
6958
  }
6959
+ function formatLintJson(results) {
6960
+ return JSON.stringify({ skills: results });
6961
+ }
6957
6962
 
6958
- // src/evolve.ts
6963
+ // src/scan.ts
6959
6964
  var import_node_fs6 = require("fs");
6960
6965
  var import_node_path6 = require("path");
6961
6966
  var import_node_os6 = require("os");
6962
- function findSkillDir(skillName) {
6963
- const dirs = [
6964
- (0, import_node_path6.join)(process.cwd(), ".claude/skills"),
6965
- (0, import_node_path6.join)(process.cwd(), ".codex/skills"),
6966
- (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".claude/skills"),
6967
- (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".codex/skills")
6968
- ];
6969
- for (const d of dirs) {
6970
- if (!(0, import_node_fs6.existsSync)(d)) continue;
6971
- const skillDir = (0, import_node_path6.join)(d, skillName);
6972
- if ((0, import_node_fs6.existsSync)(skillDir)) return skillDir;
6973
- }
6974
- return null;
6975
- }
6976
- function evolvePrompt(skillName) {
6977
- const lines = [];
6978
- lines.push(`# \u6539\u8FDB skill: ${skillName}`);
6979
- lines.push("");
6980
- const stats = aggregate(30);
6981
- const stat = stats.find((s) => s.name === skillName);
6982
- const total = stat ? stat.manual + stat.ai + stat.mention : 0;
6983
- lines.push(`## usage \u4FE1\u53F7`);
6984
- if (!stat || total === 0) {
6985
- lines.push(`- \u26A0 \u8FD1 30 \u5929\u4ECE\u672A\u8C03\u7528(\u5199\u4E86\u6CA1\u7528?description \u6CA1\u8BF4\u6E05 trigger \u2192 AI \u4E0D\u89E6\u53D1)`);
6986
- } else {
6987
- lines.push(`- \u8C03\u7528 ${total} \u6B21(\u624B\u52A8 ${stat.manual} + AI ${stat.ai} + \u63D0\u53CA ${stat.mention})`);
6988
- 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)`);
6989
- }
6990
- const skillDir = findSkillDir(skillName);
6991
- lines.push("");
6992
- lines.push(`## lint \u4FE1\u53F7`);
6993
- let lint = null;
6994
- if (!skillDir) {
6995
- lines.push(`- \u26A0 skill \u76EE\u5F55\u627E\u4E0D\u5230(${skillName} \u672A\u88C5?)`);
6996
- } else {
6997
- lint = lintSkill(skillDir);
6998
- if (lint.issues.length === 0) {
6999
- lines.push(`- \u2713 \u9759\u6001\u8D28\u91CF\u5408\u89C4(0 issue)`);
7000
- } else {
7001
- for (const issue of lint.issues) {
7002
- lines.push(`- ${issue.severity} ${issue.rule}: ${issue.message}`);
7003
- }
7004
- }
7005
- }
7006
- lines.push("");
7007
- lines.push(`## \u6539\u8FDB\u6307\u4EE4(\u7ED9 AI)`);
7008
- lines.push(`\u8BF7\u57FA\u4E8E\u4EE5\u4E0A\u4FE1\u53F7,\u6539\u8FDB skill \`${skillName}\` \u7684 SKILL.md:`);
7009
- if (!stat || total === 0) {
7010
- 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)`);
7011
- }
7012
- if (stat && stat.ai === 0) {
7013
- lines.push(`- AI \u4E0D\u4E3B\u52A8\u8C03\u7528 \u2192 description \u8865 trigger \u5173\u952E\u8BCD(\u8BA9 AI \u81EA\u51B3\u89E6\u53D1)`);
7014
- }
7015
- if (lint) {
7016
- for (const issue of lint.issues) {
7017
- if (issue.severity === "ERROR") {
7018
- if (issue.rule === "name-kebab") lines.push(`- name \u4E0D\u5408\u89C4 \u2192 \u6539 name \u4E3A kebab-case(\u5C0F\u5199+\u8FDE\u5B57\u7B26)`);
7019
- if (issue.rule === "name-dir-match") lines.push(`- name\u2260\u76EE\u5F55 \u2192 \u6539 name \u6216\u76EE\u5F55\u540D(\u4E00\u81F4)`);
7020
- if (issue.rule === "description-present") lines.push(`- description \u7F3A \u2192 \u52A0 description(\u8BF4\u660E\u80FD\u529B+\u89E6\u53D1)`);
7021
- }
7022
- if (issue.severity === "WARN" && issue.rule === "description-len") lines.push(`- description \u957F\u5EA6 \u2192 \u8C03\u5230 20-300 \u5B57\u7B26`);
7023
- if (issue.severity === "WARN" && issue.rule === "token-budget") lines.push(`- body \u592A\u957F \u2192 \u62C6 references/`);
7024
- }
7025
- }
7026
- lines.push("");
7027
- lines.push(`\u751F\u6210\u6539\u8FDB diff,\u6211\u5BA1\u8FC7\u540E\u5E94\u7528(\u4E0D\u81EA\u52A8\u6539)\u3002`);
7028
- return lines.join("\n");
7029
- }
7030
-
7031
- // src/inspire.ts
7032
- var import_node_fs8 = require("fs");
7033
- var import_node_path8 = require("path");
7034
- var import_node_os8 = require("os");
7035
-
7036
- // src/llm.ts
7037
- var import_node_fs7 = require("fs");
7038
- var import_node_os7 = require("os");
7039
- var import_node_path7 = require("path");
7040
- var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
7041
- function getApiKey() {
7042
- const env = process.env.ANTHROPIC_API_KEY;
7043
- if (env) return env;
7044
- try {
7045
- const settings = JSON.parse((0, import_node_fs7.readFileSync)((0, import_node_path7.join)((0, import_node_os7.homedir)(), ".claude", "settings.json"), "utf-8"));
7046
- return settings.env?.ANTHROPIC_API_KEY || null;
7047
- } catch {
7048
- return null;
7049
- }
7050
- }
7051
- async function llmAnalyze(prompt, system) {
7052
- const apiKey = getApiKey();
7053
- if (!apiKey) return null;
7054
- const model = process.env.ANTHROPIC_MODEL || "claude-sonnet-4-6";
7055
- try {
7056
- const response = await fetch(ANTHROPIC_API_URL, {
7057
- method: "POST",
7058
- headers: {
7059
- "Content-Type": "application/json",
7060
- "x-api-key": apiKey,
7061
- "anthropic-version": "2023-06-01"
7062
- },
7063
- body: JSON.stringify({
7064
- model,
7065
- max_tokens: 1024,
7066
- system,
7067
- messages: [{ role: "user", content: prompt }]
7068
- })
7069
- });
7070
- if (!response.ok) return null;
7071
- const data = await response.json();
7072
- return data.content?.[0]?.text || null;
7073
- } catch {
7074
- return null;
7075
- }
7076
- }
7077
-
7078
- // src/inspire.ts
7079
6967
  function scanSessions(sinceDays = 30) {
7080
- const projectsDir = (0, import_node_path8.join)((0, import_node_os8.homedir)(), ".claude", "projects");
6968
+ const projectsDir = (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".claude", "projects");
7081
6969
  const cmdCount = /* @__PURE__ */ new Map();
7082
6970
  const seqCount = /* @__PURE__ */ new Map();
7083
- if (!(0, import_node_fs8.existsSync)(projectsDir)) return { cmdCount, seqCount };
6971
+ if (!(0, import_node_fs6.existsSync)(projectsDir)) return { cmdCount, seqCount };
7084
6972
  const cutoff = Date.now() - sinceDays * 864e5;
7085
- for (const project of (0, import_node_fs8.readdirSync)(projectsDir, { withFileTypes: true })) {
6973
+ for (const project of (0, import_node_fs6.readdirSync)(projectsDir, { withFileTypes: true })) {
7086
6974
  if (!project.isDirectory()) continue;
7087
- const projectDir = (0, import_node_path8.join)(projectsDir, project.name);
7088
- for (const file of (0, import_node_fs8.readdirSync)(projectDir)) {
6975
+ const projectDir = (0, import_node_path6.join)(projectsDir, project.name);
6976
+ for (const file of (0, import_node_fs6.readdirSync)(projectDir)) {
7089
6977
  if (!file.endsWith(".jsonl")) continue;
7090
6978
  try {
7091
- const content = (0, import_node_fs8.readFileSync)((0, import_node_path8.join)(projectDir, file), "utf-8");
6979
+ const content = (0, import_node_fs6.readFileSync)((0, import_node_path6.join)(projectDir, file), "utf-8");
7092
6980
  const toolNames = [];
7093
6981
  for (const line of content.split("\n")) {
7094
6982
  if (!line.trim()) continue;
@@ -7135,7 +7023,7 @@ function isSeqNoise(seq) {
7135
7023
  if (parts.every((p) => p === parts[0])) return true;
7136
7024
  return false;
7137
7025
  }
7138
- async function inspirePrompt(sinceDays = 30) {
7026
+ function scan(sinceDays = 30) {
7139
7027
  const { cmdCount, seqCount } = scanSessions(sinceDays);
7140
7028
  const skeletonCount = /* @__PURE__ */ new Map();
7141
7029
  for (const [cmd, count] of cmdCount) {
@@ -7149,74 +7037,15 @@ async function inspirePrompt(sinceDays = 30) {
7149
7037
  skeletonCount.set(skeleton, { count, examples: [cmd.slice(0, 80)] });
7150
7038
  }
7151
7039
  }
7152
- const cmdCandidates = [...skeletonCount.entries()].filter(([, info]) => info.count >= 3).sort((a, b) => b[1].count - a[1].count);
7153
- const seqCandidates = [...seqCount.entries()].filter(([seq, count]) => count >= 3 && !isSeqNoise(seq)).sort((a, b) => b[1] - a[1]).slice(0, 10);
7154
- if (cmdCandidates.length === 0 && seqCandidates.length === 0) {
7155
- 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)";
7156
- }
7157
- const installed = listInstalledSkills();
7158
- const llmPrompt = `\u4F60\u53CD\u590D\u8DD1\u8FD9\u4E9B(${cmdCandidates.length} \u4E2A Bash \u9AA8\u67B6 + ${seqCandidates.length} \u4E2A tool \u5E8F\u5217):
7159
-
7160
- ## Bash \u9AA8\u67B6\u5019\u9009
7161
- ${cmdCandidates.slice(0, 10).map(([sk, info]) => `- ${sk}(${info.count} \u6B21,\u4F8B: ${info.examples[0]})`).join("\n") || "(\u65E0)"}
7162
-
7163
- ## tool \u5E8F\u5217\u5019\u9009(all tools,\u5DE5\u4F5C\u6D41)
7164
- ${seqCandidates.map(([seq, count]) => `- ${seq}(${count} \u6B21)`).join("\n") || "(\u65E0)"}
7165
-
7166
- \u5DF2\u88C5 skill(\u907F\u514D\u91CD\u590D\u63D0\u8BAE):
7167
- ${installed.length > 0 ? installed.map((s) => "- " + s).join("\n") : "(\u65E0)"}
7168
-
7169
- \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
7170
- - description \u8BF4\u660E"\u4F55\u65F6\u7528"(\u8BA9 AI \u81EA\u51B3\u89E6\u53D1)
7171
- - body \u542B\u8BE5\u547D\u4EE4/\u5DE5\u4F5C\u6D41(\u81EA\u52A8\u5316)
7172
- - **\u542B test cases(Happy/Edge/Error 3 \u573A\u666F)**(\u7ED9\u4EBA\u5BA1\u9A8C)
7173
- - \u4E0D\u8981\u63D0\u8BAE\u5DF2\u88C5 skill \u91CD\u590D\u7684`;
7174
- 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";
7175
- const llmResult = await llmAnalyze(llmPrompt, system);
7176
- const lines = [];
7177
- lines.push("# inspire:\u4F60\u53CD\u590D\u8DD1\u7684\u547D\u4EE4 + \u5DE5\u4F5C\u6D41(\u5EFA\u8BAE\u5199 skill \u81EA\u52A8\u5316)");
7178
- lines.push("");
7179
- lines.push("## Bash \u9AA8\u67B6\u5019\u9009(\u6B63\u5219\u7C97\u7B5B \u22653)");
7180
- if (cmdCandidates.length > 0) {
7181
- for (const [sk, info] of cmdCandidates) lines.push(`- ${sk}(${info.count} \u6B21)`);
7182
- } else {
7183
- lines.push("(\u65E0)");
7184
- }
7185
- lines.push("");
7186
- lines.push("## tool \u5E8F\u5217\u5019\u9009(all tools,\u5DE5\u4F5C\u6D41 \u22653)");
7187
- if (seqCandidates.length > 0) {
7188
- for (const [seq, count] of seqCandidates) lines.push(`- ${seq}(${count} \u6B21)`);
7189
- } else {
7190
- lines.push("(\u65E0)");
7191
- }
7192
- lines.push("");
7193
- lines.push("## \u5DF2\u88C5 skill(OBSERVE,\u907F\u514D\u91CD\u590D)");
7194
- if (installed.length > 0) {
7195
- for (const s of installed) lines.push(`- ${s}`);
7196
- } else {
7197
- lines.push("(\u65E0)");
7198
- }
7199
- lines.push("");
7200
- if (llmResult) {
7201
- lines.push("## LLM \u7CBE\u63D0(\u542B test cases \u6307\u4EE4,\u4EBA\u5BA1)");
7202
- lines.push(llmResult);
7203
- } else {
7204
- lines.push("## \u6539\u8FDB\u6307\u4EE4(\u7ED9 AI,\u65E0 LLM \u964D\u7EA7\u7EAF\u6B63\u5219)");
7205
- lines.push("\u8BF7\u57FA\u4E8E\u4EE5\u4E0A\u5019\u9009,\u6311 1-2 \u4E2A\u6700\u9891\u7E41\u7684,\u751F\u6210 SKILL.md \u8349\u7A3F:");
7206
- lines.push('- description \u8BF4\u660E"\u4F55\u65F6\u7528"');
7207
- lines.push("- body \u542B\u8BE5\u547D\u4EE4/\u5DE5\u4F5C\u6D41");
7208
- lines.push("- **\u542B test cases(Happy/Edge/Error)**");
7209
- lines.push("- \u4E0D\u8981\u63D0\u8BAE\u5DF2\u88C5 skill \u91CD\u590D\u7684");
7210
- }
7211
- lines.push("");
7212
- lines.push("\u751F\u6210\u8349\u7A3F,\u6211\u5BA1\u8FC7\u540E\u4E22\u8FDB .claude/skills/(\u4E0D\u81EA\u52A8\u521B\u5EFA)\u3002");
7213
- return lines.join("\n");
7040
+ const candidates = [...skeletonCount.entries()].filter(([, info]) => info.count >= 3).sort((a, b) => b[1].count - a[1].count).map(([skeleton, info]) => ({ skeleton, count: info.count, examples: info.examples }));
7041
+ const tool_sequences = [...seqCount.entries()].filter(([seq, count]) => count >= 3 && !isSeqNoise(seq)).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([sequence, count]) => ({ sequence, count }));
7042
+ return { candidates, tool_sequences };
7214
7043
  }
7215
7044
 
7216
7045
  // package.json
7217
7046
  var package_default = {
7218
7047
  name: "left-skills",
7219
- version: "0.8.0",
7048
+ version: "0.9.0",
7220
7049
  description: "\u7ED9 AI \u7528\u7684 skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u5DE5\u5177 \u2014 MVP: skill \u8C03\u7528\u4F7F\u7528\u7EDF\u8BA1",
7221
7050
  bin: {
7222
7051
  "left-skills": "./dist/cli.js"
@@ -7260,7 +7089,7 @@ var package_default = {
7260
7089
 
7261
7090
  // src/cli.ts
7262
7091
  var program2 = new Command();
7263
- 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);
7092
+ program2.name("left-skills").description("\u7ED9 AI \u7528\u7684 skill \u751F\u547D\u5468\u671F\u7BA1\u7406\u5DE5\u5177(\u6570\u636E\u5DE5\u5177\u7BB1,skill \u5165\u53E3 + AI \u5206\u6790)").version(package_default.version);
7264
7093
  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) => {
7265
7094
  const since = parseInt(opts.since, 10) || 30;
7266
7095
  const report = buildReport(since);
@@ -7270,18 +7099,34 @@ program2.command("usage").description("skill \u8C03\u7528\u4F7F\u7528\u62A5\u544
7270
7099
  console.log(formatHuman(report));
7271
7100
  }
7272
7101
  });
7273
- program2.command("lint").description("\u9759\u6001\u8D28\u91CF\u68C0\u67E5 SKILL.md(\u5BF9\u9F50 skills-ref + \u8865\u6DF1\u5EA6,0-100 \u5206)").action(() => {
7274
- const results = lintAll();
7275
- console.log(formatLintHuman(results));
7102
+ program2.command("scan").description("\u626B\u4F1A\u8BDD\u627E\u91CD\u590D Bash \u547D\u4EE4 + tool \u5E8F\u5217(\u6570\u636E\u91C7\u96C6,\u4E0D LLM)").option("--json", "\u8F93\u51FA JSON(AI \u7528)").option("--since <days>", "\u65F6\u95F4\u7A97\u53E3(\u5929,\u9ED8\u8BA4 30)", "30").action((opts) => {
7103
+ const since = parseInt(opts.since, 10) || 30;
7104
+ const result = scan(since);
7105
+ if (opts.json) {
7106
+ console.log(JSON.stringify(result));
7107
+ } else {
7108
+ console.log(`scan \u62A5\u544A(${result.candidates.length} \u5019\u9009 + ${result.tool_sequences.length} \u5E8F\u5217)`);
7109
+ for (const c of result.candidates) console.log(` ${c.count} ${c.skeleton}`);
7110
+ for (const s of result.tool_sequences) console.log(` ${s.count} ${s.sequence}`);
7111
+ }
7276
7112
  });
7277
- 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) => {
7278
- console.log(evolvePrompt(skill));
7113
+ program2.command("list-skills").description("\u5217\u5DF2\u88C5 skill(.claude/skills + .codex/skills)").option("--json", "\u8F93\u51FA JSON(AI \u7528)").action((opts) => {
7114
+ const skills = listInstalledSkills();
7115
+ if (opts.json) {
7116
+ console.log(JSON.stringify({ skills }));
7117
+ } else {
7118
+ for (const s of skills) console.log(s);
7119
+ }
7279
7120
  });
7280
- 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) => {
7281
- const since = parseInt(opts.since, 10) || 30;
7282
- console.log(await inspirePrompt(since));
7121
+ program2.command("lint").description("\u9759\u6001\u8D28\u91CF\u68C0\u67E5 SKILL.md(0-100 \u5206)").option("--json", "\u8F93\u51FA JSON(AI \u7528)").action((opts) => {
7122
+ const results = lintAll();
7123
+ if (opts.json) {
7124
+ console.log(formatLintJson(results));
7125
+ } else {
7126
+ console.log(formatLintHuman(results));
7127
+ }
7283
7128
  });
7284
- 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) => {
7129
+ program2.command("report").description("\u5BFC\u51FA usage \u62A5\u544A markdown(\u53EF > report.md)").option("--markdown", "\u8F93\u51FA markdown(\u9ED8\u8BA4)").option("--since <days>", "\u65F6\u95F4\u7A97\u53E3(\u5929,\u9ED8\u8BA4 30)", "30").action((opts) => {
7285
7130
  const since = parseInt(opts.since, 10) || 30;
7286
7131
  const report = buildReport(since);
7287
7132
  console.log(formatMarkdown(report));
@@ -7294,26 +7139,23 @@ program2.command("doctor").description("\u8BCA\u65AD left-skills \u5B89\u88C5/ho
7294
7139
  if (r.fix) console.log(` \u2192 \u4FEE\u590D: ${r.fix}`);
7295
7140
  }
7296
7141
  });
7297
- program2.command("install").description("\u8F93\u51FA hook \u914D\u7F6E\u7247\u6BB5(\u9ED8\u8BA4)\u6216 --write \u81EA\u52A8\u5199\u8FDB ~/.claude/settings.json(\u5408\u5E76+\u5907\u4EFD .bak)").option("--write", "\u81EA\u52A8\u5199 hook \u5230 settings.json(\u5408\u5E76\u53BB\u91CD + \u5907\u4EFD .bak)", false).action((opts) => {
7142
+ program2.command("install").description("\u8F93\u51FA hook \u7247\u6BB5(\u9ED8\u8BA4)\u6216 --write \u914D hook + \u653E SKILL.md").option("--write", "\u81EA\u52A8\u5199 hook + \u653E SKILL.md(\u5907\u4EFD .bak)", false).action((opts) => {
7298
7143
  if (opts.write) {
7299
7144
  const path = globalSettingsPath();
7300
7145
  writeHooksToSettings(path);
7301
7146
  writeSkillWrapper();
7302
- console.log(`\u2713 hook \u5DF2\u5199\u5165 ${path}(\u5DF2\u5907\u4EFD .bak)`);
7303
- console.log(`\u2713 skill wrapper \u5DF2\u653E ~/.claude/skills/left-skills/SKILL.md(/left-skills slash \u89E6\u53D1)`);
7304
- console.log(" \u6253 /skill \u6216 AI \u8C03 skill \u4F1A\u81EA\u52A8\u8BB0\u5F55,\u8DD1 left-skills usage \u770B\u62A5\u544A");
7147
+ console.log(`\u2713 hook \u5DF2\u5199\u5165 ${path}(\u5907\u4EFD .bak)`);
7148
+ console.log(`\u2713 SKILL.md \u5DF2\u653E ~/.claude/skills/left-skills/(/left-skills slash \u89E6\u53D1)`);
7305
7149
  } else {
7306
7150
  console.log(JSON.stringify(hookSnippet(), null, 2));
7307
- console.log("\n# \u628A\u4E0A\u9762\u7247\u6BB5\u52A0\u8FDB ~/.claude/settings.json \u7684 hooks \u5B57\u6BB5,\u6216\u8DD1 left-skills install --write \u81EA\u52A8\u5199");
7308
7151
  }
7309
7152
  });
7310
- program2.command("uninstall").description("\u5220 ~/.claude/settings.json \u7684 left-skills hook(\u5E72\u51C0\u5378\u8F7D,\u5907\u4EFD .bak)").action(() => {
7153
+ program2.command("uninstall").description("\u5220 hook + SKILL.md(\u5E72\u51C0\u5378\u8F7D)").action(() => {
7311
7154
  const path = globalSettingsPath();
7312
7155
  removeHooksFromSettings(path);
7313
7156
  removeSkillWrapper();
7314
- console.log(`\u2713 left-skills hook \u5DF2\u4ECE ${path} \u5220\u9664(\u5DF2\u5907\u4EFD .bak)`);
7315
- console.log(`\u2713 skill wrapper \u5DF2\u5220 ~/.claude/skills/left-skills/`);
7316
- console.log(" \u518D\u8DD1 npm uninstall -g left-skills \u5378\u8F7D binary");
7157
+ console.log(`\u2713 hook \u5DF2\u5220 ${path}(\u5907\u4EFD .bak)`);
7158
+ console.log(`\u2713 SKILL.md \u5DF2\u5220`);
7317
7159
  });
7318
7160
  program2.command("hook <event>").description("hook \u5165\u53E3(\u8BFB stdin payload)").action(async (event) => {
7319
7161
  const payload = await readStdinPayload();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "left-skills",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "给 AI 用的 skill 生命周期管理工具 — MVP: skill 调用使用统计",
5
5
  "bin": {
6
6
  "left-skills": "./dist/cli.js"