c8ctl-plugin-nano 1.61.2 → 1.62.0

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
@@ -236,11 +236,14 @@ How it works and why it needs no wiring:
236
236
  agent jobs at all, it and the app are already on the same engine, so *what
237
237
  agent job types exist* is answerable from that engine alone — **no cross-machine
238
238
  app discovery, no app enrol endpoint, no channel connection**.
239
- - **Agent-task header filter.** Not every service task is an agent task —
239
+ - **Agent-task marker filter.** Not every service task is an agent task —
240
240
  connectors and record-keepers (e.g. `pr.record-plan`) are plain workers.
241
- `--auto` keeps only leaves whose service task carries an
242
- **`io.nanobpm.agentTask.`** task header (e.g. `senior:plan` carries
243
- `io.nanobpm.agentTask.task.prompt`; a record-keeper does not).
241
+ `--auto` keeps only leaves whose service task carries the single-convention
242
+ external-agent marker **`<zeebe:agentDefinition agentType="external" />`** (the
243
+ same marker every external agent task already declares). A task can **opt out**
244
+ of `--auto` with `<zeebe:property name="io.nanobpm.agentTask.autoSubscribe"
245
+ value="false" />` — it is then served only by explicit `--job-type`/profile
246
+ subscription.
244
247
  - **One poller per agent job type, reconciled on change.** It opens one poller
245
248
  per agent job type and re-reads the engine periodically, adding pollers for
246
249
  newly deployed agent processes and draining pollers for undeployed ones — the
@@ -1263,6 +1263,50 @@ export function createAgentInstanceProducer(opts = {}) {
1263
1263
  await queue;
1264
1264
  },
1265
1265
 
1266
+ /**
1267
+ * Abort/discard teardown for a run ABANDONED during setup (issue #222). Unlike
1268
+ * `complete()` this does NOT drive a terminal COMPLETED update and — critically —
1269
+ * does NOT make a last-chance create attempt: the run is being yielded for retry,
1270
+ * so minting an instance for it would be an orphaned side effect. It makes the
1271
+ * producer permanently INERT so no late create can mint after the runner has
1272
+ * returned from the abort path — closing the window the suppressed advisory flags,
1273
+ * where a retry-pending producer (`active === false`) whose in-flight/armed
1274
+ * `createAgentInstance` settles late would still mint a durable instance:
1275
+ * - `finalized = true` gates `ingest()` (drops late ACP frames), `maybeStartCreate()`
1276
+ * (no hot-path retry), AND `doCreate()`'s latch guard (a late create success is
1277
+ * dropped rather than latching a key + replaying the pre-mint buffer);
1278
+ * - bumping `createGen` neutralises an already in-flight attempt via the SAME
1279
+ * identity guard `retireCreate` uses, so its late settle is dropped even before
1280
+ * `finalized` is read, and frees the `creating` slot;
1281
+ * - the pre-mint buffer is released (it can never be replayed now);
1282
+ * - queued appends against an ALREADY-minted instance are drained best-effort so
1283
+ * they are not lost, without transitioning status.
1284
+ * Idempotent and best-effort; never throws. Safe to call for BOTH an active
1285
+ * producer and a retry-pending one (the two cases the advisory calls out).
1286
+ */
1287
+ async discard() {
1288
+ if (finalized) {
1289
+ try { await this.drain(); } catch { /* best effort */ }
1290
+ return;
1291
+ }
1292
+ finalized = true;
1293
+ // Neutralise any in-flight create: bump the identity past the owning attempt so
1294
+ // its late resolve/reject is dropped by doCreate's `gen !== createGen` guard, and
1295
+ // free the slot (a retired attempt's own finally is a no-op once we've bumped).
1296
+ createGen += 1;
1297
+ creating = null;
1298
+ creatingGen = 0;
1299
+ creatingFinal = false;
1300
+ // The pre-mint buffer can never be replayed once finalized — release it (and its
1301
+ // counters) rather than pin it for the life of a still-hung uncancellable POST.
1302
+ preMintBuffer.length = 0;
1303
+ preMintBufferBytes = 0;
1304
+ preMintDropped = 0;
1305
+ // Flush appends already queued against a minted instance (best effort); no
1306
+ // terminal update — the run was abandoned, not successfully completed.
1307
+ try { await this.drain(); } catch { /* best effort */ }
1308
+ },
1309
+
1266
1310
  /**
1267
1311
  * End the AgentInstance lifecycle. Flushes any pending message turn, drains the
1268
1312
  * append queue, then — only on a SUCCESSFUL job end (`ok`) — updates the instance
package/agentic.mjs CHANGED
@@ -97,8 +97,10 @@ export * as sessionAcp from '@nanobpm/agentic/session/acp';
97
97
  // `httpC8RestReader` to enumerate deployed process definitions and read each
98
98
  // one's BPMN XML straight from the engine the worker already talks to — the
99
99
  // zero-config enrolment source. The header-filter that narrows those leaves to
100
- // *agent* job types lives in the plugin (`scanAgentTaskLeaves`), extending the
101
- // package's type/element/process-only scanner with a `zeebe:taskHeaders` read.
100
+ // *agent* job types lives in the plugin (`scanAgentTaskLeaves`), narrowing the
101
+ // package's type/element/process scanner to leaves carrying the single-convention
102
+ // external-agent marker (`<zeebe:agentDefinition agentType="external">`, issue
103
+ // #235) and dropping any opted out via `io.nanobpm.agentTask.autoSubscribe="false"`.
102
104
  // ---------------------------------------------------------------------------
103
105
  export * as demand from '@nanobpm/agentic/demand';
104
106