c8ctl-plugin-nano 1.33.2 → 1.34.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 +25 -10
- package/c8ctl-plugin.js +48 -10
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -274,24 +274,39 @@ its agents' terminals to an operator's cockpit. This rides the app's agentic
|
|
|
274
274
|
channel (ADR 0056), served **same-port** on the app's own HTTP base URL at path
|
|
275
275
|
**`/agentic`** — not a sidecar, so there's no extra port to open.
|
|
276
276
|
|
|
277
|
-
**Connecting
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
277
|
+
**Connecting — on by default (local-first).** Nano is designed for local use, so
|
|
278
|
+
visibility is **on by default**. Run a worker against a local app and it appears
|
|
279
|
+
live with **zero configuration** — it joins the channel with a well-known
|
|
280
|
+
localhost token in **LOCAL mode** (no credential). The worker presents this
|
|
281
|
+
token to whatever `NANO_AGENTIC_URL` you point it at; the same-machine
|
|
282
|
+
restriction is enforced by the **hub**, which only honours the well-known LOCAL
|
|
283
|
+
token for local/loopback connections:
|
|
281
284
|
|
|
282
285
|
```bash
|
|
283
|
-
#
|
|
286
|
+
# LOCAL mode (default): appears live with no secrets
|
|
284
287
|
export NANO_AGENTIC_URL=http://localhost:8080 # app base URL; channel is served at /agentic
|
|
288
|
+
c8ctl nano work reviewer
|
|
289
|
+
# agentic channel (local): announcing presence as ‹worker› on ws://localhost:8080/agentic
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Secure mode (opt-in).** For a shared/remote deployment, enrol the worker with an
|
|
293
|
+
ADR 0028 **identity token** and a **capability credential** (the same `?token=…`
|
|
294
|
+
pattern the blackboard uses). Setting either switches the worker into SECURE mode,
|
|
295
|
+
which requires **both** (fail closed if only one is set):
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# SECURE mode: real enrolment
|
|
299
|
+
export NANO_AGENTIC_URL=http://localhost:8080
|
|
285
300
|
export NANO_AGENTIC_TOKEN=<identity-token> # ADR 0028 identity
|
|
286
301
|
export NANO_AGENTIC_CREDENTIAL=<capability-cred> # capability credential
|
|
287
302
|
c8ctl nano work reviewer
|
|
288
|
-
# agentic channel: announcing presence as ‹worker› on ws://localhost:8080/agentic
|
|
303
|
+
# agentic channel (secure): announcing presence as ‹worker› on ws://localhost:8080/agentic
|
|
289
304
|
```
|
|
290
305
|
|
|
291
|
-
|
|
292
|
-
visibility, no relay, nothing else
|
|
293
|
-
connects; an invalid identity is rejected
|
|
294
|
-
is rejected (forbidden).
|
|
306
|
+
To opt out entirely, set `NANO_AGENTIC=off` (or persisted `agentic: false`) — the
|
|
307
|
+
worker then runs with **no visibility, no relay, nothing else changed**. In secure
|
|
308
|
+
mode a valid identity + capability connects; an invalid identity is rejected
|
|
309
|
+
(unauthorized) and a missing capability is rejected (forbidden).
|
|
295
310
|
|
|
296
311
|
**How presence appears.** On connect the worker **announces** its identity, its
|
|
297
312
|
`host`, and the set of `jobKeys` it is currently running, then **heartbeats** to
|
package/c8ctl-plugin.js
CHANGED
|
@@ -135,6 +135,16 @@ const SUPERVISOR_STATE_FILE = 'supervisor.json';
|
|
|
135
135
|
const PROCESSOS_DEFAULT_PORT = 8090;
|
|
136
136
|
const DEFAULT_NANO_URL = 'http://localhost:8080';
|
|
137
137
|
|
|
138
|
+
// The well-known identity token used for LOCAL agentic visibility (security opt-in). Nano is
|
|
139
|
+
// local-first: on the operator's own machine a `nano work` worker joins the visibility channel with
|
|
140
|
+
// zero configuration, so it presents this constant, well-known localhost token — NOT a secret. The
|
|
141
|
+
// worker does not enforce any loopback restriction itself (it presents this token to whatever
|
|
142
|
+
// NANO_AGENTIC_URL is configured); same-machine gating is enforced by the hub, which only honours
|
|
143
|
+
// this well-known token for local/loopback connections. Kept in lock-step with the hub constant in
|
|
144
|
+
// nanobpm/nano-workforce (`app/agentic/channel.ts` LOCAL_AGENTIC_TOKEN). In secure mode (a real
|
|
145
|
+
// NANO_AGENTIC_TOKEN + NANO_AGENTIC_CREDENTIAL) this is never used.
|
|
146
|
+
const LOCAL_AGENTIC_TOKEN = 'nano-local';
|
|
147
|
+
|
|
138
148
|
// Passive update notifier (npm-style): refresh the latest published version
|
|
139
149
|
// from the registry in a detached background process at most once per day, and
|
|
140
150
|
// surface a one-line "update available" notice at most once per day. Never
|
|
@@ -3800,30 +3810,54 @@ function buildResultEnvelope(result, { sandbox, image, git, result: agentResult,
|
|
|
3800
3810
|
* HTTP base URL at `/agentic`; the identity token + capability credential follow
|
|
3801
3811
|
* the blackboard's `?token=…` pattern.
|
|
3802
3812
|
*
|
|
3813
|
+
* Local-first (security opt-in). Nano is designed for local use, so visibility is
|
|
3814
|
+
* ON BY DEFAULT:
|
|
3815
|
+
* - LOCAL mode (default): no credentials configured — the worker connects with
|
|
3816
|
+
* the well-known localhost token ({@link LOCAL_AGENTIC_TOKEN}) and no
|
|
3817
|
+
* capability credential, so it appears live with zero configuration (the hub's
|
|
3818
|
+
* matching LOCAL mode accepts it).
|
|
3819
|
+
* - SECURE mode: set NANO_AGENTIC_TOKEN + NANO_AGENTIC_CREDENTIAL (or the
|
|
3820
|
+
* persisted `agenticToken`/`agenticCredential`) — an ADR 0028 identity token
|
|
3821
|
+
* AND a capability credential are then sent (enrolment). If only one is set the
|
|
3822
|
+
* config is incomplete and we stay off (fail closed), returning `null`.
|
|
3823
|
+
* - OFF: NANO_AGENTIC=off (or 0/false/no), or persisted `agentic:false`.
|
|
3824
|
+
*
|
|
3803
3825
|
* Env wins over persisted config; the base URL falls back to the configured nano
|
|
3804
|
-
* URL (the app's own port).
|
|
3805
|
-
* and a capability credential are present (enrolment) — absent either, it runs
|
|
3806
|
-
* exactly as before, off the visibility page. Returns `null` when not enrolled.
|
|
3826
|
+
* URL (the app's own port). Returns `null` only when disabled or half-configured.
|
|
3807
3827
|
*
|
|
3808
|
-
* @returns {{ url: string, token: string, credential: string, bufferCapacity: number } | null}
|
|
3828
|
+
* @returns {{ url: string, token: string, credential: string, bufferCapacity: number, secure: boolean } | null}
|
|
3809
3829
|
*/
|
|
3810
3830
|
function resolveAgenticConfig() {
|
|
3811
3831
|
const cfg = readConfig();
|
|
3832
|
+
// Explicit off-switch (env wins). Lets an operator fully opt out of visibility.
|
|
3833
|
+
const offSetting = process.env.NANO_AGENTIC
|
|
3834
|
+
?? (cfg.agentic === false ? 'off' : cfg.agentic);
|
|
3835
|
+
if (/^(0|off|false|no)$/i.test(String(offSetting ?? ''))) return null;
|
|
3836
|
+
|
|
3812
3837
|
const url = process.env.NANO_AGENTIC_URL
|
|
3813
3838
|
|| cfg.agenticUrl
|
|
3814
3839
|
|| cfg.nanoUrl
|
|
3815
3840
|
|| process.env.NANO_BASE_URL
|
|
3816
3841
|
|| DEFAULT_NANO_URL;
|
|
3842
|
+
if (!url) return null;
|
|
3817
3843
|
const token = process.env.NANO_AGENTIC_TOKEN || cfg.agenticToken || '';
|
|
3818
3844
|
const credential = process.env.NANO_AGENTIC_CREDENTIAL || cfg.agenticCredential || '';
|
|
3819
|
-
if (!url || !token || !credential) return null;
|
|
3820
3845
|
// Outbound hub-down buffer bound (frames). Operator-tunable (C4, #43) so a
|
|
3821
3846
|
// long expected outage can be given more headroom; resolveBufferCapacity
|
|
3822
3847
|
// validates it to a positive integer and falls back to the client default.
|
|
3823
3848
|
const bufferCapacity = resolveBufferCapacity(
|
|
3824
3849
|
process.env.NANO_AGENTIC_BUFFER_CAPACITY ?? cfg.agenticBufferCapacity,
|
|
3825
3850
|
);
|
|
3826
|
-
|
|
3851
|
+
|
|
3852
|
+
// SECURE mode: any explicit credential configured means the operator opted into
|
|
3853
|
+
// enrolment — require BOTH halves, fail closed if only one is present.
|
|
3854
|
+
if (token || credential) {
|
|
3855
|
+
if (!token || !credential) return null;
|
|
3856
|
+
return { url, token, credential, bufferCapacity, secure: true };
|
|
3857
|
+
}
|
|
3858
|
+
|
|
3859
|
+
// LOCAL mode (default): well-known localhost token, no capability credential.
|
|
3860
|
+
return { url, token: LOCAL_AGENTIC_TOKEN, credential: '', bufferCapacity, secure: false };
|
|
3827
3861
|
}
|
|
3828
3862
|
|
|
3829
3863
|
/**
|
|
@@ -4146,8 +4180,10 @@ async function workAgent(req, flags) {
|
|
|
4146
4180
|
// accessors on `workChannel` (relay-lane sink + connect/disconnect/reconnect
|
|
4147
4181
|
// lifecycle events) rather than opening their own connection.
|
|
4148
4182
|
//
|
|
4149
|
-
//
|
|
4150
|
-
// worker
|
|
4183
|
+
// Local-first (security opt-in): visibility is ON BY DEFAULT. In LOCAL mode the
|
|
4184
|
+
// worker joins with the well-known localhost token and no credential; SECURE
|
|
4185
|
+
// mode (NANO_AGENTIC_TOKEN + NANO_AGENTIC_CREDENTIAL) sends a real ADR 0028
|
|
4186
|
+
// identity + capability; NANO_AGENTIC=off disables it (see resolveAgenticConfig).
|
|
4151
4187
|
const agenticCfg = resolveAgenticConfig();
|
|
4152
4188
|
if (agenticCfg) {
|
|
4153
4189
|
try {
|
|
@@ -4167,7 +4203,8 @@ async function workAgent(req, flags) {
|
|
|
4167
4203
|
logger,
|
|
4168
4204
|
});
|
|
4169
4205
|
const shown = redactAgenticUrl(buildAgenticUrl(agenticCfg.url, {}));
|
|
4170
|
-
|
|
4206
|
+
const mode = agenticCfg.secure ? 'secure' : 'local';
|
|
4207
|
+
logger.info(` agentic channel (${mode}): announcing presence as ${workerName} on ${shown}`);
|
|
4171
4208
|
} catch (err) {
|
|
4172
4209
|
// Never let a channel failure stop the worker from doing its actual job.
|
|
4173
4210
|
workChannel = null;
|
|
@@ -4191,7 +4228,7 @@ async function workAgent(req, flags) {
|
|
|
4191
4228
|
}
|
|
4192
4229
|
}
|
|
4193
4230
|
} else {
|
|
4194
|
-
logger.info(' agentic channel:
|
|
4231
|
+
logger.info(' agentic channel: disabled — either the off-switch is set (NANO_AGENTIC=off or persisted agentic:false), or SECURE mode is half-configured (set BOTH NANO_AGENTIC_TOKEN + NANO_AGENTIC_CREDENTIAL). Clear the off-switch to use default LOCAL visibility.');
|
|
4195
4232
|
}
|
|
4196
4233
|
|
|
4197
4234
|
// C3 (#42): the role's live-terminal mode — a full PTY (streamed on the relay
|
|
@@ -7566,6 +7603,7 @@ function parseProcessosRequest(args, flags) {
|
|
|
7566
7603
|
export { resolveBinary, findBinary, launcherEnvMarkers };
|
|
7567
7604
|
export { setConfig, unsetConfig, readConfig, writeConfig, getConfigFile, SETTING_ALIASES };
|
|
7568
7605
|
export { buildNpmInvocation };
|
|
7606
|
+
export { resolveAgenticConfig, LOCAL_AGENTIC_TOKEN };
|
|
7569
7607
|
export { compareSemver, githubRepoSlug, filterReleasesSince, renderReleaseBody };
|
|
7570
7608
|
export {
|
|
7571
7609
|
webConsoleUrl,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.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.34.0",
|
|
61
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.34.0",
|
|
62
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.34.0",
|
|
63
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.34.0",
|
|
64
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.34.0",
|
|
65
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.34.0",
|
|
66
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.34.0"
|
|
67
67
|
}
|
|
68
68
|
}
|