harnessed 3.4.0 → 3.4.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # harnessed
2
2
 
3
- **English** | [中文](./README-cn.md)
3
+ **English** | [简体中文](./README-cn.md) | [繁體中文](./README-tw.md) | [日本語](./README-ja.md) | [한국어](./README-ko.md) | [Português (Brasil)](./README-pt-BR.md) | [Türkçe](./README-tr.md) | [Русский](./README-ru.md) | [Tiếng Việt](./README-vi.md) | [ไทย](./README-th.md)
4
4
 
5
5
  > AI coding harness package manager + composition orchestrator
6
6
  > Machine-executes the three-layer-stack collaboration methodology (gstack governance + GSD project manager + superpowers senior engineer + karpathy principles + mattpocock moves) as a runnable engine
@@ -15,7 +15,7 @@
15
15
 
16
16
  ## ✨ TL;DR
17
17
 
18
- Assembles the best open-source Claude Code ecosystem components, weaving them into a unified workflow via opinionated composition skills; does not vendor upstream code — manifests describe install/check, and composition skills orchestrate multi-upstream collaboration.
18
+ **Best-practice orchestration for Harness Engineering on Claude Code** — assembles the best open-source Claude Code ecosystem components, weaving them into a unified workflow via opinionated composition skills; does not vendor upstream code — manifests describe install/check, and composition skills orchestrate multi-upstream collaboration.
19
19
 
20
20
  ---
21
21
 
package/dist/cli.mjs CHANGED
@@ -847,7 +847,7 @@ var init_resume = __esm({
847
847
 
848
848
  // package.json
849
849
  var package_default = {
850
- version: "3.4.0"};
850
+ version: "3.4.1"};
851
851
 
852
852
  // src/manifest/errors.ts
853
853
  function instancePathToKeyPath(instancePath) {
@@ -5020,6 +5020,129 @@ async function atomicWrite2(path, content) {
5020
5020
  return `write ${path} failed: ${err2.message}`;
5021
5021
  }
5022
5022
  }
5023
+ function readInstalledPlugins(homedirOverride) {
5024
+ const home = homedir();
5025
+ const path = join(home, ".claude", "plugins", "installed_plugins.json");
5026
+ let raw;
5027
+ try {
5028
+ raw = readFileSync(path, "utf8");
5029
+ } catch {
5030
+ return /* @__PURE__ */ new Set();
5031
+ }
5032
+ let parsed;
5033
+ try {
5034
+ parsed = JSON.parse(raw);
5035
+ } catch {
5036
+ return /* @__PURE__ */ new Set();
5037
+ }
5038
+ if (!parsed || typeof parsed !== "object") return /* @__PURE__ */ new Set();
5039
+ const plugins = parsed.plugins;
5040
+ if (!plugins || typeof plugins !== "object") return /* @__PURE__ */ new Set();
5041
+ const out = /* @__PURE__ */ new Set();
5042
+ for (const key of Object.keys(plugins)) {
5043
+ const at = key.indexOf("@");
5044
+ if (at <= 0) continue;
5045
+ out.add(key.slice(0, at));
5046
+ }
5047
+ return out;
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
+ };
5059
+ }
5060
+ const bare = cmd.slice(1);
5061
+ return { renderedCmd: `/${plugin_namespace}:${bare}` };
5062
+ }
5063
+ var CAPABILITY_CMD_TEMPLATE = /\{\{\s*capabilities\.([a-zA-Z0-9_-]+)\.cmd\s*\}\}/g;
5064
+ function renderSkillBody(body, capabilities, installedPlugins) {
5065
+ const warningsSet = /* @__PURE__ */ new Set();
5066
+ const out = body.replace(CAPABILITY_CMD_TEMPLATE, (match2, name) => {
5067
+ const cap = capabilities[name];
5068
+ if (!cap) {
5069
+ warningsSet.add(
5070
+ `capability '${name}' referenced in SKILL.md but not defined in capabilities.yaml`
5071
+ );
5072
+ return match2;
5073
+ }
5074
+ const { renderedCmd, warning } = resolveCapabilityCmd(cap, installedPlugins);
5075
+ if (warning) warningsSet.add(warning);
5076
+ return renderedCmd;
5077
+ });
5078
+ return { body: out, warnings: [...warningsSet] };
5079
+ }
5080
+
5081
+ // src/cli/lib/renderSkillTemplates.ts
5082
+ async function loadCapabilities(workflowsDir) {
5083
+ const path = join(workflowsDir, "capabilities.yaml");
5084
+ const raw = await readFile(path, "utf8");
5085
+ const doc = parse(raw);
5086
+ return doc?.capabilities ?? {};
5087
+ }
5088
+ async function renderSkillFile(skillName, skillsBase, capabilities, installedPlugins) {
5089
+ const skillPath = join(skillsBase, skillName, "SKILL.md");
5090
+ const result = {
5091
+ name: skillName,
5092
+ skillPath,
5093
+ rendered: false,
5094
+ warnings: []
5095
+ };
5096
+ let body;
5097
+ try {
5098
+ body = await readFile(skillPath, "utf8");
5099
+ } catch (e) {
5100
+ result.error = `read failed: ${e.message}`;
5101
+ return result;
5102
+ }
5103
+ const rendered = renderSkillBody(body, capabilities, installedPlugins);
5104
+ if (rendered.body === body) {
5105
+ result.warnings = rendered.warnings;
5106
+ return result;
5107
+ }
5108
+ try {
5109
+ await writeFile(skillPath, rendered.body, "utf8");
5110
+ result.rendered = true;
5111
+ result.warnings = rendered.warnings;
5112
+ } catch (e) {
5113
+ result.error = `write failed: ${e.message}`;
5114
+ }
5115
+ return result;
5116
+ }
5117
+ async function renderAllSkills(skillNames, skillsBase, workflowsDir, homedirOverride) {
5118
+ let capabilities = {};
5119
+ try {
5120
+ capabilities = await loadCapabilities(workflowsDir);
5121
+ } catch (e) {
5122
+ return {
5123
+ results: skillNames.map((name) => ({
5124
+ name,
5125
+ skillPath: join(skillsBase, name, "SKILL.md"),
5126
+ rendered: false,
5127
+ warnings: [],
5128
+ error: `capabilities.yaml load failed: ${e.message}`
5129
+ })),
5130
+ aggregatedWarnings: [
5131
+ `capabilities.yaml unreadable \u2014 SKILL.md placeholders left verbatim (${e.message})`
5132
+ ]
5133
+ };
5134
+ }
5135
+ const installedPlugins = readInstalledPlugins();
5136
+ const results = [];
5137
+ const warningSet = /* @__PURE__ */ new Set();
5138
+ for (const name of skillNames) {
5139
+ const r = await renderSkillFile(name, skillsBase, capabilities, installedPlugins);
5140
+ results.push(r);
5141
+ for (const w of r.warnings) warningSet.add(w);
5142
+ if (r.error) warningSet.add(`${name}: ${r.error}`);
5143
+ }
5144
+ return { results, aggregatedWarnings: [...warningSet] };
5145
+ }
5023
5146
  init_checkAgentTeams();
5024
5147
  var FLAT_LEGACY_DEPRECATED = /* @__PURE__ */ new Set(["plan-feature", "execute-task", "verify-work"]);
5025
5148
  var FLAT_LEGACY_KEEP = /* @__PURE__ */ new Set(["research", "retro", "auto"]);
@@ -5240,6 +5363,21 @@ function registerSetup(program2) {
5240
5363
  }
5241
5364
  }
5242
5365
  console.log(t("setup.step_a_complete", { count: skillsInstalled, path: skillsBase }));
5366
+ const skillNames = toInstall.map((wf) => wf.name);
5367
+ const rendered = await renderAllSkills(skillNames, skillsBase, workflowsDir);
5368
+ const renderedCount = rendered.results.filter((r) => r.rendered).length;
5369
+ console.log(
5370
+ t("setup.step_a_render.complete", {
5371
+ count: renderedCount,
5372
+ total: skillsInstalled
5373
+ })
5374
+ );
5375
+ if (rendered.aggregatedWarnings.length > 0) {
5376
+ console.warn(t("setup.step_a_render.warnings_header"));
5377
+ for (const w of rendered.aggregatedWarnings) {
5378
+ console.warn(` - ${w}`);
5379
+ }
5380
+ }
5243
5381
  const cResult = await enableAgentTeamsInSettings();
5244
5382
  if (cResult.status === "created") {
5245
5383
  console.log(t("setup.step_c.created", { path: cResult.path }));