c8ctl-plugin-nano 1.16.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.
Files changed (3) hide show
  1. package/README.md +21 -0
  2. package/c8ctl-plugin.js +124 -15
  3. 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
@@ -461,6 +461,19 @@ function webConsoleUrl(baseUrl) {
461
461
  return `${baseUrl}/console`;
462
462
  }
463
463
 
464
+ /**
465
+ * Human label for the console link, keyed on the runtime console profile.
466
+ * The default `studio` profile IS the full web IDE, so name it as such — users
467
+ * kept missing that Nano ships a browser IDE when it was labelled "Web console".
468
+ * `observe` is the read-only console. `off` serves no console, so the label is
469
+ * meaningless there; callers must guard `profile !== 'off'` before rendering it,
470
+ * and this helper returns null for `off` to enforce that contract.
471
+ */
472
+ function consoleLinkLabel(profile) {
473
+ if (profile === 'off') return null;
474
+ return profile === 'studio' ? 'Web IDE (Studio)' : `Web console (${profile})`;
475
+ }
476
+
464
477
  /** Probe a node's always-on GET /v2/topology endpoint for reachability. */
465
478
  async function probeHealthy(url) {
466
479
  const controller = new AbortController();
@@ -788,6 +801,7 @@ async function startCluster(req) {
788
801
  inMemory,
789
802
  historyMax: historyMax ?? null,
790
803
  basePort,
804
+ consoleProfile,
791
805
  nodes,
792
806
  };
793
807
  writeState(state);
@@ -834,15 +848,22 @@ async function printSummary(state) {
834
848
  // The landing page (and the /docs user guide + /console) only exist in builds
835
849
  // compiled with the web console; probe so we advertise the right entry point.
836
850
  const hasConsole = await probePath(entry.url, '/');
837
- if (hasConsole) {
838
- console.log(` Start here ${entry.url}/ (landing: console, user guide & API docs)`);
851
+ const profile = state.consoleProfile ?? 'studio';
852
+ // Lead with the web IDE it is Nano's headline surface and the thing users
853
+ // most often did not realise was there. Only advertise it when this build
854
+ // actually serves a console and the profile is not 'off'.
855
+ if (hasConsole && profile !== 'off') {
856
+ console.log(` ${consoleLinkLabel(profile)} ${webConsoleUrl(entry.url)}`);
857
+ const surface = profile === 'studio' ? 'the Nano web IDE' : 'the Nano web console';
858
+ console.log(` ^ open this in your browser: ${surface}`);
859
+ console.log('');
839
860
  }
840
- console.log(` REST API ${entry.url}/v2`);
841
- console.log(` Topology ${entry.url}/v2/topology`);
842
861
  if (hasConsole) {
843
- console.log(` Web console ${webConsoleUrl(entry.url)}`);
862
+ console.log(` Landing ${entry.url}/ (console, user guide & API docs)`);
844
863
  console.log(` User guide ${entry.url}/docs`);
845
864
  }
865
+ console.log(` REST API ${entry.url}/v2`);
866
+ console.log(` Topology ${entry.url}/v2/topology`);
846
867
  if (state.workspaceDir) {
847
868
  console.log(` Workspace ${state.workspaceDir} (models/, workers/)`);
848
869
  }
@@ -1052,6 +1073,21 @@ async function statusCluster(req) {
1052
1073
  }
1053
1074
  console.log('');
1054
1075
 
1076
+ // Surface the web IDE again here so it stays discoverable long after the
1077
+ // initial `start` scrolled off — probe a healthy node so we only advertise a
1078
+ // console that is actually served (API-only builds 404 `/`).
1079
+ const profile = state.consoleProfile ?? 'studio';
1080
+ if (overall !== 'stopped' && profile !== 'off') {
1081
+ // Only probe a HEALTHY node: it already answered /v2/topology this run, so
1082
+ // GET / returns fast. Falling back to a merely-alive (unreachable) node
1083
+ // would add a full probe timeout to every `nano status` in a degraded state.
1084
+ const consoleNode = checks.find((c) => c.healthy);
1085
+ if (consoleNode && (await probePath(consoleNode.url, '/'))) {
1086
+ console.log(` ${consoleLinkLabel(profile)} ${webConsoleUrl(consoleNode.url)}`);
1087
+ console.log('');
1088
+ }
1089
+ }
1090
+
1055
1091
  // Enrich with the live topology when reachable — the authoritative view of
1056
1092
  // partition leadership across the cluster.
1057
1093
  if (topo) {
@@ -1380,6 +1416,39 @@ function parseEnvPairs(input) {
1380
1416
  return { env, errors };
1381
1417
  }
1382
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
+
1383
1452
  // A worker job-type token: rank/capability tokens use `:` (rank↔cap) and `+`
1384
1453
  // (combined caps) as delimiters, and code-first `@nanobpm/workflow` job types
1385
1454
  // are `<flowId>:<taskName>` or an explicit override. The first character must be
@@ -1477,6 +1546,7 @@ function normalizeStoredProfile(name, profile) {
1477
1546
  name,
1478
1547
  rank,
1479
1548
  command,
1549
+ args: normalizeArgList(profile.args),
1480
1550
  model: typeof profile.model === 'string' ? profile.model.trim() : '',
1481
1551
  capabilities: normalizeCapabilities(profile.capabilities),
1482
1552
  sandbox,
@@ -1505,7 +1575,7 @@ async function hireWorker(req, flags) {
1505
1575
  logger.info('Hired agent profiles:');
1506
1576
  for (const name of names.sort()) {
1507
1577
  const p = hires[name];
1508
- 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(', ') || '-'})`);
1509
1579
  }
1510
1580
  logger.info('');
1511
1581
  logger.info('Put one to work with: c8ctl nano work <name>');
@@ -1521,11 +1591,14 @@ async function hireWorker(req, flags) {
1521
1591
  let capabilities = flags?.capabilities !== undefined ? flags.capabilities : undefined;
1522
1592
  let sandbox = flags?.sandbox !== undefined ? String(flags.sandbox).trim().toLowerCase() : undefined;
1523
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);
1524
1597
  const envFromFlags = flags?.env !== undefined;
1525
1598
  const { env: profileEnv, errors: envErrors } = parseEnvPairs(flags?.env);
1526
1599
  if (envErrors.length > 0) {
1527
1600
  logger.error(envErrors.join('; '));
1528
- logger.info('Example: c8ctl nano hire --name coder --rank senior --command copilot --env COPILOT_ENABLE_ALL_TOOLS=1 --env FOO=bar');
1601
+ logger.info('Example: c8ctl nano hire --name coder --rank senior --command copilot --arg --allow-all --env COPILOT_ENABLE_ALL_TOOLS=1');
1529
1602
  process.exit(1);
1530
1603
  }
1531
1604
 
@@ -1623,6 +1696,7 @@ async function hireWorker(req, flags) {
1623
1696
  name,
1624
1697
  rank,
1625
1698
  command,
1699
+ args: commandArgs,
1626
1700
  model: model || '',
1627
1701
  capabilities: normalizeCapabilities(capabilities),
1628
1702
  sandbox,
@@ -1633,9 +1707,10 @@ async function hireWorker(req, flags) {
1633
1707
  writeHire(profile);
1634
1708
 
1635
1709
  const matrix = jobTypeMatrix(profile.rank, profile.capabilities);
1636
- logger.info(`${existed ? 'Updated' : 'Hired'} "${name}" [${profile.rank}] → ${profile.command}`);
1710
+ logger.info(`${existed ? 'Updated' : 'Hired'} "${name}" [${profile.rank}] → ${buildAgentCommandLine(profile.command, profile.args)}`);
1637
1711
  logger.info(` model: ${profile.model || '(none)'}`);
1638
1712
  logger.info(` capabilities: ${profile.capabilities.join(', ') || '(none)'}`);
1713
+ if (profile.args.length > 0) logger.info(` args: ${profile.args.map(shQuote).join(' ')}`);
1639
1714
  logger.info(` sandbox: ${profile.sandbox}${CONTAINER_SANDBOXES.has(profile.sandbox) ? ` (image ${profile.image})` : ''}`);
1640
1715
  const envKeys = Object.keys(profile.env);
1641
1716
  if (envKeys.length > 0) logger.info(` env: ${envKeys.join(', ')}`);
@@ -2414,9 +2489,13 @@ function baseAgentEnv(profile, job) {
2414
2489
  * Both paths resolve to the same result contract.
2415
2490
  */
2416
2491
  function runAgentJob(profile, job, opts = {}) {
2417
- 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;
2418
2493
  const payload = JSON.stringify(buildAgentPayload(profile, job, envelope));
2419
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);
2420
2499
  // Static, non-secret env for the harness: the worker/profile's env (e.g. a
2421
2500
  // harness's permission toggles) plus the per-job envelope's setup.env
2422
2501
  // (job-specific tuning wins over the profile default). Reserved AGENT_* and
@@ -2425,9 +2504,16 @@ function runAgentJob(profile, job, opts = {}) {
2425
2504
 
2426
2505
  if (!CONTAINER_SANDBOXES.has(sandbox)) {
2427
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
+ }
2428
2514
  const resultEnv = resultFile ? { [AGENT_RESULT_FILE_ENV]: resultFile } : {};
2429
2515
  return spawnCaptureOneShot({
2430
- command: profile.command,
2516
+ command: commandLine,
2431
2517
  shell: true,
2432
2518
  // Own process group so the timeout handler can kill the whole tree.
2433
2519
  detached: process.platform !== 'win32',
@@ -2480,7 +2566,7 @@ function runAgentJob(profile, job, opts = {}) {
2480
2566
  ...mountArgs,
2481
2567
  ...envArgs,
2482
2568
  image,
2483
- 'sh', '-c', profile.command,
2569
+ 'sh', '-c', commandLine,
2484
2570
  ];
2485
2571
 
2486
2572
  return spawnCaptureOneShot({
@@ -2582,6 +2668,11 @@ async function workAgent(req, flags) {
2582
2668
  }
2583
2669
  const profileEnv = { ...profile.env, ...workEnv };
2584
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
+
2585
2676
  const intFlag = (v, dflt) => {
2586
2677
  const n = Number.parseInt(String(v ?? ''), 10);
2587
2678
  return Number.isFinite(n) && n > 0 ? n : dflt;
@@ -2602,6 +2693,17 @@ async function workAgent(req, flags) {
2602
2693
  logger.error(`--sandbox ${sandbox} requires an --image (or hire the profile with --image).`);
2603
2694
  process.exit(1);
2604
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
+ }
2605
2707
 
2606
2708
  const secretResolver = makeSecretResolver(flags?.['secret-resolver']);
2607
2709
  if (!secretResolver) {
@@ -2677,7 +2779,7 @@ async function workAgent(req, flags) {
2677
2779
  const jobTypes = [...new Set([...matrix, ...extraJobTypes])];
2678
2780
  const camunda = globalThis.c8ctl.createClient();
2679
2781
 
2680
- logger.info(`Putting "${name}" [${profile.rank}] to work → ${profile.command}`);
2782
+ logger.info(`Putting "${name}" [${profile.rank}] to work → ${buildAgentCommandLine(profile.command, effectiveArgs)}`);
2681
2783
  logger.info(` model: ${profile.model || '(none)'}; capabilities: ${profile.capabilities.join(', ') || '(none)'}`);
2682
2784
  logger.info(` sandbox: ${sandbox}${isContainer ? ` (image ${image})` : ''}`);
2683
2785
  const profileEnvKeys = Object.keys(profileEnv);
@@ -2694,7 +2796,7 @@ async function workAgent(req, flags) {
2694
2796
  maxParallelJobs,
2695
2797
  jobTimeoutMs,
2696
2798
  jobHandler: async (job) => {
2697
- 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)}`);
2698
2800
 
2699
2801
  // Disk-budget admission shed: if the engine data root is below the free
2700
2802
  // floor, don't start a container — fail (retryable) so work sheds until
@@ -2788,6 +2890,7 @@ async function workAgent(req, flags) {
2788
2890
  resultFile,
2789
2891
  stream,
2790
2892
  streamPrefix: `[${jobType} ${job.jobKey}] `,
2893
+ args: effectiveArgs,
2791
2894
  // Route the --stream tee through c8ctl's output-mode-aware logger so
2792
2895
  // spying never corrupts a structured/JSON output mode.
2793
2896
  onStreamOut: stream ? (line) => logger.info(line) : undefined,
@@ -4217,6 +4320,7 @@ export { resolveBinary, findBinary, launcherEnvMarkers };
4217
4320
  export { buildNpmInvocation };
4218
4321
  export {
4219
4322
  webConsoleUrl,
4323
+ consoleLinkLabel,
4220
4324
  hireWorker,
4221
4325
  };
4222
4326
  export {
@@ -4236,6 +4340,9 @@ export {
4236
4340
  sanitizeResultVars,
4237
4341
  parseEnvPairs,
4238
4342
  normalizeEnvMap,
4343
+ normalizeArgList,
4344
+ shQuote,
4345
+ buildAgentCommandLine,
4239
4346
  reapAgentContainers,
4240
4347
  diskBudgetOk,
4241
4348
  containerEngineAvailable,
@@ -4290,6 +4397,7 @@ export const metadata = {
4290
4397
  { command: 'c8ctl nano update --check', description: 'Check whether a newer nano release is available' },
4291
4398
  { command: 'c8ctl nano hire', description: 'Interactively create a CLI agent worker profile (name, rank, command, model, capabilities)' },
4292
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)' },
4293
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' },
4294
4402
  { command: 'c8ctl nano hire --list', description: 'List hired agent profiles' },
4295
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' },
@@ -4338,6 +4446,7 @@ export const commands = {
4338
4446
  name: { type: 'string', description: 'hire/work: agent profile name (alt to positional arg)' },
4339
4447
  rank: { type: 'string', description: 'hire: agent rank (principal|senior|junior|decider)' },
4340
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.' },
4341
4450
  model: { type: 'string', description: 'hire: model name passed to the harness (AGENT_MODEL)' },
4342
4451
  capabilities: { type: 'string', description: 'hire: comma-separated capability list' },
4343
4452
  sandbox: { type: 'string', description: 'hire/work: execution sandbox none|docker|podman (default none). Containers isolate each job.' },
@@ -4496,8 +4605,8 @@ function printUsage() {
4496
4605
  console.log(' c8ctl nano set <bin|model-dir> <path>');
4497
4606
  console.log(' c8ctl nano config');
4498
4607
  console.log(' c8ctl nano update [--check]');
4499
- 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]');
4500
- 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]');
4501
4610
  console.log('');
4502
4611
  console.log('Subcommands:');
4503
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.16.0",
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.16.0",
53
- "@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.16.0",
54
- "@nanobpm/c8ctl-plugin-nano-linux-x64": "1.16.0",
55
- "@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.16.0",
56
- "@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.16.0",
57
- "@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.16.0",
58
- "@nanobpm/c8ctl-plugin-nano-win32-x64": "1.16.0"
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
  }