harnessed 4.5.0 โ 4.5.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 +11 -4
- package/dist/cli.mjs +34 -16
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/messages/en.json +2 -2
- package/messages/zh-Hans.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
### ๐ The operating loop
|
|
23
23
|
|
|
24
|
-
> **Discuss โ Plan โ Build โ Verify โ Ship
|
|
24
|
+
> **Discuss โ Plan โ Build โ Verify โ Ship**, closed by a **Learn** loop โ machine-executed across the three-layer stack (gstack governance ยท GSD orchestration ยท superpowers TDD ยท checkpoint evidence). Raw agent work drifts; harnessed turns it into a source-of-truth path where progress and evidence persist instead of living in chat. **Learning is automatic**: every completed workflow appends its failure/loop/reject signals to `.planning/LEARNINGS.md`, which are injected into the next cycle โ this is always-on, **not** gated on the optional Retro. Retro (`/retro`) is a separate, optional milestone summary.
|
|
25
25
|
|
|
26
26
|
```mermaid
|
|
27
27
|
flowchart LR
|
|
@@ -30,9 +30,9 @@ flowchart LR
|
|
|
30
30
|
P --> T(["โข Task<br/>TDD build + checkpoint"])
|
|
31
31
|
T --> V(["โฃ Verify<br/>independent review + evidence gate"])
|
|
32
32
|
V --> S(["โค Ship<br/>release-preflight โ tag-ready (publish via CI)"])
|
|
33
|
-
S
|
|
33
|
+
S -. "milestone summary" .-> RT(["Retro<br/>(optional)"]):::opt
|
|
34
34
|
V -. "fail / gap" .-> T
|
|
35
|
-
|
|
35
|
+
S == "๐ Learn โ learnings captured on every workflow completion โ injected next cycle" ==> D
|
|
36
36
|
classDef opt stroke-dasharray:5,opacity:0.8
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -405,10 +405,17 @@ planning-with-files /plan (cross-cutting tool) โ write artifacts to .planning/
|
|
|
405
405
|
| `harnessed gates <master>` | Evaluate which sub-workflows fire for a master stage (JSON: fire/skip/parallelism). Used by slash commands to orchestrate native spawns. |
|
|
406
406
|
| `harnessed prompt <sub>` | Output a spawn-ready prompt (role + checklist + disciplines + completion/clarification protocols) for a sub-workflow. |
|
|
407
407
|
| `harnessed checkpoint <action> <sub>` | Record sub-workflow start/complete/fail to `~/.claude/harnessed/checkpoints/`. |
|
|
408
|
+
| `harnessed next` | Deterministic next-step contract (`NEXT: auto\|manual\|done`) for the active workflow. |
|
|
409
|
+
| `harnessed reject <sub>` | Mark a sub as user-rejected (terminal, distinct from `failed`). |
|
|
410
|
+
| `harnessed compact [--tokens <n>]` | Summarize+evict resolved ledger entries (G6-safe: `fail_count>0` never evicted); auto-triggers on `checkpoint complete --tokens`. |
|
|
411
|
+
| `harnessed workflows` | List in-flight workflows (one per repo). |
|
|
412
|
+
| `harnessed learn "<lesson>"` | Append a prose learning to this repo's `.planning/LEARNINGS.md`. |
|
|
408
413
|
| `harnessed run <name>` | Run a workflow via in-process SDK spawn (CI/headless mode). Slash commands use CC-native spawn instead. |
|
|
409
414
|
| `harnessed resume` | Resume from the most recent checkpoint after a session interruption |
|
|
410
415
|
| `harnessed status` | Current phase + lock holder |
|
|
411
|
-
| `harnessed doctor` |
|
|
416
|
+
| `harnessed doctor` | 14-check health check (Node / MCP / jq / Win bash / routing / token budget / mattpocock / CodeGraph / update-available, etc.) |
|
|
417
|
+
| `harnessed update [--check\|--upstreams\|--migration-report]` | Self-update (`npm i -g harnessed@latest`); `--check` reports the latest version; `--upstreams` re-runs the base manifests; `--migration-report` is a read-only stale-state inventory |
|
|
418
|
+
| `harnessed release-preflight` | Read-only release-readiness gate (CHANGELOG `[Unreleased]` / version / git-clean / tag-absent); exits 1 if not ready. The Ship-stage gate. |
|
|
412
419
|
| `harnessed install <name>` | Install an upstream manifest |
|
|
413
420
|
| `harnessed uninstall [name]` | Reverse uninstall |
|
|
414
421
|
| `harnessed backup` | Snapshot backup management |
|
package/dist/cli.mjs
CHANGED
|
@@ -38,7 +38,7 @@ var init_package = __esm({
|
|
|
38
38
|
"package.json"() {
|
|
39
39
|
package_default = {
|
|
40
40
|
name: "harnessed",
|
|
41
|
-
version: "4.5.
|
|
41
|
+
version: "4.5.1",
|
|
42
42
|
description: "AI coding harness package manager + composition orchestrator",
|
|
43
43
|
type: "module",
|
|
44
44
|
license: "Apache-2.0",
|
|
@@ -944,6 +944,10 @@ async function backup(plan, ctx) {
|
|
|
944
944
|
});
|
|
945
945
|
continue;
|
|
946
946
|
}
|
|
947
|
+
if (code === "EISDIR") {
|
|
948
|
+
entries.push({ target: file.target, backup: "", sha1: "", eol: "lf" });
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
947
951
|
return {
|
|
948
952
|
ok: false,
|
|
949
953
|
error: {
|
|
@@ -4816,7 +4820,7 @@ function expandTildeForWindows(cmd) {
|
|
|
4816
4820
|
const home = homedir().replace(/\\/g, "/");
|
|
4817
4821
|
return cmd.replace(/(^|[\s"'`(])~\//g, `$1${home}/`);
|
|
4818
4822
|
}
|
|
4819
|
-
async function spawnCmd(ctx, cmd, args, timeoutMs) {
|
|
4823
|
+
async function spawnCmd(ctx, cmd, args, timeoutMs, opts) {
|
|
4820
4824
|
const violation = checkCmdString(cmd);
|
|
4821
4825
|
if (violation) {
|
|
4822
4826
|
return {
|
|
@@ -4837,14 +4841,21 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
|
|
|
4837
4841
|
const env = { ...process.env, ...installCfg.env ?? {} };
|
|
4838
4842
|
const cwd = installCfg.cwd ?? ctx.cwd;
|
|
4839
4843
|
let child;
|
|
4844
|
+
let triedBash = false;
|
|
4840
4845
|
if (process.platform === "win32") {
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
cwd,
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4846
|
+
if (opts?.posixShell) {
|
|
4847
|
+
const joined = args.length > 0 ? `${cmd} ${args.join(" ")}` : cmd;
|
|
4848
|
+
triedBash = true;
|
|
4849
|
+
child = spawn("bash", ["-c", joined], { cwd, env, windowsHide: true });
|
|
4850
|
+
} else {
|
|
4851
|
+
const expandedCmd = expandTildeForWindows(cmd);
|
|
4852
|
+
const expandedArgs = args.map(expandTildeForWindows);
|
|
4853
|
+
child = spawn("cmd.exe", ["/c", expandedCmd, ...expandedArgs], {
|
|
4854
|
+
cwd,
|
|
4855
|
+
env,
|
|
4856
|
+
windowsHide: true
|
|
4857
|
+
});
|
|
4858
|
+
}
|
|
4848
4859
|
} else {
|
|
4849
4860
|
const joined = args.length > 0 ? `${cmd} ${args.join(" ")}` : cmd;
|
|
4850
4861
|
child = spawn("/bin/sh", ["-c", joined], { cwd, env });
|
|
@@ -4875,16 +4886,17 @@ async function spawnCmd(ctx, cmd, args, timeoutMs) {
|
|
|
4875
4886
|
}, effectiveTimeoutMs);
|
|
4876
4887
|
child.on("error", (err2) => {
|
|
4877
4888
|
clearTimeout(timer);
|
|
4889
|
+
const bashMissing = triedBash && err2.code === "ENOENT";
|
|
4878
4890
|
resolve20({
|
|
4879
4891
|
ok: false,
|
|
4880
4892
|
phase: "spawn",
|
|
4881
4893
|
error: {
|
|
4882
4894
|
file: ctx.manifest.metadata.name,
|
|
4883
4895
|
path: "/spec/install/cmd",
|
|
4884
|
-
message: `spawn failed: ${err2.message}`,
|
|
4896
|
+
message: bashMissing ? "Git Bash is required for this component on Windows, but `bash` was not found on PATH. Install Git for Windows (https://git-scm.com/download/win) and re-run `harnessed setup`." : `spawn failed: ${err2.message}`,
|
|
4885
4897
|
line: null,
|
|
4886
4898
|
column: null,
|
|
4887
|
-
keyword: "spawn-error"
|
|
4899
|
+
keyword: bashMissing ? "bash-missing" : "spawn-error"
|
|
4888
4900
|
}
|
|
4889
4901
|
});
|
|
4890
4902
|
});
|
|
@@ -4899,7 +4911,7 @@ var init_spawn = __esm({
|
|
|
4899
4911
|
"src/installers/lib/spawn.ts"() {
|
|
4900
4912
|
init_security();
|
|
4901
4913
|
DEFAULT_VERIFY_TIMEOUT_MS = 15e3;
|
|
4902
|
-
DEFAULT_INSTALL_TIMEOUT_MS =
|
|
4914
|
+
DEFAULT_INSTALL_TIMEOUT_MS = 12e4;
|
|
4903
4915
|
}
|
|
4904
4916
|
});
|
|
4905
4917
|
function extractSkillName(cmd, fallback) {
|
|
@@ -5335,7 +5347,7 @@ var init_gitCloneWithSetup2 = __esm({
|
|
|
5335
5347
|
if (ctx.opts.dryRun) return { aborted: true, reason: "user-cancel" };
|
|
5336
5348
|
const bk = await backup(plan, ctx);
|
|
5337
5349
|
if (!bk.ok) return { ok: false, phase: "preflight", error: bk.error };
|
|
5338
|
-
const sp = await spawnCmd(ctx, install.cmd, [], DEFAULT_INSTALL_TIMEOUT_MS);
|
|
5350
|
+
const sp = await spawnCmd(ctx, install.cmd, [], DEFAULT_INSTALL_TIMEOUT_MS, { posixShell: true });
|
|
5339
5351
|
if (!("exitCode" in sp)) return { ...sp, backupId: bk.backupId };
|
|
5340
5352
|
if (sp.exitCode !== 0) {
|
|
5341
5353
|
return {
|
|
@@ -5378,7 +5390,9 @@ var init_gitCloneWithSetup2 = __esm({
|
|
|
5378
5390
|
};
|
|
5379
5391
|
}
|
|
5380
5392
|
const verifyTimeoutMs = ctx.manifest.spec.verify.timeout_ms ?? DEFAULT_VERIFY_TIMEOUT_MS;
|
|
5381
|
-
const vr = await spawnCmd(ctx, ctx.manifest.spec.verify.cmd, [], verifyTimeoutMs
|
|
5393
|
+
const vr = await spawnCmd(ctx, ctx.manifest.spec.verify.cmd, [], verifyTimeoutMs, {
|
|
5394
|
+
posixShell: true
|
|
5395
|
+
});
|
|
5382
5396
|
if (!("exitCode" in vr)) return { ...vr, backupId: bk.backupId };
|
|
5383
5397
|
const expected = ctx.manifest.spec.verify.expected_exit_code ?? 0;
|
|
5384
5398
|
if (vr.exitCode !== expected) {
|
|
@@ -5809,7 +5823,9 @@ var init_npmCli2 = __esm({
|
|
|
5809
5823
|
};
|
|
5810
5824
|
}
|
|
5811
5825
|
const verifyTimeoutMs = ctx.manifest.spec.verify.timeout_ms ?? DEFAULT_VERIFY_TIMEOUT_MS;
|
|
5812
|
-
const vr = await spawnCmd(ctx, ctx.manifest.spec.verify.cmd, [], verifyTimeoutMs
|
|
5826
|
+
const vr = await spawnCmd(ctx, ctx.manifest.spec.verify.cmd, [], verifyTimeoutMs, {
|
|
5827
|
+
posixShell: true
|
|
5828
|
+
});
|
|
5813
5829
|
if (!("exitCode" in vr)) return { ...vr, backupId: bk.backupId };
|
|
5814
5830
|
const expected = ctx.manifest.spec.verify.expected_exit_code ?? 0;
|
|
5815
5831
|
if (vr.exitCode !== expected) {
|
|
@@ -5938,7 +5954,9 @@ var init_npxSkillInstaller2 = __esm({
|
|
|
5938
5954
|
};
|
|
5939
5955
|
}
|
|
5940
5956
|
const verifyTimeoutMs = ctx.manifest.spec.verify.timeout_ms ?? DEFAULT_VERIFY_TIMEOUT_MS;
|
|
5941
|
-
const vr = await spawnCmd(ctx, ctx.manifest.spec.verify.cmd, [], verifyTimeoutMs
|
|
5957
|
+
const vr = await spawnCmd(ctx, ctx.manifest.spec.verify.cmd, [], verifyTimeoutMs, {
|
|
5958
|
+
posixShell: true
|
|
5959
|
+
});
|
|
5942
5960
|
if (!("exitCode" in vr)) return { ...vr, backupId: bk.backupId };
|
|
5943
5961
|
const expected = ctx.manifest.spec.verify.expected_exit_code ?? 0;
|
|
5944
5962
|
if (vr.exitCode !== expected) {
|