c8ctl-plugin-nano 1.44.2 → 1.44.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/README.md CHANGED
@@ -571,9 +571,24 @@ the job with a decremented retry count. Profiles are stored in the plugin's
571
571
  > the node is lost, the harness is idle-killed, or it hits the hard cap — the
572
572
  > lock lapses within one `--recovery-window` and the broker reclaims the job.
573
573
  > This is deliberately optimised for quick reclaim, not for holding a stale lock.
574
- > - **`--idle-timeout`** (default `300000`ms) is the liveness gate: if the agent
575
- > produces no stdout/stderr for this long it is killed as wedged, extension
576
- > stops, and the job is reclaimed so a hung agent can't hold a job forever.
574
+ > - **`--idle-timeout`** (default `300000`ms) is the liveness gate but it is
575
+ > **progress-aware**, not a blunt silence timer. When the window elapses the
576
+ > worker probes the harness's process subtree: if a descendant is still doing
577
+ > work (aggregate CPU time across the tree is advancing — e.g. a long, quiet
578
+ > `./mvnw -q` build that emits nothing for minutes) the agent is treated as
579
+ > **live** and the kill is deferred. Only a genuinely quiescent tree — no live
580
+ > descendant, or descendants burning no CPU across the window — is killed as
581
+ > wedged, so a hung agent still can't hold a job forever while a silent-but-busy
582
+ > one keeps the cheapest, zero-token build pattern. Reclaim timing: because a
583
+ > single CPU sample can't reveal progress, the first elapse with live
584
+ > descendants only *baselines* and re-probes — the kill-vs-defer decision then
585
+ > lands on the following `--recovery-window`, so a quiescent-but-live subtree
586
+ > ages out roughly `--idle-timeout` **plus one recovery window** after the last
587
+ > output, not the instant the idle window first elapses. (A tree with no live
588
+ > descendants is killed immediately when the idle window elapses.) A task can
589
+ > widen this per-task class via the envelope's `task.idleTimeoutMs` /
590
+ > `task.recoveryWindowMs` (see the task envelope below) instead of a global
591
+ > flag change.
577
592
  > - **`--job-timeout`** is now an *optional* absolute hard cap on total harness
578
593
  > runtime (default `0` = unlimited), for when you want a ceiling regardless of
579
594
  > output. `--lock-grace` is **deprecated and ignored** — the lock is auto-managed.
@@ -616,7 +631,16 @@ stdin payload as `task`:
616
631
  Element templates emit flat dotpath header keys (strings); the plugin expands
617
632
  them into a nested object and coerces `"true"/"false"` → bool and numeric
618
633
  strings → int. The normalized shape is
619
- `{ schemaVersion, repository{provider,url,ref,sha,depth,singleBranch,filter,baseRef,baseSha,cloneTimeoutMs,submodules,authRef}, branch{base,create,push}, setup{commands,env,secretRefs}, task{prompt,promptFile,maxIterations,timeoutMs,allowPr,prBase} }`.
634
+ `{ schemaVersion, repository{provider,url,ref,sha,depth,singleBranch,filter,baseRef,baseSha,cloneTimeoutMs,submodules,authRef}, branch{base,create,push}, setup{commands,env,secretRefs}, task{prompt,promptFile,maxIterations,timeoutMs,idleTimeoutMs,recoveryWindowMs,allowPr,prBase} }`.
635
+
636
+ **Per-task liveness overrides.** `task.idleTimeoutMs` and `task.recoveryWindowMs`
637
+ let a specific task class (e.g. an implementation job on a large monorepo) widen
638
+ the idle-liveness / broker-lock recovery window without touching the worker's
639
+ global `--idle-timeout` / `--recovery-window` flags, and `task.timeoutMs` raises
640
+ the absolute hard cap (`--job-timeout`). Precedence is **envelope override →
641
+ worker flag → built-in default**, each clamped to a sane maximum so a task can't
642
+ request an unbounded window; absent fields leave the worker-flag behaviour
643
+ unchanged.
620
644
 
621
645
  **Prompt = base + optional verbatim append.** The agent's prompt resolves to
622
646
  `task.prompt` (typically a model header filled at deploy time), falling back to a
@@ -728,6 +752,25 @@ deleted after each job (keep them with `--keep-runs`).
728
752
  c8ctl nano work coder # sandbox=none: repository-bearing jobs are provisioned on the host
729
753
  ```
730
754
 
755
+ **Repo-less jobs run in a throwaway temp cwd (host).** When `--sandbox none` and
756
+ the envelope carries **no** `repository` block at all, there is nothing to clone,
757
+ but the job still gets a fresh, **empty** `run-*` workspace under
758
+ `<state>/agent-runs/` as its `cwd` (tracked and auto-reaped by the same run-dir
759
+ lifecycle as a provisioned clone). This makes *"each job runs in a throwaway
760
+ per-job workspace"* true **by default**, not only for repo-bearing tasks: the
761
+ worker's launch dir is never polluted with scratch files or a stray `git init`,
762
+ and an agent that must clone the repo itself gets a clean base. **This is hygiene,
763
+ not a sandbox** — the harness runs as your user with full filesystem access, so an
764
+ empty `cwd` does **not** *confine* it (an agent can still `cd` to a known absolute
765
+ path); true confinement remains the container increment, and a provisioned
766
+ `repository` envelope stays the preferred path (it also avoids a full-monorepo
767
+ self-clone, defeating the `singleBranch`+`filter` shaping above). A job whose
768
+ envelope carries a `repository` block that declares intent (any `repository.*`
769
+ field set) but whose **`url` is absent or not a usable clone target** is treated
770
+ as an orchestrator bug and **fails closed** (retryable) rather than silently
771
+ degrading to the temp cwd — surfacing the half-specified envelope loudly instead
772
+ of running an agent with no repo where one was expected.
773
+
731
774
  **Sandbox.** By default the command runs on the host (`--sandbox none`). Pass
732
775
  `--sandbox docker` (or `podman`) with an `--image` to run **each job in a
733
776
  throwaway container** instead:
package/agentic.mjs CHANGED
@@ -74,6 +74,15 @@ export * as presence from '@nanobpm/agentic/presence';
74
74
  export * as relay from '@nanobpm/agentic/relay';
75
75
  export * as transcript from '@nanobpm/agentic/transcript';
76
76
 
77
+ // ACP → transcript bridge (nanobpm/nano-ide#534). The canonical, pure wire seam
78
+ // that turns one raw ACP `session/update` into the exact `{ nwfTranscriptEvent:
79
+ // 1, kind, … }` transcript-chunk bytes the cockpit decodes — `classifyUpdate`
80
+ // composed with `encodeTranscriptEvent` behind the single `acpUpdateToTranscriptChunk`
81
+ // helper. The ACP executor (`spawnCaptureAcp`) consumes it through THIS surface
82
+ // instead of hand-rolling an envelope grammar, so there is one producer of the
83
+ // wire and the shared conformance corpus pins it to the hub.
84
+ export * as sessionAcp from '@nanobpm/agentic/session/acp';
85
+
77
86
  // ---------------------------------------------------------------------------
78
87
  // Demand read — @nanobpm/agentic/demand.
79
88
  //