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 +2 -2
- package/dist/cli.mjs +139 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/workflows/capabilities.yaml +64 -0
- package/workflows/discuss/phase/SKILL.md +8 -0
- package/workflows/discuss/strategic/SKILL.md +8 -0
- package/workflows/discuss/subtask/SKILL.md +8 -0
- package/workflows/plan/architecture/SKILL.md +8 -0
- package/workflows/plan/phase/SKILL.md +8 -0
- package/workflows/retro/SKILL.md +8 -0
- package/workflows/task/clarify/SKILL.md +8 -0
- package/workflows/task/code/SKILL.md +8 -0
- package/workflows/task/deliver/SKILL.md +8 -0
- package/workflows/task/test/SKILL.md +8 -0
- package/workflows/verify/code-review/SKILL.md +8 -0
- package/workflows/verify/design/SKILL.md +8 -0
- package/workflows/verify/multispec/SKILL.md +8 -0
- package/workflows/verify/paranoid/SKILL.md +8 -0
- package/workflows/verify/progress/SKILL.md +8 -0
- package/workflows/verify/qa/SKILL.md +8 -0
- package/workflows/verify/security/SKILL.md +8 -0
- package/workflows/verify/simplify/SKILL.md +8 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# harnessed
|
|
2
2
|
|
|
3
|
-
**English** | [
|
|
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
|
-
|
|
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.
|
|
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 }));
|