c8ctl-plugin-nano 1.38.0 → 1.39.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/c8ctl-plugin.js +70 -48
- package/package.json +9 -9
package/c8ctl-plugin.js
CHANGED
|
@@ -2483,54 +2483,43 @@ function resolveAutoRestConfig(camunda, env = process.env) {
|
|
|
2483
2483
|
// exist" is answerable from that engine alone.
|
|
2484
2484
|
//
|
|
2485
2485
|
// `@nanobpm/agentic/demand` already reads deployed `taskDefinition` leaves over
|
|
2486
|
-
// C8 REST (`process-definitions/search` → `/{key}/xml`)
|
|
2487
|
-
//
|
|
2488
|
-
//
|
|
2489
|
-
//
|
|
2490
|
-
//
|
|
2491
|
-
//
|
|
2492
|
-
//
|
|
2493
|
-
//
|
|
2486
|
+
// C8 REST (`process-definitions/search` → `/{key}/xml`). As of
|
|
2487
|
+
// `@nanobpm/agentic@0.4.0` its `scanTaskDefinitions(xml)` tags every leaf with a
|
|
2488
|
+
// canonical `agentic: boolean` — true iff the service task declares a
|
|
2489
|
+
// `<zeebe:linkedResource … linkName="prompt">` base-prompt side-car (its internal
|
|
2490
|
+
// `hasPromptLink`). That flag is the SINGLE SOURCE OF TRUTH for agentic-ness (see
|
|
2491
|
+
// the package's `demand/taskdef.d.ts` and nano-workforce SPEC "Agent job
|
|
2492
|
+
// contract"): every external agent task delivers its base prompt through a
|
|
2493
|
+
// `linkName="prompt"` linked resource, and no in-process worker task does. Not
|
|
2494
|
+
// every service task is an agent task — plain connectors and record-keepers
|
|
2495
|
+
// (e.g. `pr.record-plan`) are ordinary workers, and they carry no prompt link.
|
|
2496
|
+
//
|
|
2497
|
+
// Per AGENTS.md "Derivation Over Duplication: No Drift Surfaces", this plugin
|
|
2498
|
+
// CONSUMES that flag rather than re-implementing the scan, so the detector can
|
|
2499
|
+
// never drift out of lock-step with the package again (as it did in #95, when a
|
|
2500
|
+
// local copy keyed on the legacy `io.nanobpm.agentTask` header missed the current
|
|
2501
|
+
// linked-prompt marker). Advertise the raw job-type string the engine matches
|
|
2502
|
+
// (`senior:plan`) verbatim — colon-named types are NOT forced through the agentic
|
|
2503
|
+
// dot-grammar.
|
|
2494
2504
|
// ---------------------------------------------------------------------------
|
|
2495
2505
|
|
|
2496
|
-
//
|
|
2497
|
-
//
|
|
2498
|
-
//
|
|
2499
|
-
//
|
|
2500
|
-
//
|
|
2501
|
-
function
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
// Scan one deployed BPMN document for its *agent* task-definition leaves: every
|
|
2512
|
-
// `<bpmn:serviceTask>` carrying BOTH a non-empty `<zeebe:taskDefinition type>`
|
|
2513
|
-
// AND an `io.nanobpm.agentTask.` task header. Returns `{ taskType, process }`
|
|
2514
|
-
// leaves in first-occurrence order. This is the header-aware extension of the
|
|
2515
|
-
// demand package's `scanTaskDefinitions` (which reads type/element/process only).
|
|
2516
|
-
function scanAgentTaskLeaves(xml) {
|
|
2517
|
-
const source = String(xml || '');
|
|
2518
|
-
const procMatch = source.match(/<bpmn:process\b[^>]*\bid\s*=\s*"([^"]*)"/);
|
|
2519
|
-
const proc = procMatch ? procMatch[1] : '';
|
|
2520
|
-
const out = [];
|
|
2521
|
-
const blockRe = /<bpmn:serviceTask\b[^>]*>([\s\S]*?)<\/bpmn:serviceTask>/g;
|
|
2522
|
-
let block;
|
|
2523
|
-
while ((block = blockRe.exec(source)) !== null) {
|
|
2524
|
-
const body = block[1];
|
|
2525
|
-
const tdMatch = body.match(/<zeebe:taskDefinition\b[^>]*>/);
|
|
2526
|
-
if (!tdMatch) continue;
|
|
2527
|
-
const typeMatch = tdMatch[0].match(/\btype\s*=\s*"([^"]*)"/);
|
|
2528
|
-
const taskType = typeMatch ? typeMatch[1] : '';
|
|
2529
|
-
if (!taskType) continue;
|
|
2530
|
-
if (!serviceTaskHasAgentHeader(body)) continue;
|
|
2531
|
-
out.push({ taskType, process: proc });
|
|
2506
|
+
// Scan one deployed BPMN document for its *agent* task-definition leaves: the
|
|
2507
|
+
// subset of `@nanobpm/agentic` `demand.scanTaskDefinitions(xml)` leaves whose
|
|
2508
|
+
// canonical `agentic` flag is set (i.e. the service task declares a
|
|
2509
|
+
// `linkName="prompt"` linked resource). Returns `{ taskType, process }` leaves in
|
|
2510
|
+
// first-occurrence order. The published `scanTaskDefinitions` is INJECTED so this
|
|
2511
|
+
// stays a pure, synchronous function; `readDeployedAgentJobTypes` supplies the
|
|
2512
|
+
// real one from the lazily-imported demand surface (`agentic.mjs`).
|
|
2513
|
+
function scanAgentTaskLeaves(xml, scanTaskDefinitions) {
|
|
2514
|
+
if (typeof scanTaskDefinitions !== 'function') {
|
|
2515
|
+
throw new TypeError(
|
|
2516
|
+
'scanAgentTaskLeaves: `scanTaskDefinitions` must be an injected function ' +
|
|
2517
|
+
`(got ${typeof scanTaskDefinitions}); pass demand.scanTaskDefinitions from ./agentic.mjs`
|
|
2518
|
+
);
|
|
2532
2519
|
}
|
|
2533
|
-
return
|
|
2520
|
+
return scanTaskDefinitions(String(xml || ''))
|
|
2521
|
+
.filter((leaf) => leaf.agentic)
|
|
2522
|
+
.map((leaf) => ({ taskType: leaf.taskType, process: leaf.process }));
|
|
2534
2523
|
}
|
|
2535
2524
|
|
|
2536
2525
|
// Read the distinct deployed *agent* job types through a demand C8RestReader
|
|
@@ -2539,12 +2528,13 @@ function scanAgentTaskLeaves(xml) {
|
|
|
2539
2528
|
// optional `scope` narrows to one app/network — kept only when the leaf's
|
|
2540
2529
|
// `bpmn:process` id equals or is prefixed by the scope string.
|
|
2541
2530
|
async function readDeployedAgentJobTypes(reader, { scope = '' } = {}) {
|
|
2531
|
+
const { demand } = await import('./agentic.mjs');
|
|
2542
2532
|
const keys = await reader.searchProcessDefinitionKeys();
|
|
2543
2533
|
const seen = new Set();
|
|
2544
2534
|
const out = [];
|
|
2545
2535
|
for (const key of keys) {
|
|
2546
2536
|
const xml = await reader.getProcessDefinitionXml(key);
|
|
2547
|
-
for (const leaf of scanAgentTaskLeaves(xml)) {
|
|
2537
|
+
for (const leaf of scanAgentTaskLeaves(xml, demand.scanTaskDefinitions)) {
|
|
2548
2538
|
if (scope && !(leaf.process === scope || leaf.process.startsWith(scope))) continue;
|
|
2549
2539
|
if (seen.has(leaf.taskType)) continue;
|
|
2550
2540
|
seen.add(leaf.taskType);
|
|
@@ -4702,7 +4692,9 @@ async function workAgent(req, flags) {
|
|
|
4702
4692
|
// no capability, no app enrol endpoint, no channel connection. It is the
|
|
4703
4693
|
// mutually-exclusive counterpart to capability-resolved SERVE: in `--auto`
|
|
4704
4694
|
// the rank×capability matrix is bypassed entirely (any deployed agent job is
|
|
4705
|
-
// served, gated only by the `
|
|
4695
|
+
// served, gated only by the leaf's canonical `agentic` flag — the
|
|
4696
|
+
// `linkName="prompt"` linked-resource marker read by
|
|
4697
|
+
// `@nanobpm/agentic`'s demand scanner), and the
|
|
4706
4698
|
// desired set is reconciled by polling the engine rather than watching the
|
|
4707
4699
|
// profile. `--auto-scope <process-id|prefix>` narrows the blast radius to one
|
|
4708
4700
|
// app/network; without it, every agent job type on the engine is served.
|
|
@@ -5836,6 +5828,10 @@ function summarizeSupervisorWorker(w, now = Date.now()) {
|
|
|
5836
5828
|
startedAtMs,
|
|
5837
5829
|
lastExit: w.lastExit ?? null,
|
|
5838
5830
|
args: Array.isArray(w.args) ? w.args : [],
|
|
5831
|
+
// The per-worker log path (logs/supervisor/worker-<id>.log). Carried through
|
|
5832
|
+
// so `supervisor status` can surface it (see formatSupervisorLogsLines);
|
|
5833
|
+
// null when the source record predates it (e.g. an older persisted state).
|
|
5834
|
+
logFile: w.logFile ?? null,
|
|
5839
5835
|
activity,
|
|
5840
5836
|
engine,
|
|
5841
5837
|
agentic,
|
|
@@ -6042,6 +6038,30 @@ function createSupervisorLiveView({
|
|
|
6042
6038
|
};
|
|
6043
6039
|
}
|
|
6044
6040
|
|
|
6041
|
+
/**
|
|
6042
|
+
* The `Logs:` block for `supervisor status`, derived purely from the status
|
|
6043
|
+
* payload so it renders identically for a live daemon status and a synthesized
|
|
6044
|
+
* one. Lists the daemon log and each worker's log file, plus a hint at the
|
|
6045
|
+
* existing tailer. Returns an empty array (no section) when no log path is
|
|
6046
|
+
* known — an older persisted state, or a dead daemon whose frame carried none.
|
|
6047
|
+
*/
|
|
6048
|
+
function formatSupervisorLogsLines(status) {
|
|
6049
|
+
const daemonLog = status?.daemon?.logFile || null;
|
|
6050
|
+
const workers = Array.isArray(status?.workers) ? status.workers : [];
|
|
6051
|
+
const workerLogs = workers
|
|
6052
|
+
.filter((w) => w && w.logFile)
|
|
6053
|
+
.map((w) => ({ label: String(w.id), path: String(w.logFile) }));
|
|
6054
|
+
const entries = [];
|
|
6055
|
+
if (daemonLog) entries.push({ label: 'daemon', path: String(daemonLog) });
|
|
6056
|
+
for (const w of workerLogs) entries.push(w);
|
|
6057
|
+
if (entries.length === 0) return [];
|
|
6058
|
+
const labelWidth = Math.max(...entries.map((e) => e.label.length));
|
|
6059
|
+
const out = ['', 'Logs:'];
|
|
6060
|
+
for (const e of entries) out.push(` ${e.label.padEnd(labelWidth)} ${e.path}`);
|
|
6061
|
+
out.push(' View: c8ctl nano supervisor logs [<id>] [--follow]');
|
|
6062
|
+
return out;
|
|
6063
|
+
}
|
|
6064
|
+
|
|
6045
6065
|
/** Render a supervisor status object as an aligned text table. */
|
|
6046
6066
|
function formatSupervisorStatus(status) {
|
|
6047
6067
|
const lines = [];
|
|
@@ -6055,6 +6075,7 @@ function formatSupervisorStatus(status) {
|
|
|
6055
6075
|
lines.push('');
|
|
6056
6076
|
if (workers.length === 0) {
|
|
6057
6077
|
lines.push(' No workers. Add one with: c8ctl nano supervisor add <profile>');
|
|
6078
|
+
lines.push(...formatSupervisorLogsLines(status));
|
|
6058
6079
|
return lines.join('\n');
|
|
6059
6080
|
}
|
|
6060
6081
|
const rows = workers.map((w) => ({
|
|
@@ -6079,6 +6100,7 @@ function formatSupervisorStatus(status) {
|
|
|
6079
6100
|
const fmt = (r) => ' ' + cols.map((c) => r[c].padEnd(width[c])).join(' ');
|
|
6080
6101
|
lines.push(fmt(head));
|
|
6081
6102
|
for (const r of rows) lines.push(fmt(r));
|
|
6103
|
+
lines.push(...formatSupervisorLogsLines(status));
|
|
6082
6104
|
return lines.join('\n');
|
|
6083
6105
|
}
|
|
6084
6106
|
|
|
@@ -8881,7 +8903,6 @@ export {
|
|
|
8881
8903
|
jobTypeMatrix,
|
|
8882
8904
|
diffJobTypes,
|
|
8883
8905
|
parseJobTypeFlags,
|
|
8884
|
-
serviceTaskHasAgentHeader,
|
|
8885
8906
|
scanAgentTaskLeaves,
|
|
8886
8907
|
readDeployedAgentJobTypes,
|
|
8887
8908
|
resolveAutoJobTypes,
|
|
@@ -8912,6 +8933,7 @@ export {
|
|
|
8912
8933
|
formatDuration,
|
|
8913
8934
|
summarizeSupervisorWorker,
|
|
8914
8935
|
formatSupervisorStatus,
|
|
8936
|
+
formatSupervisorLogsLines,
|
|
8915
8937
|
reageSupervisorStatus,
|
|
8916
8938
|
clampToWidth,
|
|
8917
8939
|
createSupervisorLiveView,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.39.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "c8ctl plugin to start, inspect, and stop a local Nano BPM (nanobpmn) cluster",
|
|
6
6
|
"main": "c8ctl-plugin.js",
|
|
@@ -52,17 +52,17 @@
|
|
|
52
52
|
"semantic-release": "^25.0.3"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@nanobpm/agentic": "^0.
|
|
55
|
+
"@nanobpm/agentic": "^0.4.0",
|
|
56
56
|
"@nanobpm/urban-agent-client": "^0.1.4"
|
|
57
57
|
},
|
|
58
58
|
"optionalDependencies": {
|
|
59
59
|
"node-pty": "^1.0.0",
|
|
60
|
-
"@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.
|
|
61
|
-
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.
|
|
62
|
-
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.
|
|
63
|
-
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.
|
|
64
|
-
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.
|
|
65
|
-
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.
|
|
66
|
-
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.
|
|
60
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.39.0",
|
|
61
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.39.0",
|
|
62
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.39.0",
|
|
63
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.39.0",
|
|
64
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.39.0",
|
|
65
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.39.0",
|
|
66
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.39.0"
|
|
67
67
|
}
|
|
68
68
|
}
|