@nanobpm/nano-workforce 0.186.3 → 0.186.4

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.186.4](https://github.com/nanobpm/nano-workforce/compare/v0.186.3...v0.186.4) (2026-09-12)
2
+
3
+ ### Bug Fixes
4
+
5
+ * **agentic:** allow c8ctl GitHub auth for repository provisioning ([#784](https://github.com/nanobpm/nano-workforce/issues/784)) ([323bb05](https://github.com/nanobpm/nano-workforce/commit/323bb05060e63ca57082d42e3bf9c91f63abaa0a)), closes [#770](https://github.com/nanobpm/nano-workforce/issues/770) [#770](https://github.com/nanobpm/nano-workforce/issues/770) [#770](https://github.com/nanobpm/nano-workforce/issues/770)
6
+
1
7
  ## [0.186.3](https://github.com/nanobpm/nano-workforce/compare/v0.186.2...v0.186.3) (2026-09-12)
2
8
 
3
9
  ### Bug Fixes
package/app/contracts.ts CHANGED
@@ -399,9 +399,9 @@ export const WIRE_CONTRACTS = {
399
399
  name: "io.nanobpm.agentTask.repository",
400
400
  owner: "app/repoEnvelope.ts",
401
401
  semantics:
402
- "Repo-provisioning envelope the app emits as a `createInstance` process variable (`repoEnvelopeVars`, app/repoEnvelope.ts) and the c8ctl worker harness consumes to provision an isolated clone — instead of the agent inheriting the worker's launch dir (issue #684). `ref` is the branch checked out: the PR HEAD branch on the PR-based paths (review-round / fix-ci / rebase), or — on the PRE-PR implementation path (feature.bpmn / plan-fanout's `implement-cell`, issue #684; the delivery-graph runner's agent cells, issue #686) — the BASE branch, off which the harness cuts a new feature branch named by the optional `branch.create` (the deterministic `feat/<task.id>`, emitted only for a single-task feature run; the epic seed AND the delivery-graph run-root seed omit it so each fan-out slice's agent branches per node/MI child). Beyond `{provider,url,ref}`, it carries clone-shaping fields for large monorepos (issue #287): `singleBranch:true` + `filter:\"blob:none\"` (a branch-scoped, blobless partial clone — trees fetched up-front, blobs lazily, no `--depth 1` so the merge-base/3-dot diff stays valid) and an optional `baseRef` (the PR base branch, emitted only when resolvable, so the harness fetches its tip and keeps `origin/<base>` reachable) and a `cloneTimeoutMs` (from `NANO_PR_CLONE_TIMEOUT_MS`, default 600000 = 10 min) that raises the harness's 120s default so a large monorepo's blobless single-branch clone provisions instead of dying at 120s (issue #694). World-restore (issue #324, ADR 0062 Slice 4/5): an optional `sha` — the last durable push-checkpoint — is emitted so a REPLACEMENT activation on a fresh worktree reconstructs the tree to the EXACT pushed SHA (inverting the round's `git push` into `git fetch && git checkout <sha>`), omitted when the PR has no checkpoint yet. The field is named `sha` because that is the field the c8ctl harness's `provisionRepo` reads to drive the checkout — an earlier `commitSha` key was a silent no-op (issue #695). Gated on c8ctl provisioner support (jwulf/c8ctl-plugin-nano#91).",
402
+ "Repo-provisioning envelope the app emits as a `createInstance` process variable (`repoEnvelopeVars`, app/repoEnvelope.ts) and the c8ctl worker harness consumes to provision an isolated clone — instead of the agent inheriting the worker's launch dir (issue #684). `ref` is the branch checked out: the PR HEAD branch on the PR-based paths (review-round / fix-ci / rebase), or — on the PRE-PR implementation path (feature.bpmn / plan-fanout's `implement-cell`, issue #684; the delivery-graph runner's agent cells, issue #686) — the BASE branch, off which the harness cuts a new feature branch named by the optional `branch.create` (the deterministic `feat/<task.id>`, emitted only for a single-task feature run; the epic seed AND the delivery-graph run-root seed omit it so each fan-out slice's agent branches per node/MI child). Beyond `{provider,url,ref}`, it carries clone-shaping fields for large monorepos (issue #287): `singleBranch:true` + `filter:\"blob:none\"` (a branch-scoped, blobless partial clone — trees fetched up-front, blobs lazily, no `--depth 1` so the merge-base/3-dot diff stays valid) and an optional `baseRef` (the PR base branch, emitted only when resolvable, so the harness fetches its tip and keeps `origin/<base>` reachable) and a `cloneTimeoutMs` (from `NANO_PR_CLONE_TIMEOUT_MS`, default 600000 = 10 min) that raises the harness's 120s default so a large monorepo's blobless single-branch clone provisions instead of dying at 120s (issue #694). World-restore (issue #324, ADR 0062 Slice 4/5): an optional `sha` — the last durable push-checkpoint — is emitted so a REPLACEMENT activation on a fresh worktree reconstructs the tree to the EXACT pushed SHA (inverting the round's `git push` into `git fetch && git checkout <sha>`), omitted when the PR has no checkpoint yet. The field is named `sha` because that is the field the c8ctl harness's `provisionRepo` reads to drive the checkout — an earlier `commitSha` key was a silent no-op (issue #695). Alongside the `repository` slice the envelope carries a sibling `task.allowPr: true` (issue #770): c8ctl-plugin-nano (≥1.60.2) only resolves the git credential (GITHUB_TOKEN, or the `gh` default) for repo provisioning behind that flag, so every repo-backed envelope sets it or the clone dies with `unable to get password from user`; the repoless path emits no envelope and so no `task`. Gated on c8ctl provisioner support (jwulf/c8ctl-plugin-nano#91).",
403
403
  shape:
404
- '{ provider: "github", url: string, ref: string, singleBranch: true, filter: "blob:none", cloneTimeoutMs: number, baseRef?: string, sha?: string, branch?: { create: string } }',
404
+ 'io.nanobpm.agentTask: { repository: { provider: "github", url: string, ref?: string, singleBranch: true, filter: "blob:none", cloneTimeoutMs: number, baseRef?: string, sha?: string, branch?: { create: string } }, task: { allowPr: true } }',
405
405
  },
406
406
  "epicSet.submit": {
407
407
  category: "wire",
@@ -485,6 +485,9 @@ test("prepareDeliveryGraph injects the repository envelope PER agent cell from t
485
485
  assert(headers.some((h) => h.includes('repository.provider" value="github"')), "provider header");
486
486
  assert(headers.some((h) => h.includes('repository.singleBranch" value="true"')), "branch-scoped blobless clone (#287)");
487
487
  assert(headers.some((h) => h.includes('repository.filter" value="blob:none"')), "blobless filter");
488
+ // Repo-provisioning auth gate (issue #770): the per-cell envelope carries `task.allowPr:true` so the
489
+ // c8ctl harness resolves the git credential for the clone instead of failing on password prompt.
490
+ assert(headers.some((h) => h.includes('task.allowPr" value="true"')), `expected a task.allowPr header, got ${JSON.stringify(headers)}`);
488
491
  // No `__repoSpec` marker survives injection — it is the compiler's digest-stable anchor only.
489
492
  assert(!p.bpmn.includes("__repoSpec"), "the __repoSpec marker is fully replaced");
490
493
  // No run-root `io.nanobpm.agentTask` variable — the envelope rides headers now, not a run variable.
@@ -191,6 +191,14 @@ export function repoEnvelopeVars(
191
191
  ? { branch: { create: branchCreate.trim() } }
192
192
  : {}),
193
193
  },
194
+ // Repo-provisioning auth gate (issue #770): c8ctl-plugin-nano (≥1.60.2) only resolves the
195
+ // git credential (GITHUB_TOKEN, or the `gh` default when it's absent) for repository
196
+ // provisioning when `task.allowPr` is truthy — `resolveJobSecrets` pulls the token behind that
197
+ // flag. Without it, a repo-backed clone dies with `unable to get password from user` before the
198
+ // agent even starts. So EVERY repo-backed envelope (this builder only runs past the `owner/repo`
199
+ // guard above) opts the harness into auth-resolved provisioning. The repoless path emits `{}`
200
+ // (no envelope, no `task`), so its behaviour — and its auth posture — is unchanged.
201
+ task: { allowPr: true },
194
202
  },
195
203
  };
196
204
  }
@@ -222,6 +230,11 @@ export function agentNodeRepoEnvelope(repo: string, base: string | null): Record
222
230
  // `feat/<node.id>` off. Omitted when unknown so the harness clones the repo's default branch.
223
231
  ...(ref ? { ref, baseRef: ref } : {}),
224
232
  },
233
+ // Repo-provisioning auth gate (issue #770): as in `repoEnvelopeVars`, a repo-backed cell must
234
+ // opt the harness into git-credential resolution (`task.allowPr`) or the clone fails with
235
+ // `unable to get password from user`. Emitted on every resolved cell (past the `owner/repo`
236
+ // guard above); an unresolved/`repoless` cell returns `{}` and carries no `task`.
237
+ task: { allowPr: true },
225
238
  },
226
239
  };
227
240
  }
@@ -487,6 +487,24 @@ test("repoEnvelopeVars emits the repository envelope keyed on the PR head branch
487
487
  assertEquals(env.repository.cloneTimeoutMs, 600000);
488
488
  });
489
489
 
490
+ // Repo-provisioning auth gate (issue #770): c8ctl-plugin-nano (≥1.60.2) only resolves the git
491
+ // credential (GITHUB_TOKEN, or the `gh` default when it's absent) for repository provisioning when
492
+ // `task.allowPr` is truthy. Without it a repo-backed clone dies with `unable to get password from
493
+ // user` before the agent starts. Every repo-backed envelope must therefore carry `task.allowPr:
494
+ // true`; the repoless (unresolved) path emits nothing, so it carries no `task` and is unchanged.
495
+ test("repoEnvelopeVars emits task.allowPr:true on every repo-backed envelope (#770)", () => {
496
+ // PR-based path (review-round / fix-ci / rebase).
497
+ const pr = (repoEnvelopeVars("owner/repo", "feat/issue-12", "main") as any)["io.nanobpm.agentTask"];
498
+ assertEquals(pr.task.allowPr, true, "the PR-based envelope opts the harness into auth-resolved provisioning");
499
+ // Pre-PR implementation path (feature.bpmn / plan-fanout's implement-cell, #684).
500
+ const prePr = (repoEnvelopeVars("owner/repo", "main", null, null, "feat/issue-7") as any)["io.nanobpm.agentTask"];
501
+ assertEquals(prePr.task.allowPr, true, "the pre-PR envelope opts in too");
502
+ // A repoless / unresolved input emits NOTHING — no envelope, and so no `task` (auth posture
503
+ // unchanged: the launch-dir fallback needs no repo credential).
504
+ assertEquals(Object.keys(repoEnvelopeVars("owner/repo", null)).length, 0, "unresolved head → no envelope, no task");
505
+ assertEquals(Object.keys(repoEnvelopeVars("not-owner-repo", "feat/x")).length, 0, "malformed repo → no envelope, no task");
506
+ });
507
+
490
508
  test("repoEnvelopeVars emits cloneTimeoutMs from NANO_PR_CLONE_TIMEOUT_MS, default 600000 (#694)", () => {
491
509
  // Default (knob unset): 600000ms = 10 min, raising the harness's 120000ms default so a
492
510
  // branch-scoped blobless clone of a large monorepo provisions instead of dying at 120s.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.186.3",
3
+ "version": "0.186.4",
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",