c8ctl-plugin-nano 1.14.0 → 1.15.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 +12 -0
- package/c8ctl-plugin.js +46 -3
- package/nanobpmn-binary.json +3 -3
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -169,6 +169,18 @@ capabilities `code-review, testing` the matrix is:
|
|
|
169
169
|
so a BPMN service task can target a worker at any granularity by setting its job
|
|
170
170
|
type to the matching token.
|
|
171
171
|
|
|
172
|
+
To also service a job type the matrix can't express — for example a code-first
|
|
173
|
+
[`@nanobpm/workflow`](https://www.npmjs.com/package/@nanobpm/workflow) flow whose
|
|
174
|
+
external task type is `<flowId>:<taskName>`, or any bespoke token — add one or
|
|
175
|
+
more `--job-type <token>` flags. They are serviced **in addition to** the
|
|
176
|
+
rank×capability matrix, so a single hired reviewer can drive both a model-first
|
|
177
|
+
`senior:pr-review` task and a code-first flow's task without re-hiring:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
c8ctl nano work reviewer --job-type convergence-loop:review-round
|
|
181
|
+
c8ctl nano work reviewer --job-type senior:pr-review --job-type senior:triage
|
|
182
|
+
```
|
|
183
|
+
|
|
172
184
|
```bash
|
|
173
185
|
c8ctl nano work reviewer # poll for work until Ctrl-C
|
|
174
186
|
c8ctl nano work reviewer --max-parallel 2 --job-timeout 600000
|
package/c8ctl-plugin.js
CHANGED
|
@@ -1401,6 +1401,35 @@ function parseEnvPairs(input) {
|
|
|
1401
1401
|
return { env, errors };
|
|
1402
1402
|
}
|
|
1403
1403
|
|
|
1404
|
+
// A worker job-type token: rank/capability tokens use `:` (rank↔cap) and `+`
|
|
1405
|
+
// (combined caps) as delimiters, and code-first `@nanobpm/workflow` job types
|
|
1406
|
+
// are `<flowId>:<taskName>` or an explicit override. The first character must be
|
|
1407
|
+
// a letter, digit, or `_`; the remainder may also include `. : + -`. Mirrors the
|
|
1408
|
+
// SDK's assertJobType so a token authored on one side is accepted on the other.
|
|
1409
|
+
const JOB_TYPE_TOKEN_RE = /^[A-Za-z0-9_][A-Za-z0-9_.:+-]*$/;
|
|
1410
|
+
|
|
1411
|
+
// Parse repeatable `--job-type <token>` CLI input (string | string[]) into a
|
|
1412
|
+
// deduped, validated list of explicit job types a worker should also service,
|
|
1413
|
+
// in addition to its rank×capability matrix. Returns { jobTypes, errors }.
|
|
1414
|
+
function parseJobTypeFlags(input) {
|
|
1415
|
+
const list = input == null ? [] : (Array.isArray(input) ? input : [input]);
|
|
1416
|
+
const seen = new Set();
|
|
1417
|
+
const jobTypes = [];
|
|
1418
|
+
const errors = [];
|
|
1419
|
+
for (const item of list) {
|
|
1420
|
+
const token = String(item).trim();
|
|
1421
|
+
if (!token) { errors.push('--job-type must be a non-empty token'); continue; }
|
|
1422
|
+
if (!JOB_TYPE_TOKEN_RE.test(token)) {
|
|
1423
|
+
errors.push(`--job-type "${token}" is invalid (must match ${JOB_TYPE_TOKEN_RE.source})`);
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
if (seen.has(token)) continue;
|
|
1427
|
+
seen.add(token);
|
|
1428
|
+
jobTypes.push(token);
|
|
1429
|
+
}
|
|
1430
|
+
return { jobTypes, errors };
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1404
1433
|
/** A profile name must be a safe, filesystem/token-friendly slug. */
|
|
1405
1434
|
function isValidProfileName(name) {
|
|
1406
1435
|
return typeof name === 'string' && /^[a-z0-9][a-z0-9._-]*$/i.test(name);
|
|
@@ -2658,6 +2687,16 @@ async function workAgent(req, flags) {
|
|
|
2658
2687
|
}
|
|
2659
2688
|
|
|
2660
2689
|
const matrix = jobTypeMatrix(profile.rank, profile.capabilities);
|
|
2690
|
+
// Optional explicit job types (repeatable `--job-type`), serviced in addition
|
|
2691
|
+
// to the rank×capability matrix. This lets a hired profile also drive a pool
|
|
2692
|
+
// keyed on a token the matrix can't express — e.g. a code-first
|
|
2693
|
+
// `@nanobpm/workflow` flow whose external task type isn't a `rank:cap` token.
|
|
2694
|
+
const { jobTypes: extraJobTypes, errors: jobTypeErrors } = parseJobTypeFlags(flags?.['job-type']);
|
|
2695
|
+
if (jobTypeErrors.length > 0) {
|
|
2696
|
+
logger.error(jobTypeErrors.join('; '));
|
|
2697
|
+
process.exit(1);
|
|
2698
|
+
}
|
|
2699
|
+
const jobTypes = [...new Set([...matrix, ...extraJobTypes])];
|
|
2661
2700
|
const camunda = globalThis.c8ctl.createClient();
|
|
2662
2701
|
|
|
2663
2702
|
logger.info(`Putting "${name}" [${profile.rank}] to work → ${profile.command}`);
|
|
@@ -2665,12 +2704,13 @@ async function workAgent(req, flags) {
|
|
|
2665
2704
|
logger.info(` sandbox: ${sandbox}${isContainer ? ` (image ${image})` : ''}`);
|
|
2666
2705
|
const profileEnvKeys = Object.keys(profileEnv);
|
|
2667
2706
|
if (profileEnvKeys.length > 0) logger.info(` harness env: ${profileEnvKeys.join(', ')}`);
|
|
2668
|
-
|
|
2707
|
+
const extraNote = extraJobTypes.length > 0 ? ` (${extraJobTypes.length} via --job-type)` : '';
|
|
2708
|
+
logger.info(` listening on ${jobTypes.length} job type(s)${extraNote}: ${jobTypes.join(' ')}`);
|
|
2669
2709
|
logger.info(` max parallel: ${maxParallelJobs}; job timeout: ${jobTimeoutMs}ms`);
|
|
2670
2710
|
logger.info(` console: ${webConsoleUrl(runningConsoleBaseUrl(), JOURNEY_AGENTIC_AUTHOR)}`);
|
|
2671
2711
|
logger.info('Polling for work — press Ctrl-C to stop.');
|
|
2672
2712
|
|
|
2673
|
-
const workers =
|
|
2713
|
+
const workers = jobTypes.map((jobType) =>
|
|
2674
2714
|
camunda.createJobWorker({
|
|
2675
2715
|
jobType,
|
|
2676
2716
|
workerName: `${name}:${jobType}`,
|
|
@@ -4236,6 +4276,7 @@ export {
|
|
|
4236
4276
|
ProvisionError,
|
|
4237
4277
|
normalizeStoredProfile,
|
|
4238
4278
|
jobTypeMatrix,
|
|
4279
|
+
parseJobTypeFlags,
|
|
4239
4280
|
AGENT_TASK_NS,
|
|
4240
4281
|
AGENT_RESULT_KEY,
|
|
4241
4282
|
RESULT_SENTINEL,
|
|
@@ -4338,6 +4379,7 @@ export const commands = {
|
|
|
4338
4379
|
list: { type: 'boolean', description: 'hire: list existing agent profiles instead of creating one' },
|
|
4339
4380
|
'max-parallel': { type: 'string', description: 'work: max concurrent jobs per worker (default 1)' },
|
|
4340
4381
|
'job-timeout': { type: 'string', description: 'work: max harness runtime per job in ms; the spawned process is killed past this (default 300000)' },
|
|
4382
|
+
'job-type': { type: 'string', multiple: true, description: 'work: extra job type to service alongside the rank×capability matrix (repeatable)' },
|
|
4341
4383
|
},
|
|
4342
4384
|
handler: async (args, flags) => {
|
|
4343
4385
|
const logger = getLogger();
|
|
@@ -4481,7 +4523,7 @@ function printUsage() {
|
|
|
4481
4523
|
console.log(' c8ctl nano config');
|
|
4482
4524
|
console.log(' c8ctl nano update [--check]');
|
|
4483
4525
|
console.log(' c8ctl nano hire [--name <n>] [--rank <r>] [--command <c>] [--model <m>] [--capabilities <a,b>] [--sandbox none|docker|podman] [--image <ref>] [--env NAME=VALUE ...] [--list]');
|
|
4484
|
-
console.log(' c8ctl nano work <profileName> [--max-parallel <n>] [--job-timeout <ms>] [--sandbox none|docker|podman] [--image <ref>] [--env NAME=VALUE ...] [--secret-resolver host] [--min-free-mb <n>] [--clone-timeout <ms>] [--keep-runs] [--stream]');
|
|
4526
|
+
console.log(' c8ctl nano work <profileName> [--max-parallel <n>] [--job-timeout <ms>] [--job-type <token> ...] [--sandbox none|docker|podman] [--image <ref>] [--env NAME=VALUE ...] [--secret-resolver host] [--min-free-mb <n>] [--clone-timeout <ms>] [--keep-runs] [--stream]');
|
|
4485
4527
|
console.log('');
|
|
4486
4528
|
console.log('Subcommands:');
|
|
4487
4529
|
console.log(' start Spawn an N-node local cluster wired to talk to each other on localhost');
|
|
@@ -4522,6 +4564,7 @@ function printUsage() {
|
|
|
4522
4564
|
console.log(' --env NAME=VALUE hire/work: static env var for the harness (repeatable); persisted on hire, work extends/overrides');
|
|
4523
4565
|
console.log(' --list hire: list existing agent profiles instead of creating one');
|
|
4524
4566
|
console.log(' --max-parallel <n> work: max concurrent jobs per worker (default 1)');
|
|
4567
|
+
console.log(' --job-type <token> work: extra job type to service alongside the rank×capability matrix (repeatable)');
|
|
4525
4568
|
console.log(' --job-timeout <ms> work: max harness runtime per job in ms (default 300000)');
|
|
4526
4569
|
console.log(' --secret-resolver <r> work: secret resolver for task secretRefs (host; default host)');
|
|
4527
4570
|
console.log(' --reap-age <ms> work: age before a finished agent container/workspace is reaped (default 3600000)');
|
package/nanobpmn-binary.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.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",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"semantic-release": "^25.0.3"
|
|
50
50
|
},
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.
|
|
53
|
-
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.
|
|
54
|
-
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.
|
|
55
|
-
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.
|
|
56
|
-
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.
|
|
57
|
-
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.
|
|
58
|
-
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.
|
|
52
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.15.0",
|
|
53
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.15.0",
|
|
54
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.15.0",
|
|
55
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.15.0",
|
|
56
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.15.0",
|
|
57
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.15.0",
|
|
58
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.15.0"
|
|
59
59
|
}
|
|
60
60
|
}
|