harnessed 3.4.0 → 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/README.md +2 -2
- package/dist/cli.mjs +193 -2
- 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 +146 -7
- package/workflows/discuss/phase/SKILL.md +11 -0
- package/workflows/discuss/strategic/SKILL.md +11 -0
- package/workflows/discuss/subtask/SKILL.md +11 -0
- package/workflows/plan/architecture/SKILL.md +11 -0
- package/workflows/plan/phase/SKILL.md +11 -0
- package/workflows/retro/SKILL.md +11 -0
- package/workflows/task/clarify/SKILL.md +11 -0
- package/workflows/task/code/SKILL.md +11 -0
- package/workflows/task/deliver/SKILL.md +11 -0
- package/workflows/task/test/SKILL.md +11 -0
- package/workflows/verify/code-review/SKILL.md +11 -0
- package/workflows/verify/design/SKILL.md +11 -0
- package/workflows/verify/multispec/SKILL.md +11 -0
- package/workflows/verify/paranoid/SKILL.md +11 -0
- package/workflows/verify/progress/SKILL.md +11 -0
- package/workflows/verify/qa/SKILL.md +11 -0
- package/workflows/verify/security/SKILL.md +11 -0
- package/workflows/verify/simplify/SKILL.md +11 -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
|
@@ -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,
|
|
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.
|
|
850
|
+
version: "3.4.2"};
|
|
851
851
|
|
|
852
852
|
// src/manifest/errors.ts
|
|
853
853
|
function instancePathToKeyPath(instancePath) {
|
|
@@ -5020,6 +5020,182 @@ 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 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
|
+
}
|
|
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
|
+
};
|
|
5104
|
+
}
|
|
5105
|
+
var CAPABILITY_CMD_TEMPLATE = /\{\{\s*capabilities\.([a-zA-Z0-9_-]+)\.cmd\s*\}\}/g;
|
|
5106
|
+
function renderSkillBody(body, capabilities, installedPlugins, installedUserSkills) {
|
|
5107
|
+
const warningsSet = /* @__PURE__ */ new Set();
|
|
5108
|
+
const out = body.replace(CAPABILITY_CMD_TEMPLATE, (match2, name) => {
|
|
5109
|
+
const cap = capabilities[name];
|
|
5110
|
+
if (!cap) {
|
|
5111
|
+
warningsSet.add(
|
|
5112
|
+
`capability '${name}' referenced in SKILL.md but not defined in capabilities.yaml`
|
|
5113
|
+
);
|
|
5114
|
+
return match2;
|
|
5115
|
+
}
|
|
5116
|
+
const { renderedCmd, warning } = resolveCapabilityCmd(
|
|
5117
|
+
cap,
|
|
5118
|
+
installedPlugins,
|
|
5119
|
+
installedUserSkills
|
|
5120
|
+
);
|
|
5121
|
+
if (warning) warningsSet.add(warning);
|
|
5122
|
+
return renderedCmd;
|
|
5123
|
+
});
|
|
5124
|
+
return { body: out, warnings: [...warningsSet] };
|
|
5125
|
+
}
|
|
5126
|
+
|
|
5127
|
+
// src/cli/lib/renderSkillTemplates.ts
|
|
5128
|
+
async function loadCapabilities(workflowsDir) {
|
|
5129
|
+
const path = join(workflowsDir, "capabilities.yaml");
|
|
5130
|
+
const raw = await readFile(path, "utf8");
|
|
5131
|
+
const doc = parse(raw);
|
|
5132
|
+
return doc?.capabilities ?? {};
|
|
5133
|
+
}
|
|
5134
|
+
async function renderSkillFile(skillName, skillsBase, capabilities, installedPlugins, installedUserSkills) {
|
|
5135
|
+
const skillPath = join(skillsBase, skillName, "SKILL.md");
|
|
5136
|
+
const result = {
|
|
5137
|
+
name: skillName,
|
|
5138
|
+
skillPath,
|
|
5139
|
+
rendered: false,
|
|
5140
|
+
warnings: []
|
|
5141
|
+
};
|
|
5142
|
+
let body;
|
|
5143
|
+
try {
|
|
5144
|
+
body = await readFile(skillPath, "utf8");
|
|
5145
|
+
} catch (e) {
|
|
5146
|
+
result.error = `read failed: ${e.message}`;
|
|
5147
|
+
return result;
|
|
5148
|
+
}
|
|
5149
|
+
const rendered = renderSkillBody(body, capabilities, installedPlugins, installedUserSkills);
|
|
5150
|
+
if (rendered.body === body) {
|
|
5151
|
+
result.warnings = rendered.warnings;
|
|
5152
|
+
return result;
|
|
5153
|
+
}
|
|
5154
|
+
try {
|
|
5155
|
+
await writeFile(skillPath, rendered.body, "utf8");
|
|
5156
|
+
result.rendered = true;
|
|
5157
|
+
result.warnings = rendered.warnings;
|
|
5158
|
+
} catch (e) {
|
|
5159
|
+
result.error = `write failed: ${e.message}`;
|
|
5160
|
+
}
|
|
5161
|
+
return result;
|
|
5162
|
+
}
|
|
5163
|
+
async function renderAllSkills(skillNames, skillsBase, workflowsDir, homedirOverride) {
|
|
5164
|
+
let capabilities = {};
|
|
5165
|
+
try {
|
|
5166
|
+
capabilities = await loadCapabilities(workflowsDir);
|
|
5167
|
+
} catch (e) {
|
|
5168
|
+
return {
|
|
5169
|
+
results: skillNames.map((name) => ({
|
|
5170
|
+
name,
|
|
5171
|
+
skillPath: join(skillsBase, name, "SKILL.md"),
|
|
5172
|
+
rendered: false,
|
|
5173
|
+
warnings: [],
|
|
5174
|
+
error: `capabilities.yaml load failed: ${e.message}`
|
|
5175
|
+
})),
|
|
5176
|
+
aggregatedWarnings: [
|
|
5177
|
+
`capabilities.yaml unreadable \u2014 SKILL.md placeholders left verbatim (${e.message})`
|
|
5178
|
+
]
|
|
5179
|
+
};
|
|
5180
|
+
}
|
|
5181
|
+
const installedPlugins = readInstalledPlugins();
|
|
5182
|
+
const installedUserSkills = readInstalledUserSkills();
|
|
5183
|
+
const results = [];
|
|
5184
|
+
const warningSet = /* @__PURE__ */ new Set();
|
|
5185
|
+
for (const name of skillNames) {
|
|
5186
|
+
const r = await renderSkillFile(
|
|
5187
|
+
name,
|
|
5188
|
+
skillsBase,
|
|
5189
|
+
capabilities,
|
|
5190
|
+
installedPlugins,
|
|
5191
|
+
installedUserSkills
|
|
5192
|
+
);
|
|
5193
|
+
results.push(r);
|
|
5194
|
+
for (const w of r.warnings) warningSet.add(w);
|
|
5195
|
+
if (r.error) warningSet.add(`${name}: ${r.error}`);
|
|
5196
|
+
}
|
|
5197
|
+
return { results, aggregatedWarnings: [...warningSet] };
|
|
5198
|
+
}
|
|
5023
5199
|
init_checkAgentTeams();
|
|
5024
5200
|
var FLAT_LEGACY_DEPRECATED = /* @__PURE__ */ new Set(["plan-feature", "execute-task", "verify-work"]);
|
|
5025
5201
|
var FLAT_LEGACY_KEEP = /* @__PURE__ */ new Set(["research", "retro", "auto"]);
|
|
@@ -5240,6 +5416,21 @@ function registerSetup(program2) {
|
|
|
5240
5416
|
}
|
|
5241
5417
|
}
|
|
5242
5418
|
console.log(t("setup.step_a_complete", { count: skillsInstalled, path: skillsBase }));
|
|
5419
|
+
const skillNames = toInstall.map((wf) => wf.name);
|
|
5420
|
+
const rendered = await renderAllSkills(skillNames, skillsBase, workflowsDir);
|
|
5421
|
+
const renderedCount = rendered.results.filter((r) => r.rendered).length;
|
|
5422
|
+
console.log(
|
|
5423
|
+
t("setup.step_a_render.complete", {
|
|
5424
|
+
count: renderedCount,
|
|
5425
|
+
total: skillsInstalled
|
|
5426
|
+
})
|
|
5427
|
+
);
|
|
5428
|
+
if (rendered.aggregatedWarnings.length > 0) {
|
|
5429
|
+
console.warn(t("setup.step_a_render.warnings_header"));
|
|
5430
|
+
for (const w of rendered.aggregatedWarnings) {
|
|
5431
|
+
console.warn(` - ${w}`);
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5243
5434
|
const cResult = await enableAgentTeamsInSettings();
|
|
5244
5435
|
if (cResult.status === "created") {
|
|
5245
5436
|
console.log(t("setup.step_c.created", { path: cResult.path }));
|