c8ctl-plugin-nano 1.31.0 → 1.32.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 +10 -1
- package/c8ctl-plugin.js +209 -27
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -696,7 +696,7 @@ release onto a machine that already has nano installed:
|
|
|
696
696
|
|
|
697
697
|
```bash
|
|
698
698
|
c8ctl nano update # check npm for a newer release and install it
|
|
699
|
-
c8ctl nano update --check #
|
|
699
|
+
c8ctl nano update --check # report whether an update is available (no install)
|
|
700
700
|
```
|
|
701
701
|
|
|
702
702
|
`update` compares the installed plugin version against the latest published on
|
|
@@ -706,6 +706,15 @@ with it. It only ever drives npm — it never touches the private upstream sourc
|
|
|
706
706
|
so it works for any npm-installed user. After updating, restart any running
|
|
707
707
|
cluster (`c8ctl nano restart`) so it picks up the new binary.
|
|
708
708
|
|
|
709
|
+
Whenever an update is available, `update` (and `update --check`) also prints a
|
|
710
|
+
**changelog of what changed since the installed release** — the per-version
|
|
711
|
+
"Features" / "Bug Fixes" notes pulled from the plugin's public
|
|
712
|
+
[GitHub Releases](https://github.com/jwulf/c8ctl-plugin-nano/releases) (where
|
|
713
|
+
semantic-release records them). This lookup is best-effort and non-blocking: if
|
|
714
|
+
GitHub is unreachable or rate-limited it degrades to a link to the releases page
|
|
715
|
+
and the update proceeds normally. Set `GH_TOKEN` (or `GITHUB_TOKEN`) to raise the
|
|
716
|
+
unauthenticated API rate limit.
|
|
717
|
+
|
|
709
718
|
If the plugin is running from a local checkout rather than a global npm install,
|
|
710
719
|
`update` prints the manual command instead of reinstalling in place.
|
|
711
720
|
|
package/c8ctl-plugin.js
CHANGED
|
@@ -5789,6 +5789,183 @@ function compareSemver(a, b) {
|
|
|
5789
5789
|
return 0;
|
|
5790
5790
|
}
|
|
5791
5791
|
|
|
5792
|
+
// ---------------------------------------------------------------------------
|
|
5793
|
+
// Update changelog. `update --check` (and the pre-pull path of a real update)
|
|
5794
|
+
// shows what changed between the installed release and latest. The authoritative
|
|
5795
|
+
// source is this plugin's PUBLIC GitHub Releases — semantic-release records the
|
|
5796
|
+
// generated notes there (@semantic-release/github). The committed CHANGELOG.md
|
|
5797
|
+
// is deliberately NOT maintained (the release config dropped the changelog/git
|
|
5798
|
+
// plugins so it never pushes to the protected `main`) and isn't even in the npm
|
|
5799
|
+
// `files`, so it can't be the source. Every lookup here is best-effort and
|
|
5800
|
+
// non-blocking: any failure (offline, rate-limited, private) degrades to a link,
|
|
5801
|
+
// never to a failed `update`.
|
|
5802
|
+
// ---------------------------------------------------------------------------
|
|
5803
|
+
|
|
5804
|
+
/** `owner/repo` parsed from the plugin package's `repository` field (null if absent). */
|
|
5805
|
+
function githubRepoSlug() {
|
|
5806
|
+
try {
|
|
5807
|
+
const pkg = JSON.parse(readFileSync(join(pluginDir, 'package.json'), 'utf8'));
|
|
5808
|
+
const raw = pkg?.repository?.url ?? (typeof pkg?.repository === 'string' ? pkg.repository : '');
|
|
5809
|
+
const m = String(raw).match(/github\.com[/:]([^/\s]+\/[^/\s]+?)(?:\.git)?(?:[/#?].*)?$/i);
|
|
5810
|
+
return m ? m[1] : null;
|
|
5811
|
+
} catch {
|
|
5812
|
+
return null;
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
|
|
5816
|
+
/**
|
|
5817
|
+
* Keep only the releases strictly newer than `currentVersion` and no newer than
|
|
5818
|
+
* `latestVersion` (when known), newest-first. Pure over its `releases` input (an
|
|
5819
|
+
* array of GitHub release objects) so it is unit-testable without a network call.
|
|
5820
|
+
*/
|
|
5821
|
+
function filterReleasesSince(releases, currentVersion, latestVersion) {
|
|
5822
|
+
if (!Array.isArray(releases)) return [];
|
|
5823
|
+
const items = [];
|
|
5824
|
+
for (const r of releases) {
|
|
5825
|
+
if (!r || r.draft || r.prerelease) continue;
|
|
5826
|
+
const tag = r.tag_name || r.name || '';
|
|
5827
|
+
const norm = String(tag).replace(/^v/, '');
|
|
5828
|
+
// Require a plain vX.Y.Z tag: a prerelease/build suffix (e.g. -rc.1, +meta)
|
|
5829
|
+
// must exclude the release rather than be normalised away into the window.
|
|
5830
|
+
if (!/^\d+\.\d+\.\d+$/.test(norm)) continue;
|
|
5831
|
+
const ver = norm;
|
|
5832
|
+
if (!currentVersion || compareSemver(ver, currentVersion) <= 0) continue;
|
|
5833
|
+
if (latestVersion && compareSemver(ver, latestVersion) > 0) continue;
|
|
5834
|
+
items.push({ version: ver, tag, body: r.body || '', url: r.html_url || '' });
|
|
5835
|
+
}
|
|
5836
|
+
items.sort((a, b) => compareSemver(b.version, a.version));
|
|
5837
|
+
return items;
|
|
5838
|
+
}
|
|
5839
|
+
|
|
5840
|
+
/**
|
|
5841
|
+
* Render one semantic-release release body to tight terminal lines: drop the
|
|
5842
|
+
* redundant `# [x.y.z](…)` header, turn `### Features` into a `Features:` label,
|
|
5843
|
+
* flatten `* **scope:** subject ([abc](url))` bullets to `• scope: subject`
|
|
5844
|
+
* (stripping any `([label](url))` commit/PR link groups and inlining any
|
|
5845
|
+
* remaining `[text](url)` as its text). Returns an array of already-indented lines.
|
|
5846
|
+
*/
|
|
5847
|
+
function renderReleaseBody(body) {
|
|
5848
|
+
const out = [];
|
|
5849
|
+
for (const line of String(body).split(/\r?\n/)) {
|
|
5850
|
+
if (/^#{1,2}\s+\[?\d+\.\d+\.\d+/.test(line)) continue; // redundant version header
|
|
5851
|
+
const heading = line.match(/^#{2,3}\s+(.*\S)\s*$/);
|
|
5852
|
+
if (heading) {
|
|
5853
|
+
out.push(` ${heading[1]}:`);
|
|
5854
|
+
continue;
|
|
5855
|
+
}
|
|
5856
|
+
const bullet = line.match(/^\s*[*-]\s+(.*)$/);
|
|
5857
|
+
if (bullet) {
|
|
5858
|
+
let text = bullet[1]
|
|
5859
|
+
.replace(/\s*\(\[[^\]]*\]\([^)]*\)\)/g, '') // ([label](url)) commit/PR link groups
|
|
5860
|
+
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1') // inline [text](url) -> text
|
|
5861
|
+
.replace(/\*\*(.*?)\*\*/g, '$1') // **scope** -> scope
|
|
5862
|
+
.replace(/\s+/g, ' ')
|
|
5863
|
+
.trim();
|
|
5864
|
+
if (text) out.push(` \u2022 ${text}`);
|
|
5865
|
+
}
|
|
5866
|
+
}
|
|
5867
|
+
return out;
|
|
5868
|
+
}
|
|
5869
|
+
|
|
5870
|
+
/** Cap on release pages walked, so a repo with a huge history can never hang the walk. */
|
|
5871
|
+
const RELEASE_PAGE_LIMIT = 20;
|
|
5872
|
+
|
|
5873
|
+
/**
|
|
5874
|
+
* True once a page contains a published (non-draft/non-prerelease) vX.Y.Z release
|
|
5875
|
+
* at or below `current`. Because the releases API returns newest-first, everything
|
|
5876
|
+
* after that point is older than the installed version, so the walk can stop.
|
|
5877
|
+
*/
|
|
5878
|
+
function reachedInstalledRelease(page, current) {
|
|
5879
|
+
if (!current || !Array.isArray(page)) return false;
|
|
5880
|
+
for (const r of page) {
|
|
5881
|
+
if (!r || r.draft || r.prerelease) continue;
|
|
5882
|
+
const norm = String(r.tag_name || r.name || '').replace(/^v/, '');
|
|
5883
|
+
if (!/^\d+\.\d+\.\d+$/.test(norm)) continue;
|
|
5884
|
+
if (compareSemver(norm, current) <= 0) return true;
|
|
5885
|
+
}
|
|
5886
|
+
return false;
|
|
5887
|
+
}
|
|
5888
|
+
|
|
5889
|
+
/**
|
|
5890
|
+
* Fetch this plugin's GitHub releases newer than `current` (best-effort; null on
|
|
5891
|
+
* any failure). Paginates newest-first, stopping as soon as it reaches the
|
|
5892
|
+
* installed release (or a bounded page cap), so the window stays accurate even
|
|
5893
|
+
* when the installed version is far behind and there are >100 releases since.
|
|
5894
|
+
*/
|
|
5895
|
+
async function fetchReleaseNotesSince(slug, current, latest, timeoutMs = 5000) {
|
|
5896
|
+
if (!slug) return null;
|
|
5897
|
+
try {
|
|
5898
|
+
const ctrl = new AbortController();
|
|
5899
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
5900
|
+
const headers = {
|
|
5901
|
+
accept: 'application/vnd.github+json',
|
|
5902
|
+
'user-agent': 'c8ctl-plugin-nano',
|
|
5903
|
+
'x-github-api-version': '2022-11-28',
|
|
5904
|
+
};
|
|
5905
|
+
const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
|
|
5906
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
5907
|
+
try {
|
|
5908
|
+
const all = [];
|
|
5909
|
+
for (let page = 1; page <= RELEASE_PAGE_LIMIT; page++) {
|
|
5910
|
+
const res = await fetch(
|
|
5911
|
+
`https://api.github.com/repos/${slug}/releases?per_page=100&page=${page}`,
|
|
5912
|
+
{ headers, redirect: 'follow', signal: ctrl.signal },
|
|
5913
|
+
);
|
|
5914
|
+
if (!res.ok) return null;
|
|
5915
|
+
const arr = await res.json();
|
|
5916
|
+
if (!Array.isArray(arr) || arr.length === 0) break;
|
|
5917
|
+
all.push(...arr);
|
|
5918
|
+
// Newest-first: once we hit the installed release (or a short final
|
|
5919
|
+
// page), everything remaining is older than `current` — stop early.
|
|
5920
|
+
if (arr.length < 100 || reachedInstalledRelease(arr, current)) break;
|
|
5921
|
+
}
|
|
5922
|
+
return filterReleasesSince(all, current, latest);
|
|
5923
|
+
} finally {
|
|
5924
|
+
clearTimeout(timer);
|
|
5925
|
+
}
|
|
5926
|
+
} catch {
|
|
5927
|
+
return null;
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
|
|
5931
|
+
/**
|
|
5932
|
+
* Print the changelog between the installed release and `latest`. Best-effort:
|
|
5933
|
+
* on any fetch failure it prints a single line pointing at the releases page and
|
|
5934
|
+
* returns, so it can never block or fail an `update`.
|
|
5935
|
+
*/
|
|
5936
|
+
async function printChangelogSince(_name, current, latest) {
|
|
5937
|
+
const logger = getLogger();
|
|
5938
|
+
const slug = githubRepoSlug();
|
|
5939
|
+
const releasesUrl = slug ? `https://github.com/${slug}/releases` : null;
|
|
5940
|
+
const releases = await fetchReleaseNotesSince(slug, current, latest);
|
|
5941
|
+
|
|
5942
|
+
if (releases === null) {
|
|
5943
|
+
if (releasesUrl) logger.info(`See what changed: ${releasesUrl}`);
|
|
5944
|
+
logger.info('');
|
|
5945
|
+
return;
|
|
5946
|
+
}
|
|
5947
|
+
if (releases.length === 0) {
|
|
5948
|
+
// Nothing resolved between the two (only a build-metadata bump, or a
|
|
5949
|
+
// degraded resolution: current is null / tags don't match vX.Y.Z). Point
|
|
5950
|
+
// at the releases page so the best-effort feature still leaves a trail.
|
|
5951
|
+
if (releasesUrl) logger.info(`See what changed: ${releasesUrl}`);
|
|
5952
|
+
logger.info('');
|
|
5953
|
+
return;
|
|
5954
|
+
}
|
|
5955
|
+
|
|
5956
|
+
logger.info(`What's changed since v${current ?? '?'}:`);
|
|
5957
|
+
logger.info('');
|
|
5958
|
+
for (const rel of releases) {
|
|
5959
|
+
logger.info(` v${rel.version}`);
|
|
5960
|
+
const lines = renderReleaseBody(rel.body);
|
|
5961
|
+
if (lines.length === 0) logger.info(' (no notes)');
|
|
5962
|
+
else for (const l of lines) logger.info(l);
|
|
5963
|
+
logger.info('');
|
|
5964
|
+
}
|
|
5965
|
+
if (releasesUrl) logger.info(`Full release notes: ${releasesUrl}`);
|
|
5966
|
+
logger.info('');
|
|
5967
|
+
}
|
|
5968
|
+
|
|
5792
5969
|
/**
|
|
5793
5970
|
* Resolve how npm must be spawned on the given platform. Spawning `npm`
|
|
5794
5971
|
* directly is not portable: on Windows npm is a `npm.cmd` shim, so bare
|
|
@@ -5921,7 +6098,8 @@ function manualUpdateCommand(name, info) {
|
|
|
5921
6098
|
return ` npm install -g ${name}@latest`;
|
|
5922
6099
|
}
|
|
5923
6100
|
|
|
5924
|
-
function updatePlugin(req) {
|
|
6101
|
+
async function updatePlugin(req) {
|
|
6102
|
+
const logger = getLogger();
|
|
5925
6103
|
const { name, version: current } = pluginPackage();
|
|
5926
6104
|
|
|
5927
6105
|
// The nano server binary ships with the plugin as its platform package
|
|
@@ -5942,44 +6120,47 @@ function updatePlugin(req) {
|
|
|
5942
6120
|
const info = pluginInstallInfo();
|
|
5943
6121
|
const manual = manualUpdateCommand(name, info);
|
|
5944
6122
|
|
|
5945
|
-
|
|
6123
|
+
logger.info(`Installed: ${name} v${current ?? '?'}${nanoNote}`);
|
|
5946
6124
|
|
|
5947
6125
|
let latest;
|
|
5948
6126
|
try {
|
|
5949
6127
|
latest = npmLatestVersion(name);
|
|
5950
6128
|
} catch (err) {
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
6129
|
+
logger.info(`Could not check npm for updates: ${err.message}`);
|
|
6130
|
+
logger.info('Pull the latest release manually with:');
|
|
6131
|
+
logger.info(manual);
|
|
5954
6132
|
return;
|
|
5955
6133
|
}
|
|
5956
|
-
|
|
5957
|
-
|
|
6134
|
+
logger.info(`Latest: ${name} v${latest} (npm)`);
|
|
6135
|
+
logger.info('');
|
|
5958
6136
|
|
|
5959
6137
|
if (current && compareSemver(current, latest) >= 0) {
|
|
5960
6138
|
if (!nanoBin) {
|
|
5961
6139
|
// Plugin is current but npm never fetched the matching server binary.
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
6140
|
+
logger.info('Plugin is current, but the nano server binary is not installed for this platform.');
|
|
6141
|
+
logger.info('Provision it by reinstalling the plugin so npm fetches the platform package:');
|
|
6142
|
+
logger.info(' c8ctl sync plugin');
|
|
5965
6143
|
return;
|
|
5966
6144
|
}
|
|
5967
|
-
|
|
6145
|
+
logger.info('Already on the latest release — nothing to do.');
|
|
5968
6146
|
return;
|
|
5969
6147
|
}
|
|
5970
6148
|
|
|
5971
|
-
|
|
6149
|
+
logger.info(`Update available: v${current ?? '?'} -> v${latest}`);
|
|
6150
|
+
logger.info('');
|
|
6151
|
+
|
|
6152
|
+
await printChangelogSince(name, current, latest);
|
|
5972
6153
|
|
|
5973
6154
|
if (req.check) {
|
|
5974
|
-
|
|
5975
|
-
|
|
6155
|
+
logger.info('Run `c8ctl nano update` to pull it (or manually):');
|
|
6156
|
+
logger.info(manual);
|
|
5976
6157
|
return;
|
|
5977
6158
|
}
|
|
5978
6159
|
|
|
5979
6160
|
if (info.mode === 'local') {
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
6161
|
+
logger.info('This plugin runs from a local checkout, so it cannot self-update in place.');
|
|
6162
|
+
logger.info('Update it with:');
|
|
6163
|
+
logger.info(manual);
|
|
5983
6164
|
return;
|
|
5984
6165
|
}
|
|
5985
6166
|
|
|
@@ -5988,8 +6169,8 @@ function updatePlugin(req) {
|
|
|
5988
6169
|
? ['install', `${name}@${latest}`, '--prefix', info.prefix]
|
|
5989
6170
|
: ['install', '-g', `${name}@${latest}`];
|
|
5990
6171
|
const where = info.mode === 'managed' ? 'the c8ctl plugin store' : "npm's global prefix";
|
|
5991
|
-
|
|
5992
|
-
|
|
6172
|
+
logger.info(`Pulling ${name}@${latest} into ${where}...`);
|
|
6173
|
+
logger.info('');
|
|
5993
6174
|
try {
|
|
5994
6175
|
runNpm(installArgs, { stdio: 'inherit' });
|
|
5995
6176
|
} catch (err) {
|
|
@@ -6006,14 +6187,14 @@ function updatePlugin(req) {
|
|
|
6006
6187
|
`npm ${installArgs.join(' ')} failed${code}. ${hint}`,
|
|
6007
6188
|
);
|
|
6008
6189
|
}
|
|
6009
|
-
|
|
6190
|
+
logger.info('');
|
|
6010
6191
|
if (info.mode === 'managed') {
|
|
6011
|
-
|
|
6192
|
+
logger.info(`Updated to v${latest}. The new plugin and bundled nano server load on your next c8ctl command.`);
|
|
6012
6193
|
} else {
|
|
6013
|
-
|
|
6194
|
+
logger.info(`Updated to v${latest}.`);
|
|
6014
6195
|
}
|
|
6015
|
-
|
|
6016
|
-
|
|
6196
|
+
logger.info('Restart any running cluster to use the new server binary:');
|
|
6197
|
+
logger.info(' c8ctl nano restart');
|
|
6017
6198
|
}
|
|
6018
6199
|
|
|
6019
6200
|
// ---------------------------------------------------------------------------
|
|
@@ -7061,6 +7242,7 @@ function parseProcessosRequest(args, flags) {
|
|
|
7061
7242
|
export { resolveBinary, findBinary, launcherEnvMarkers };
|
|
7062
7243
|
export { setConfig, unsetConfig, readConfig, writeConfig, getConfigFile, SETTING_ALIASES };
|
|
7063
7244
|
export { buildNpmInvocation };
|
|
7245
|
+
export { compareSemver, githubRepoSlug, filterReleasesSince, renderReleaseBody };
|
|
7064
7246
|
export {
|
|
7065
7247
|
webConsoleUrl,
|
|
7066
7248
|
consoleLinkLabel,
|
|
@@ -7190,7 +7372,7 @@ export const metadata = {
|
|
|
7190
7372
|
{ command: 'c8ctl nano set model-dir <path>', description: 'Set the workspace dir (models + workers)' },
|
|
7191
7373
|
{ command: 'c8ctl nano config', description: 'Show current plugin configuration and paths' },
|
|
7192
7374
|
{ command: 'c8ctl nano update', description: 'Pull the latest published nano release (re-installs via npm)' },
|
|
7193
|
-
{ command: 'c8ctl nano update --check', description: 'Check
|
|
7375
|
+
{ command: 'c8ctl nano update --check', description: 'Check for a newer nano release and show the changelog since the installed version (no install)' },
|
|
7194
7376
|
{ command: 'c8ctl nano hire', description: 'Interactively create a CLI agent worker profile (name, rank, command, model, capabilities)' },
|
|
7195
7377
|
{ command: 'c8ctl nano hire --name reviewer --rank senior --command copilot --model gpt-5 --capabilities code-review,testing', description: 'Create a profile non-interactively' },
|
|
7196
7378
|
{ command: 'c8ctl nano hire --name coder --rank senior --command copilot --arg --allow-all', description: 'Hire copilot with a command-line switch (copilot --allow-all)' },
|
|
@@ -7247,7 +7429,7 @@ export const commands = {
|
|
|
7247
7429
|
purge: { type: 'boolean', description: 'stop/restart: also delete per-node engine data' },
|
|
7248
7430
|
force: { type: 'boolean', description: 'start: stop any existing cluster first' },
|
|
7249
7431
|
workspace: { type: 'boolean', description: 'clean: also delete the workspace (models + workers)' },
|
|
7250
|
-
check: { type: 'boolean', description: 'update:
|
|
7432
|
+
check: { type: 'boolean', description: 'update: report whether a new release is available (with the changelog since the installed version); do not install' },
|
|
7251
7433
|
binary: { type: 'string', description: 'Path to the nanobpmn server binary' },
|
|
7252
7434
|
name: { type: 'string', description: 'work/supervisor add: worker name (auto ‹host›-‹profile›-‹random› if omitted); hire/assign: agent profile name' },
|
|
7253
7435
|
rank: { type: 'string', description: 'hire: agent rank (principal|senior|junior|decider)' },
|
|
@@ -7326,7 +7508,7 @@ export const commands = {
|
|
|
7326
7508
|
showConfig();
|
|
7327
7509
|
break;
|
|
7328
7510
|
case 'update':
|
|
7329
|
-
updatePlugin(req);
|
|
7511
|
+
await updatePlugin(req);
|
|
7330
7512
|
break;
|
|
7331
7513
|
case 'hire':
|
|
7332
7514
|
await hireWorker(req, flags);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.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",
|
|
@@ -57,12 +57,12 @@
|
|
|
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.32.0",
|
|
61
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.32.0",
|
|
62
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.32.0",
|
|
63
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.32.0",
|
|
64
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.32.0",
|
|
65
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.32.0",
|
|
66
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.32.0"
|
|
67
67
|
}
|
|
68
68
|
}
|