@nanobpm/nano-workforce 0.175.1 → 0.175.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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.175.2](https://github.com/nanobpm/nano-workforce/compare/v0.175.1...v0.175.2) (2026-09-02)
2
+
3
+ ### Bug Fixes
4
+
5
+ * **abandon:** don't let the cancel-check deadlock a shell-less agent ([#678](https://github.com/nanobpm/nano-workforce/issues/678)) ([#709](https://github.com/nanobpm/nano-workforce/issues/709)) ([f5fed93](https://github.com/nanobpm/nano-workforce/commit/f5fed93bdd0e98cbb24f7dff4b0f9a650c235a69)), closes [#76](https://github.com/nanobpm/nano-workforce/issues/76) [#76](https://github.com/nanobpm/nano-workforce/issues/76)
6
+
1
7
  ## [0.175.1](https://github.com/nanobpm/nano-workforce/compare/v0.175.0...v0.175.1) (2026-09-02)
2
8
 
3
9
  ### Bug Fixes
@@ -83,6 +83,32 @@ test("renderAbandonBrief embeds the concrete URL and the stop contract", () => {
83
83
  assertEquals(brief.includes("curl -fsS"), true);
84
84
  });
85
85
 
86
+ test("renderAbandonBrief forbids delegating the check to a sub-agent (issue #678)", () => {
87
+ // A non-Claude agent (e.g. qwen) that hands this shell command to a shell-less
88
+ // `general-purpose` sub-agent deadlocks: the sub-agent has no shell, produces no
89
+ // output, and the worker's idle timeout kills the round. The brief must steer the
90
+ // agent to run the check inline with its OWN shell and never delegate it.
91
+ const brief = renderAbandonBrief("https://host/app/api/hooks/abandon?token=tok");
92
+ // Not merely that it *mentions* sub-agents/inline — it must explicitly PROHIBIT delegation, so a
93
+ // future edit that softened the brief into *encouraging* delegation would fail this test.
94
+ assertEquals(/do \*\*not\*\* delegate it to a\s+sub-?agent/i.test(brief), true, "explicitly forbids delegating to a sub-agent");
95
+ assertEquals(/inline/i.test(brief), true, "tells the agent to run it inline");
96
+ });
97
+
98
+ test("renderAbandonBrief degrades gracefully when the agent has no shell (issue #678)", () => {
99
+ // The check is ADVISORY over an airtight harness job-fence (issue #76 layer 2). An
100
+ // agent that cannot run a shell command at all must be told to SKIP and proceed
101
+ // rather than thrash/hang — the harness job-fence (issue #76 layer 2) still fences
102
+ // a cancelled run, so a skipped check degrades safely rather than promising full
103
+ // independent enforcement.
104
+ const brief = renderAbandonBrief("https://host/app/api/hooks/abandon?token=tok");
105
+ assertEquals(/skip this check/i.test(brief), true, "offers a skip path");
106
+ // Assert the actual anti-deadlock contract, not an explanatory word: a shell-less agent must be
107
+ // told its lack of a shell is NOT a failed check, and must be forbidden from stalling/hanging.
108
+ assertEquals(/not (a )?failed check/i.test(brief), true, "no shell is not treated as a failed check");
109
+ assertEquals(/never stall,.*hang/i.test(brief), true, "forbids stalling/hanging when it can't run curl");
110
+ });
111
+
86
112
  test("prKeyForAbandonToken resolves a known token and rejects unknowns", async () => {
87
113
  const data = memData();
88
114
  await seedPr(data, "o/r#1", "tok", "converging");
package/app/abandon.ts CHANGED
@@ -148,5 +148,18 @@ down), instead of silently printing an error body with exit 0.
148
148
  try to complete the job is EXPECTED after a cancel — do not treat it as an error to retry.
149
149
  - **Proceed** only when the command **succeeds** AND reports \`"abandoned": false\` — and re-check
150
150
  right before the push, since a cancel can land at any moment. Checking as late as possible keeps
151
- the window tiny.`;
151
+ the window tiny.
152
+
153
+ **Run this check yourself, inline, with your own shell tool.** Do **not** delegate it to a
154
+ sub-agent, helper, or a separate "run this command" task: a sub-agent may have **no shell**, in which
155
+ case it cannot run \`curl\`, produces no output, and the worker's idle timeout will kill the round.
156
+ One inline \`curl\` in your own turn is all this needs.
157
+
158
+ **Having no way to run a shell command at all is NOT a failed check — SKIP this check and proceed.**
159
+ The "abort on non-zero exit" rule above is about \`curl\` *running and reporting* a torn-down run; it
160
+ does **not** mean "abort because you have no shell to run \`curl\` with". This check is a best-effort
161
+ optimisation, not a hard gate: the harness that runs your job also fences a cancelled run's
162
+ completion, so a skipped check only widens a tiny race — it does not by itself create an orphaned
163
+ run. Never stall, thrash, hang, or fail the round trying to run \`curl\` through a tool you do not
164
+ have; a skipped check is strictly better than a hung one.`;
152
165
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.175.1",
3
+ "version": "0.175.2",
4
4
  "description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
5
5
  "type": "module",
6
6
  "main": "main.ts",