c8ctl-plugin-nano 1.17.0 → 1.18.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 +21 -0
- package/c8ctl-plugin.js +82 -10
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -150,6 +150,9 @@ c8ctl nano hire
|
|
|
150
150
|
c8ctl nano hire --name reviewer --rank senior --command copilot \
|
|
151
151
|
--model gpt-5 --capabilities code-review,testing
|
|
152
152
|
|
|
153
|
+
# Give the harness command-line switches (e.g. run copilot with --allow-all)
|
|
154
|
+
c8ctl nano hire --name coder --rank senior --command copilot --arg --allow-all
|
|
155
|
+
|
|
153
156
|
# List profiles
|
|
154
157
|
c8ctl nano hire --list
|
|
155
158
|
```
|
|
@@ -327,6 +330,24 @@ envelope layers on top (job-specific tuning wins), and the reserved `AGENT_*`
|
|
|
327
330
|
variables and resolved secrets always win over user-supplied env so they can't be
|
|
328
331
|
shadowed. For **secret** values use `secretRefs`, not `--env`.
|
|
329
332
|
|
|
333
|
+
**Command-line switches.** Some harnesses take switches rather than env vars —
|
|
334
|
+
e.g. `copilot --allow-all`. Append them to the harness command with a repeatable
|
|
335
|
+
`--arg` (each `--arg` is one argv token). They are persisted on the profile at
|
|
336
|
+
hire time and can be extended at work time:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
c8ctl nano hire --name coder --rank senior --command copilot --arg --allow-all
|
|
340
|
+
c8ctl nano work coder --arg --verbose # appends to the profile args
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The command is spawned through a shell (so `command` still resolves on `PATH`),
|
|
344
|
+
but each `--arg` is shell-quoted as a single literal token, so a value with
|
|
345
|
+
spaces or shell metacharacters can't break out or inject. They apply on the
|
|
346
|
+
container path on any OS, and on the host path on POSIX systems. **On a Windows
|
|
347
|
+
host (`sandbox=none`), `--arg` is rejected** with a clear error — the POSIX
|
|
348
|
+
quoting isn't honoured by `cmd.exe` — so use a container sandbox
|
|
349
|
+
(`--sandbox docker|podman`) or bake the switches into `--command` there.
|
|
350
|
+
|
|
330
351
|
**Disk hygiene.** Host job **workspaces** and container sandboxes both get
|
|
331
352
|
automatic cleanup so leaked artifacts can't fill the disk. Workspaces under
|
|
332
353
|
`<state>/agent-runs` are removed after each job and swept at startup + on
|
package/c8ctl-plugin.js
CHANGED
|
@@ -1416,6 +1416,39 @@ function parseEnvPairs(input) {
|
|
|
1416
1416
|
return { env, errors };
|
|
1417
1417
|
}
|
|
1418
1418
|
|
|
1419
|
+
// Normalize a stored/CLI argument list (string | string[]) into a clean string[]:
|
|
1420
|
+
// each entry is one whole argv token (e.g. "--allow-all"), coerced to a string,
|
|
1421
|
+
// with null/undefined and empty tokens dropped. Interior whitespace is preserved
|
|
1422
|
+
// so a single arg may carry a value like "--foo=a b" intact.
|
|
1423
|
+
function normalizeArgList(input) {
|
|
1424
|
+
const list = input == null ? [] : (Array.isArray(input) ? input : [input]);
|
|
1425
|
+
const out = [];
|
|
1426
|
+
for (const item of list) {
|
|
1427
|
+
if (item == null) continue;
|
|
1428
|
+
const s = String(item);
|
|
1429
|
+
if (s.length === 0) continue;
|
|
1430
|
+
out.push(s);
|
|
1431
|
+
}
|
|
1432
|
+
return out;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// POSIX single-quote a string so it survives `sh -c`/shell:true as one literal
|
|
1436
|
+
// argv token, no matter what it contains (spaces, $, quotes, globs). Empty
|
|
1437
|
+
// string → ''. This is what keeps structured `--arg` values injection-safe even
|
|
1438
|
+
// though the harness is spawned through a shell (for PATH resolution).
|
|
1439
|
+
function shQuote(s) {
|
|
1440
|
+
return `'${String(s).replace(/'/g, `'\\''`)}'`;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Build the shell command line for the agent harness: the base command followed
|
|
1444
|
+
// by each structured argument, shell-quoted. With no args the command is used
|
|
1445
|
+
// verbatim (preserving pre-existing hires that baked switches into the command).
|
|
1446
|
+
function buildAgentCommandLine(command, args) {
|
|
1447
|
+
const list = normalizeArgList(args);
|
|
1448
|
+
if (list.length === 0) return command;
|
|
1449
|
+
return `${command} ${list.map(shQuote).join(' ')}`;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1419
1452
|
// A worker job-type token: rank/capability tokens use `:` (rank↔cap) and `+`
|
|
1420
1453
|
// (combined caps) as delimiters, and code-first `@nanobpm/workflow` job types
|
|
1421
1454
|
// are `<flowId>:<taskName>` or an explicit override. The first character must be
|
|
@@ -1513,6 +1546,7 @@ function normalizeStoredProfile(name, profile) {
|
|
|
1513
1546
|
name,
|
|
1514
1547
|
rank,
|
|
1515
1548
|
command,
|
|
1549
|
+
args: normalizeArgList(profile.args),
|
|
1516
1550
|
model: typeof profile.model === 'string' ? profile.model.trim() : '',
|
|
1517
1551
|
capabilities: normalizeCapabilities(profile.capabilities),
|
|
1518
1552
|
sandbox,
|
|
@@ -1541,7 +1575,7 @@ async function hireWorker(req, flags) {
|
|
|
1541
1575
|
logger.info('Hired agent profiles:');
|
|
1542
1576
|
for (const name of names.sort()) {
|
|
1543
1577
|
const p = hires[name];
|
|
1544
|
-
logger.info(` ${name} [${p.rank}] ${p.command} (model: ${p.model || '-'}; caps: ${normalizeCapabilities(p.capabilities).join(', ') || '-'})`);
|
|
1578
|
+
logger.info(` ${name} [${p.rank}] ${buildAgentCommandLine(p.command, p.args)} (model: ${p.model || '-'}; caps: ${normalizeCapabilities(p.capabilities).join(', ') || '-'})`);
|
|
1545
1579
|
}
|
|
1546
1580
|
logger.info('');
|
|
1547
1581
|
logger.info('Put one to work with: c8ctl nano work <name>');
|
|
@@ -1557,11 +1591,14 @@ async function hireWorker(req, flags) {
|
|
|
1557
1591
|
let capabilities = flags?.capabilities !== undefined ? flags.capabilities : undefined;
|
|
1558
1592
|
let sandbox = flags?.sandbox !== undefined ? String(flags.sandbox).trim().toLowerCase() : undefined;
|
|
1559
1593
|
let image = flags?.image !== undefined ? String(flags.image).trim() : undefined;
|
|
1594
|
+
// Structured command-line switches appended to the command when spawned, e.g.
|
|
1595
|
+
// `--arg --allow-all` for `copilot`. Repeatable; each --arg is one argv token.
|
|
1596
|
+
const commandArgs = normalizeArgList(flags?.arg);
|
|
1560
1597
|
const envFromFlags = flags?.env !== undefined;
|
|
1561
1598
|
const { env: profileEnv, errors: envErrors } = parseEnvPairs(flags?.env);
|
|
1562
1599
|
if (envErrors.length > 0) {
|
|
1563
1600
|
logger.error(envErrors.join('; '));
|
|
1564
|
-
logger.info('Example: c8ctl nano hire --name coder --rank senior --command copilot --
|
|
1601
|
+
logger.info('Example: c8ctl nano hire --name coder --rank senior --command copilot --arg --allow-all --env COPILOT_ENABLE_ALL_TOOLS=1');
|
|
1565
1602
|
process.exit(1);
|
|
1566
1603
|
}
|
|
1567
1604
|
|
|
@@ -1659,6 +1696,7 @@ async function hireWorker(req, flags) {
|
|
|
1659
1696
|
name,
|
|
1660
1697
|
rank,
|
|
1661
1698
|
command,
|
|
1699
|
+
args: commandArgs,
|
|
1662
1700
|
model: model || '',
|
|
1663
1701
|
capabilities: normalizeCapabilities(capabilities),
|
|
1664
1702
|
sandbox,
|
|
@@ -1669,9 +1707,10 @@ async function hireWorker(req, flags) {
|
|
|
1669
1707
|
writeHire(profile);
|
|
1670
1708
|
|
|
1671
1709
|
const matrix = jobTypeMatrix(profile.rank, profile.capabilities);
|
|
1672
|
-
logger.info(`${existed ? 'Updated' : 'Hired'} "${name}" [${profile.rank}] → ${profile.command}`);
|
|
1710
|
+
logger.info(`${existed ? 'Updated' : 'Hired'} "${name}" [${profile.rank}] → ${buildAgentCommandLine(profile.command, profile.args)}`);
|
|
1673
1711
|
logger.info(` model: ${profile.model || '(none)'}`);
|
|
1674
1712
|
logger.info(` capabilities: ${profile.capabilities.join(', ') || '(none)'}`);
|
|
1713
|
+
if (profile.args.length > 0) logger.info(` args: ${profile.args.map(shQuote).join(' ')}`);
|
|
1675
1714
|
logger.info(` sandbox: ${profile.sandbox}${CONTAINER_SANDBOXES.has(profile.sandbox) ? ` (image ${profile.image})` : ''}`);
|
|
1676
1715
|
const envKeys = Object.keys(profile.env);
|
|
1677
1716
|
if (envKeys.length > 0) logger.info(` env: ${envKeys.join(', ')}`);
|
|
@@ -2450,9 +2489,13 @@ function baseAgentEnv(profile, job) {
|
|
|
2450
2489
|
* Both paths resolve to the same result contract.
|
|
2451
2490
|
*/
|
|
2452
2491
|
function runAgentJob(profile, job, opts = {}) {
|
|
2453
|
-
const { timeoutMs, envelope, sandbox = 'none', image, runId, secretEnv = {}, passThroughSecretNames = [], cwd, extraEnv = {}, profileEnv = {}, resultFile, stream = false, streamPrefix = '', onStreamOut, onStreamErr } = opts;
|
|
2492
|
+
const { timeoutMs, envelope, sandbox = 'none', image, runId, secretEnv = {}, passThroughSecretNames = [], cwd, extraEnv = {}, profileEnv = {}, resultFile, stream = false, streamPrefix = '', onStreamOut, onStreamErr, args: commandArgs } = opts;
|
|
2454
2493
|
const payload = JSON.stringify(buildAgentPayload(profile, job, envelope));
|
|
2455
2494
|
const agentEnv = baseAgentEnv(profile, job);
|
|
2495
|
+
// The harness command line: the profile command plus its structured switches
|
|
2496
|
+
// (persisted `--arg`s, possibly extended at work time via opts.args), each
|
|
2497
|
+
// shell-quoted. Spawned through a shell so `command` still resolves on PATH.
|
|
2498
|
+
const commandLine = buildAgentCommandLine(profile.command, commandArgs ?? profile.args);
|
|
2456
2499
|
// Static, non-secret env for the harness: the worker/profile's env (e.g. a
|
|
2457
2500
|
// harness's permission toggles) plus the per-job envelope's setup.env
|
|
2458
2501
|
// (job-specific tuning wins over the profile default). Reserved AGENT_* and
|
|
@@ -2461,9 +2504,16 @@ function runAgentJob(profile, job, opts = {}) {
|
|
|
2461
2504
|
|
|
2462
2505
|
if (!CONTAINER_SANDBOXES.has(sandbox)) {
|
|
2463
2506
|
// Host: hand the agent the result file by its real path.
|
|
2507
|
+
// Defense in depth: --arg tokens are POSIX single-quoted, which cmd.exe on
|
|
2508
|
+
// a Windows host does not honour, so args would be mis-parsed under the
|
|
2509
|
+
// shell:true spawn. workAgent already rejects this at startup, but guard the
|
|
2510
|
+
// spawn site too so the invariant holds for any direct caller of runAgentJob.
|
|
2511
|
+
if (commandLine !== profile.command && process.platform === 'win32') {
|
|
2512
|
+
return Promise.resolve({ ok: false, exitCode: null, stdout: '', stderr: '', error: 'command-line args (--arg) are not supported for host execution on Windows; use a container sandbox or bake switches into the command', truncated: false, stderrTruncated: false });
|
|
2513
|
+
}
|
|
2464
2514
|
const resultEnv = resultFile ? { [AGENT_RESULT_FILE_ENV]: resultFile } : {};
|
|
2465
2515
|
return spawnCaptureOneShot({
|
|
2466
|
-
command:
|
|
2516
|
+
command: commandLine,
|
|
2467
2517
|
shell: true,
|
|
2468
2518
|
// Own process group so the timeout handler can kill the whole tree.
|
|
2469
2519
|
detached: process.platform !== 'win32',
|
|
@@ -2516,7 +2566,7 @@ function runAgentJob(profile, job, opts = {}) {
|
|
|
2516
2566
|
...mountArgs,
|
|
2517
2567
|
...envArgs,
|
|
2518
2568
|
image,
|
|
2519
|
-
'sh', '-c',
|
|
2569
|
+
'sh', '-c', commandLine,
|
|
2520
2570
|
];
|
|
2521
2571
|
|
|
2522
2572
|
return spawnCaptureOneShot({
|
|
@@ -2618,6 +2668,11 @@ async function workAgent(req, flags) {
|
|
|
2618
2668
|
}
|
|
2619
2669
|
const profileEnv = { ...profile.env, ...workEnv };
|
|
2620
2670
|
|
|
2671
|
+
// Structured command-line switches: the profile's persisted `--arg`s, extended
|
|
2672
|
+
// by any work-time `--arg` (appended). Lets an operator add switches (e.g.
|
|
2673
|
+
// `--allow-all`) at dispatch time without re-hiring.
|
|
2674
|
+
const effectiveArgs = [...profile.args, ...normalizeArgList(flags?.arg)];
|
|
2675
|
+
|
|
2621
2676
|
const intFlag = (v, dflt) => {
|
|
2622
2677
|
const n = Number.parseInt(String(v ?? ''), 10);
|
|
2623
2678
|
return Number.isFinite(n) && n > 0 ? n : dflt;
|
|
@@ -2638,6 +2693,17 @@ async function workAgent(req, flags) {
|
|
|
2638
2693
|
logger.error(`--sandbox ${sandbox} requires an --image (or hire the profile with --image).`);
|
|
2639
2694
|
process.exit(1);
|
|
2640
2695
|
}
|
|
2696
|
+
// Structured --arg tokens are POSIX single-quoted (shQuote) for the harness
|
|
2697
|
+
// shell. On the host path that shell is the platform default — cmd.exe on
|
|
2698
|
+
// Windows, which does not honour single quotes — so the quoting would leak
|
|
2699
|
+
// literal quote characters and mis-parse the switches. The container path
|
|
2700
|
+
// always targets the image's `sh`, so it stays correct regardless of host OS.
|
|
2701
|
+
// Fail fast with actionable guidance rather than silently corrupting argv.
|
|
2702
|
+
if (!isContainer && effectiveArgs.length > 0 && process.platform === 'win32') {
|
|
2703
|
+
logger.error('--arg is not supported for host execution on Windows (cmd.exe does not honour POSIX quoting).');
|
|
2704
|
+
logger.error('Use a container sandbox (--sandbox docker|podman --image <ref>) or bake the switches into --command.');
|
|
2705
|
+
process.exit(1);
|
|
2706
|
+
}
|
|
2641
2707
|
|
|
2642
2708
|
const secretResolver = makeSecretResolver(flags?.['secret-resolver']);
|
|
2643
2709
|
if (!secretResolver) {
|
|
@@ -2713,7 +2779,7 @@ async function workAgent(req, flags) {
|
|
|
2713
2779
|
const jobTypes = [...new Set([...matrix, ...extraJobTypes])];
|
|
2714
2780
|
const camunda = globalThis.c8ctl.createClient();
|
|
2715
2781
|
|
|
2716
|
-
logger.info(`Putting "${name}" [${profile.rank}] to work → ${profile.command}`);
|
|
2782
|
+
logger.info(`Putting "${name}" [${profile.rank}] to work → ${buildAgentCommandLine(profile.command, effectiveArgs)}`);
|
|
2717
2783
|
logger.info(` model: ${profile.model || '(none)'}; capabilities: ${profile.capabilities.join(', ') || '(none)'}`);
|
|
2718
2784
|
logger.info(` sandbox: ${sandbox}${isContainer ? ` (image ${image})` : ''}`);
|
|
2719
2785
|
const profileEnvKeys = Object.keys(profileEnv);
|
|
@@ -2730,7 +2796,7 @@ async function workAgent(req, flags) {
|
|
|
2730
2796
|
maxParallelJobs,
|
|
2731
2797
|
jobTimeoutMs,
|
|
2732
2798
|
jobHandler: async (job) => {
|
|
2733
|
-
logger.info(`[${jobType}] job ${job.jobKey} (instance ${job.processInstanceKey ?? '-'}) → ${profile.command}`);
|
|
2799
|
+
logger.info(`[${jobType}] job ${job.jobKey} (instance ${job.processInstanceKey ?? '-'}) → ${buildAgentCommandLine(profile.command, effectiveArgs)}`);
|
|
2734
2800
|
|
|
2735
2801
|
// Disk-budget admission shed: if the engine data root is below the free
|
|
2736
2802
|
// floor, don't start a container — fail (retryable) so work sheds until
|
|
@@ -2824,6 +2890,7 @@ async function workAgent(req, flags) {
|
|
|
2824
2890
|
resultFile,
|
|
2825
2891
|
stream,
|
|
2826
2892
|
streamPrefix: `[${jobType} ${job.jobKey}] `,
|
|
2893
|
+
args: effectiveArgs,
|
|
2827
2894
|
// Route the --stream tee through c8ctl's output-mode-aware logger so
|
|
2828
2895
|
// spying never corrupts a structured/JSON output mode.
|
|
2829
2896
|
onStreamOut: stream ? (line) => logger.info(line) : undefined,
|
|
@@ -4273,6 +4340,9 @@ export {
|
|
|
4273
4340
|
sanitizeResultVars,
|
|
4274
4341
|
parseEnvPairs,
|
|
4275
4342
|
normalizeEnvMap,
|
|
4343
|
+
normalizeArgList,
|
|
4344
|
+
shQuote,
|
|
4345
|
+
buildAgentCommandLine,
|
|
4276
4346
|
reapAgentContainers,
|
|
4277
4347
|
diskBudgetOk,
|
|
4278
4348
|
containerEngineAvailable,
|
|
@@ -4327,6 +4397,7 @@ export const metadata = {
|
|
|
4327
4397
|
{ command: 'c8ctl nano update --check', description: 'Check whether a newer nano release is available' },
|
|
4328
4398
|
{ command: 'c8ctl nano hire', description: 'Interactively create a CLI agent worker profile (name, rank, command, model, capabilities)' },
|
|
4329
4399
|
{ command: 'c8ctl nano hire --name reviewer --rank senior --command copilot --model gpt-5 --capabilities code-review,testing', description: 'Create a profile non-interactively' },
|
|
4400
|
+
{ command: 'c8ctl nano hire --name coder --rank senior --command copilot --arg --allow-all', description: 'Hire copilot with a command-line switch (copilot --allow-all)' },
|
|
4330
4401
|
{ command: 'c8ctl nano hire --name coder --rank senior --command copilot --env COPILOT_ENABLE_ALL_TOOLS=1', description: 'Persist a harness startup env var (e.g. permissions) on the profile' },
|
|
4331
4402
|
{ command: 'c8ctl nano hire --list', description: 'List hired agent profiles' },
|
|
4332
4403
|
{ command: 'c8ctl nano hire --name coder --rank senior --command "agent-harness" --sandbox docker --image ghcr.io/acme/agent:1', description: 'Create a profile that runs each job in a throwaway Docker container' },
|
|
@@ -4375,6 +4446,7 @@ export const commands = {
|
|
|
4375
4446
|
name: { type: 'string', description: 'hire/work: agent profile name (alt to positional arg)' },
|
|
4376
4447
|
rank: { type: 'string', description: 'hire: agent rank (principal|senior|junior|decider)' },
|
|
4377
4448
|
command: { type: 'string', description: 'hire: CLI command that runs the agent harness (e.g. copilot, claude, pi)' },
|
|
4449
|
+
arg: { type: 'string', multiple: true, description: 'hire/work: command-line switch/arg appended to the harness command (repeatable), e.g. --arg --allow-all. Persisted on hire; work appends more.' },
|
|
4378
4450
|
model: { type: 'string', description: 'hire: model name passed to the harness (AGENT_MODEL)' },
|
|
4379
4451
|
capabilities: { type: 'string', description: 'hire: comma-separated capability list' },
|
|
4380
4452
|
sandbox: { type: 'string', description: 'hire/work: execution sandbox none|docker|podman (default none). Containers isolate each job.' },
|
|
@@ -4533,8 +4605,8 @@ function printUsage() {
|
|
|
4533
4605
|
console.log(' c8ctl nano set <bin|model-dir> <path>');
|
|
4534
4606
|
console.log(' c8ctl nano config');
|
|
4535
4607
|
console.log(' c8ctl nano update [--check]');
|
|
4536
|
-
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]');
|
|
4537
|
-
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]');
|
|
4608
|
+
console.log(' c8ctl nano hire [--name <n>] [--rank <r>] [--command <c>] [--arg <switch> ...] [--model <m>] [--capabilities <a,b>] [--sandbox none|docker|podman] [--image <ref>] [--env NAME=VALUE ...] [--list]');
|
|
4609
|
+
console.log(' c8ctl nano work <profileName> [--arg <switch> ...] [--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]');
|
|
4538
4610
|
console.log('');
|
|
4539
4611
|
console.log('Subcommands:');
|
|
4540
4612
|
console.log(' start Spawn an N-node local cluster wired to talk to each other on localhost');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.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.18.0",
|
|
53
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.18.0",
|
|
54
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.18.0",
|
|
55
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.18.0",
|
|
56
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.18.0",
|
|
57
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.18.0",
|
|
58
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.18.0"
|
|
59
59
|
}
|
|
60
60
|
}
|