harnessed 3.4.1 → 3.4.2

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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { execSync, spawnSync, spawn } from 'child_process';
3
- import { existsSync, mkdirSync, renameSync, writeFileSync, readFileSync, appendFileSync, readdirSync } from 'fs';
3
+ import { existsSync, mkdirSync, renameSync, writeFileSync, readFileSync, readdirSync, appendFileSync } from 'fs';
4
4
  import { join, resolve, dirname, relative } from 'path';
5
5
  import { homedir } from 'os';
6
6
  import { Type } from '@sinclair/typebox';
@@ -847,7 +847,7 @@ var init_resume = __esm({
847
847
 
848
848
  // package.json
849
849
  var package_default = {
850
- version: "3.4.1"};
850
+ version: "3.4.2"};
851
851
 
852
852
  // src/manifest/errors.ts
853
853
  function instancePathToKeyPath(instancePath) {
@@ -5046,22 +5046,64 @@ function readInstalledPlugins(homedirOverride) {
5046
5046
  }
5047
5047
  return out;
5048
5048
  }
5049
- function resolveCapabilityCmd(capability, installedPlugins) {
5050
- const { cmd, plugin_namespace } = capability;
5051
- if (!plugin_namespace) return { renderedCmd: cmd };
5052
- if (cmd.includes(":")) return { renderedCmd: cmd };
5053
- if (!cmd.startsWith("/")) return { renderedCmd: cmd };
5054
- if (!installedPlugins.has(plugin_namespace)) {
5055
- return {
5056
- renderedCmd: cmd,
5057
- warning: `plugin '${plugin_namespace}' not installed \u2014 '${cmd}' will not resolve via Claude Code. install: 'claude plugin install ${plugin_namespace}' or see plugin docs.`
5058
- };
5049
+ function readInstalledUserSkills(homedirOverride) {
5050
+ const home = homedir();
5051
+ const skillsRoot = join(home, ".claude", "skills");
5052
+ try {
5053
+ const entries = readdirSync(skillsRoot, { withFileTypes: true });
5054
+ const out = /* @__PURE__ */ new Set();
5055
+ for (const e of entries) if (e.isDirectory()) out.add(e.name);
5056
+ return out;
5057
+ } catch {
5058
+ return /* @__PURE__ */ new Set();
5059
5059
  }
5060
- const bare = cmd.slice(1);
5061
- return { renderedCmd: `/${plugin_namespace}:${bare}` };
5060
+ }
5061
+ function resolveCapabilityCmd(capability, installedPlugins, installedUserSkills) {
5062
+ const { cmd, install_type, plugin_id, skill_dir } = capability;
5063
+ if (!install_type) return { renderedCmd: cmd };
5064
+ const types = Array.isArray(install_type) ? install_type : [install_type];
5065
+ const uniqueTypes = [...new Set(types)];
5066
+ const missingHints = [];
5067
+ let anyDetected = false;
5068
+ for (const t2 of uniqueTypes) {
5069
+ if (t2 === "plugin") {
5070
+ if (!plugin_id) {
5071
+ missingHints.push(
5072
+ `install_type=plugin declared but no plugin_id (capabilities.yaml schema bug)`
5073
+ );
5074
+ continue;
5075
+ }
5076
+ if (installedPlugins.has(plugin_id)) {
5077
+ anyDetected = true;
5078
+ break;
5079
+ }
5080
+ missingHints.push(`plugin '${plugin_id}' (\`claude plugin install ${plugin_id}\`)`);
5081
+ } else {
5082
+ if (!skill_dir) {
5083
+ missingHints.push(
5084
+ `install_type=user-skill declared but no skill_dir (capabilities.yaml schema bug)`
5085
+ );
5086
+ continue;
5087
+ }
5088
+ if (installedUserSkills.has(skill_dir)) {
5089
+ anyDetected = true;
5090
+ break;
5091
+ }
5092
+ missingHints.push(
5093
+ `user-skill '${skill_dir}' under ~/.claude/skills/ (git clone the official repo; e.g. gstack: \`git clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup\`)`
5094
+ );
5095
+ }
5096
+ }
5097
+ if (anyDetected) return { renderedCmd: cmd };
5098
+ const prefix = uniqueTypes.length > 1 ? "[multi]" : `[${uniqueTypes[0]}]`;
5099
+ const joined = missingHints.join(" OR ");
5100
+ return {
5101
+ renderedCmd: cmd,
5102
+ warning: `${prefix} '${cmd}' backing missing \u2014 install either: ${joined}.`
5103
+ };
5062
5104
  }
5063
5105
  var CAPABILITY_CMD_TEMPLATE = /\{\{\s*capabilities\.([a-zA-Z0-9_-]+)\.cmd\s*\}\}/g;
5064
- function renderSkillBody(body, capabilities, installedPlugins) {
5106
+ function renderSkillBody(body, capabilities, installedPlugins, installedUserSkills) {
5065
5107
  const warningsSet = /* @__PURE__ */ new Set();
5066
5108
  const out = body.replace(CAPABILITY_CMD_TEMPLATE, (match2, name) => {
5067
5109
  const cap = capabilities[name];
@@ -5071,7 +5113,11 @@ function renderSkillBody(body, capabilities, installedPlugins) {
5071
5113
  );
5072
5114
  return match2;
5073
5115
  }
5074
- const { renderedCmd, warning } = resolveCapabilityCmd(cap, installedPlugins);
5116
+ const { renderedCmd, warning } = resolveCapabilityCmd(
5117
+ cap,
5118
+ installedPlugins,
5119
+ installedUserSkills
5120
+ );
5075
5121
  if (warning) warningsSet.add(warning);
5076
5122
  return renderedCmd;
5077
5123
  });
@@ -5085,7 +5131,7 @@ async function loadCapabilities(workflowsDir) {
5085
5131
  const doc = parse(raw);
5086
5132
  return doc?.capabilities ?? {};
5087
5133
  }
5088
- async function renderSkillFile(skillName, skillsBase, capabilities, installedPlugins) {
5134
+ async function renderSkillFile(skillName, skillsBase, capabilities, installedPlugins, installedUserSkills) {
5089
5135
  const skillPath = join(skillsBase, skillName, "SKILL.md");
5090
5136
  const result = {
5091
5137
  name: skillName,
@@ -5100,7 +5146,7 @@ async function renderSkillFile(skillName, skillsBase, capabilities, installedPlu
5100
5146
  result.error = `read failed: ${e.message}`;
5101
5147
  return result;
5102
5148
  }
5103
- const rendered = renderSkillBody(body, capabilities, installedPlugins);
5149
+ const rendered = renderSkillBody(body, capabilities, installedPlugins, installedUserSkills);
5104
5150
  if (rendered.body === body) {
5105
5151
  result.warnings = rendered.warnings;
5106
5152
  return result;
@@ -5133,10 +5179,17 @@ async function renderAllSkills(skillNames, skillsBase, workflowsDir, homedirOver
5133
5179
  };
5134
5180
  }
5135
5181
  const installedPlugins = readInstalledPlugins();
5182
+ const installedUserSkills = readInstalledUserSkills();
5136
5183
  const results = [];
5137
5184
  const warningSet = /* @__PURE__ */ new Set();
5138
5185
  for (const name of skillNames) {
5139
- const r = await renderSkillFile(name, skillsBase, capabilities, installedPlugins);
5186
+ const r = await renderSkillFile(
5187
+ name,
5188
+ skillsBase,
5189
+ capabilities,
5190
+ installedPlugins,
5191
+ installedUserSkills
5192
+ );
5140
5193
  results.push(r);
5141
5194
  for (const w of r.warnings) warningSet.add(w);
5142
5195
  if (r.error) warningSet.add(`${name}: ${r.error}`);