c8ctl-plugin-nano 1.39.1 → 1.40.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 +8 -7
- package/c8ctl-plugin.js +117 -17
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -208,7 +208,7 @@ c8ctl nano work reviewer --job-type senior:pr-review --job-type senior:triage
|
|
|
208
208
|
|
|
209
209
|
```bash
|
|
210
210
|
c8ctl nano work reviewer # poll for work until Ctrl-C
|
|
211
|
-
c8ctl nano work reviewer --
|
|
211
|
+
c8ctl nano work reviewer --recovery-window 300000
|
|
212
212
|
c8ctl nano work reviewer --name reviewer-eu # name this worker (else auto ‹host›-‹profile›-‹random›)
|
|
213
213
|
```
|
|
214
214
|
|
|
@@ -728,7 +728,7 @@ c8ctl nano supervisor
|
|
|
728
728
|
|
|
729
729
|
# Manage the fleet without the console (any terminal, any time):
|
|
730
730
|
c8ctl nano supervisor status # id, state, pid, restarts, uptime
|
|
731
|
-
c8ctl nano supervisor add reviewer
|
|
731
|
+
c8ctl nano supervisor add reviewer # add + spawn a worker (forwards work flags)
|
|
732
732
|
c8ctl nano supervisor add reviewer --name reviewer-2 # a SECOND reviewer, named so it stays distinct
|
|
733
733
|
c8ctl nano supervisor add reviewer --instances 3 # add 3 distinct auto-named reviewers in one call
|
|
734
734
|
c8ctl nano supervisor restart reviewer # by worker id or profile name
|
|
@@ -749,12 +749,13 @@ cannot be combined with `--name`; omit `--name` to let them auto-name.
|
|
|
749
749
|
`restart`/`remove` accept either a worker id **or** a profile name — targeting a
|
|
750
750
|
profile affects *every* instance of it.
|
|
751
751
|
|
|
752
|
-
Each worker takes the **same flags as `nano work`**
|
|
753
|
-
`--recovery-window`, `--idle-timeout`, `--job-timeout`, `--poll-timeout`,
|
|
752
|
+
Each worker takes the **same flags as `nano work`**
|
|
753
|
+
(`--recovery-window`, `--idle-timeout`, `--job-timeout`, `--poll-timeout`,
|
|
754
754
|
`--sandbox`/`--image`, `--job-type`, `--env`, `--arg`, …); they are forwarded
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
755
|
+
to the spawned child (reconstructed via `reconstructWorkArgs`, which normalizes
|
|
756
|
+
ordering and coerces booleans), so a supervised worker is semantically
|
|
757
|
+
equivalent to a hand-run `nano work`. In the
|
|
758
|
+
interactive console, type the flags after the profile: `add reviewer --recovery-window 300000`.
|
|
758
759
|
|
|
759
760
|
How it works and where things live:
|
|
760
761
|
|
package/c8ctl-plugin.js
CHANGED
|
@@ -1549,6 +1549,33 @@ const RANKS = ['principal', 'senior', 'junior', 'decider'];
|
|
|
1549
1549
|
// opt-in per role because a TTY changes the harness's I/O semantics.
|
|
1550
1550
|
const TERMINAL_MODES = ['pipe', 'pty'];
|
|
1551
1551
|
|
|
1552
|
+
// #110: the harness protocol a role drives its agent over — a plain stdin/scrape
|
|
1553
|
+
// `pipe` (the default floor) or `acp` (Agent Client Protocol, JSON-RPC over
|
|
1554
|
+
// stdio). Default is `pipe`; `acp` is opt-in per role. The ACP executor lands in
|
|
1555
|
+
// a downstream task — this seam only carries the schema/plumbing.
|
|
1556
|
+
const PROTOCOLS = ['pipe', 'acp'];
|
|
1557
|
+
|
|
1558
|
+
// #110: the ACP permission policy for a role. Only `yolo` (auto-allow-all) is
|
|
1559
|
+
// enforced today; `escalate`/`filter` are RESERVED pending nano-workforce#559
|
|
1560
|
+
// (the permission-event + escalation bridge) and are not yet enforced — they are
|
|
1561
|
+
// accepted and persisted for forward-compatibility (never downgraded), but today
|
|
1562
|
+
// effectively behave like `yolo` (auto-allow). Default is `yolo`.
|
|
1563
|
+
const PERMISSION_MODES = ['yolo', 'escalate', 'filter'];
|
|
1564
|
+
|
|
1565
|
+
// #110: resolve a role's agentic setting (protocol/permission) with a uniform
|
|
1566
|
+
// env-override → profile → default precedence, tolerating invalid values at
|
|
1567
|
+
// every layer. A one-off worker env var wins if it names an allowed value; else
|
|
1568
|
+
// the persisted hire profile decides if it holds an allowed value; else the safe
|
|
1569
|
+
// default. Reserved-but-allowed values (e.g. escalate/filter) carry through
|
|
1570
|
+
// verbatim; unknown values are ignored and fall through to the next layer.
|
|
1571
|
+
function resolveAgenticSetting(envValue, profileValue, allowed, dflt) {
|
|
1572
|
+
const env = String(envValue || '').trim().toLowerCase();
|
|
1573
|
+
if (allowed.includes(env)) return env;
|
|
1574
|
+
const profile = String(profileValue || '').trim().toLowerCase();
|
|
1575
|
+
if (allowed.includes(profile)) return profile;
|
|
1576
|
+
return dflt;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1552
1579
|
/** Normalize a capability list: trim, drop empties, de-dupe, sort (canonical). */
|
|
1553
1580
|
function normalizeCapabilities(input) {
|
|
1554
1581
|
const raw = Array.isArray(input)
|
|
@@ -1771,6 +1798,15 @@ function normalizeStoredProfile(name, profile) {
|
|
|
1771
1798
|
// to the safe `pipe` default rather than failing the whole profile.
|
|
1772
1799
|
const terminalRaw = typeof profile.terminal === 'string' ? profile.terminal.trim().toLowerCase() : '';
|
|
1773
1800
|
const terminal = TERMINAL_MODES.includes(terminalRaw) ? terminalRaw : 'pipe';
|
|
1801
|
+
// #110: harness protocol + ACP permission policy. Tolerant like `terminal` —
|
|
1802
|
+
// an unknown/legacy/missing value falls back to the safe defaults ('pipe' /
|
|
1803
|
+
// 'yolo') rather than failing the whole profile. A persisted escalate/filter
|
|
1804
|
+
// is preserved verbatim (it is enforced by a downstream task pending
|
|
1805
|
+
// nano-workforce#559), never downgraded.
|
|
1806
|
+
const protocolRaw = typeof profile.protocol === 'string' ? profile.protocol.trim().toLowerCase() : '';
|
|
1807
|
+
const protocol = PROTOCOLS.includes(protocolRaw) ? protocolRaw : 'pipe';
|
|
1808
|
+
const permissionRaw = typeof profile.permission === 'string' ? profile.permission.trim().toLowerCase() : '';
|
|
1809
|
+
const permission = PERMISSION_MODES.includes(permissionRaw) ? permissionRaw : 'yolo';
|
|
1774
1810
|
return {
|
|
1775
1811
|
profile: {
|
|
1776
1812
|
name,
|
|
@@ -1782,6 +1818,8 @@ function normalizeStoredProfile(name, profile) {
|
|
|
1782
1818
|
sandbox,
|
|
1783
1819
|
image,
|
|
1784
1820
|
terminal,
|
|
1821
|
+
protocol,
|
|
1822
|
+
permission,
|
|
1785
1823
|
env: normalizeEnvMap(profile.env),
|
|
1786
1824
|
},
|
|
1787
1825
|
};
|
|
@@ -1900,7 +1938,15 @@ async function hireWorker(req, flags) {
|
|
|
1900
1938
|
for (const name of names.sort()) {
|
|
1901
1939
|
const p = hires[name];
|
|
1902
1940
|
const term = String(p.terminal || '').trim().toLowerCase() === 'pty' ? '; terminal: pty' : '';
|
|
1903
|
-
|
|
1941
|
+
const proto = String(p.protocol || '').trim().toLowerCase() === 'acp' ? '; protocol: acp' : '';
|
|
1942
|
+
const perm = (() => {
|
|
1943
|
+
const v = String(p.permission || '').trim().toLowerCase();
|
|
1944
|
+
// Only surface recognized non-default modes; normalizeStoredProfile
|
|
1945
|
+
// coerces unknown/legacy values back to yolo at runtime, so showing them
|
|
1946
|
+
// here would make --list disagree with actual behavior.
|
|
1947
|
+
return v && v !== 'yolo' && PERMISSION_MODES.includes(v) ? `; permission: ${v}` : '';
|
|
1948
|
+
})();
|
|
1949
|
+
logger.info(` ${name} [${p.rank}] ${buildAgentCommandLine(p.command, p.args)} (model: ${p.model || '-'}; caps: ${normalizeCapabilities(p.capabilities).join(', ') || '-'}${term}${proto}${perm})`);
|
|
1904
1950
|
}
|
|
1905
1951
|
logger.info('');
|
|
1906
1952
|
logger.info('Put one to work with: c8ctl nano work <name>');
|
|
@@ -1917,6 +1963,8 @@ async function hireWorker(req, flags) {
|
|
|
1917
1963
|
let sandbox = flags?.sandbox !== undefined ? String(flags.sandbox).trim().toLowerCase() : undefined;
|
|
1918
1964
|
let image = flags?.image !== undefined ? String(flags.image).trim() : undefined;
|
|
1919
1965
|
let terminal = flags?.terminal !== undefined ? String(flags.terminal).trim().toLowerCase() : undefined;
|
|
1966
|
+
let protocol = flags?.protocol !== undefined ? String(flags.protocol).trim().toLowerCase() : undefined;
|
|
1967
|
+
let permission = flags?.permission !== undefined ? String(flags.permission).trim().toLowerCase() : undefined;
|
|
1920
1968
|
// Structured command-line switches appended to the command when spawned, e.g.
|
|
1921
1969
|
// `--arg --allow-all` for `copilot`. Repeatable; each --arg is one argv token.
|
|
1922
1970
|
const commandArgs = normalizeArgList(flags?.arg);
|
|
@@ -1995,6 +2043,8 @@ async function hireWorker(req, flags) {
|
|
|
1995
2043
|
if (sandbox === undefined || sandbox === '') sandbox = 'none';
|
|
1996
2044
|
if (image === undefined) image = '';
|
|
1997
2045
|
if (terminal === undefined || terminal === '') terminal = 'pipe';
|
|
2046
|
+
if (protocol === undefined || protocol === '') protocol = 'pipe';
|
|
2047
|
+
if (permission === undefined || permission === '') permission = 'yolo';
|
|
1998
2048
|
|
|
1999
2049
|
if (!SANDBOXES.includes(sandbox)) {
|
|
2000
2050
|
logger.error(`Invalid --sandbox "${sandbox}". Use one of: ${SANDBOXES.join(', ')}`);
|
|
@@ -2004,6 +2054,21 @@ async function hireWorker(req, flags) {
|
|
|
2004
2054
|
logger.error(`Invalid --terminal "${terminal}". Use one of: ${TERMINAL_MODES.join(', ')}`);
|
|
2005
2055
|
process.exit(1);
|
|
2006
2056
|
}
|
|
2057
|
+
if (!PROTOCOLS.includes(protocol)) {
|
|
2058
|
+
logger.error(`Invalid --protocol "${protocol}". Use one of: ${PROTOCOLS.join(', ')}`);
|
|
2059
|
+
process.exit(1);
|
|
2060
|
+
}
|
|
2061
|
+
if (!PERMISSION_MODES.includes(permission)) {
|
|
2062
|
+
logger.error(`Invalid --permission "${permission}". Use one of: ${PERMISSION_MODES.join(', ')}`);
|
|
2063
|
+
process.exit(1);
|
|
2064
|
+
}
|
|
2065
|
+
// #110: escalate/filter are accepted and persisted for forward-compatibility,
|
|
2066
|
+
// but not yet enforced (pending nano-workforce#559). Warn the operator so a
|
|
2067
|
+
// hire is never misread as gating destructive ops today — the value is kept as
|
|
2068
|
+
// given (never downgraded to yolo).
|
|
2069
|
+
if (permission === 'escalate' || permission === 'filter') {
|
|
2070
|
+
logger.warn(`Permission policy "${permission}" is RESERVED and NOT enforced in this build (pending nano-workforce#559): it does not gate anything today and effectively behaves like yolo (auto-allow all permission requests). The value is persisted as-is for forward-compatibility.`);
|
|
2071
|
+
}
|
|
2007
2072
|
|
|
2008
2073
|
if (CONTAINER_SANDBOXES.has(sandbox) && !image) {
|
|
2009
2074
|
logger.error(`--sandbox ${sandbox} requires --image <ref> (the container image the agent runs in).`);
|
|
@@ -2034,6 +2099,8 @@ async function hireWorker(req, flags) {
|
|
|
2034
2099
|
sandbox,
|
|
2035
2100
|
image: image || '',
|
|
2036
2101
|
terminal,
|
|
2102
|
+
protocol,
|
|
2103
|
+
permission,
|
|
2037
2104
|
env: profileEnv,
|
|
2038
2105
|
createdAt: new Date().toISOString(),
|
|
2039
2106
|
};
|
|
@@ -2046,6 +2113,8 @@ async function hireWorker(req, flags) {
|
|
|
2046
2113
|
if (profile.args.length > 0) logger.info(` args: ${profile.args.map(shQuote).join(' ')}`);
|
|
2047
2114
|
logger.info(` sandbox: ${profile.sandbox}${CONTAINER_SANDBOXES.has(profile.sandbox) ? ` (image ${profile.image})` : ''}`);
|
|
2048
2115
|
logger.info(` live terminal: ${profile.terminal}${profile.terminal === 'pty' ? ' (streamed + steerable on the relay lane)' : ''}`);
|
|
2116
|
+
logger.info(` protocol: ${profile.protocol}${profile.protocol === 'acp' ? ' (Agent Client Protocol — JSON-RPC over stdio; RESERVED — accepted/persisted but not yet active in this build; the harness still runs on the transport selected by --terminal (pipe or pty))' : ''}`);
|
|
2117
|
+
logger.info(` permission: ${profile.permission}${(profile.permission === 'escalate' || profile.permission === 'filter') ? ' (RESERVED — not yet enforced, pending nano-workforce#559)' : ''}`);
|
|
2049
2118
|
const envKeys = Object.keys(profile.env);
|
|
2050
2119
|
if (envKeys.length > 0) logger.info(` env: ${envKeys.join(', ')}`);
|
|
2051
2120
|
logger.info(` job types (${matrix.length}): ${matrix.join(' ')}`);
|
|
@@ -3066,9 +3135,9 @@ function credArgs() {
|
|
|
3066
3135
|
// git via GIT_ASKPASS only (never argv/URL/helper), preserving the ephemeral-token
|
|
3067
3136
|
// guarantee.
|
|
3068
3137
|
// Memoized for the process lifetime: this is a synchronous spawnSync (up to a
|
|
3069
|
-
// 10s timeout) that can be reached per job,
|
|
3070
|
-
//
|
|
3071
|
-
//
|
|
3138
|
+
// 10s timeout) that can be reached per job, so consult the CLI at most once per
|
|
3139
|
+
// worker run rather than blocking a handler on every job. A sentinel
|
|
3140
|
+
// distinguishes "not yet computed" from
|
|
3072
3141
|
// a cached null (gh missing / not logged in).
|
|
3073
3142
|
//
|
|
3074
3143
|
// Memoization alone still lets the *first* job pay the synchronous spawn on the
|
|
@@ -3969,7 +4038,12 @@ function startLockExtender(job, windowMs, intervalMs, tag, logger) {
|
|
|
3969
4038
|
* Both paths resolve to the same result contract.
|
|
3970
4039
|
*/
|
|
3971
4040
|
function runAgentJob(profile, job, opts = {}) {
|
|
3972
|
-
const { timeoutMs, idleTimeoutMs, envelope, sandbox = 'none', image, runId, secretEnv = {}, passThroughSecretNames = [], cwd, extraEnv = {}, profileEnv = {}, resultFile, stream = false, streamPrefix = '', onStreamOut, onStreamErr, args: commandArgs, terminal = 'pipe', relaySession = null, ptyFactory } = opts;
|
|
4041
|
+
const { timeoutMs, idleTimeoutMs, envelope, sandbox = 'none', image, runId, secretEnv = {}, passThroughSecretNames = [], cwd, extraEnv = {}, profileEnv = {}, resultFile, stream = false, streamPrefix = '', onStreamOut, onStreamErr, args: commandArgs, terminal = 'pipe', protocol = 'pipe', permission = 'yolo', relaySession = null, ptyFactory } = opts;
|
|
4042
|
+
// #110: `protocol`/`permission` are accepted here so the seam exists for the
|
|
4043
|
+
// downstream ACP executor. This task does NOT dispatch on them — the pipe/PTY
|
|
4044
|
+
// paths below are unchanged, so `protocol === 'pipe'` behavior is identical.
|
|
4045
|
+
// TODO(#110): the acp dispatch branch (spawnCaptureAcp) lands in a later task.
|
|
4046
|
+
void protocol; void permission;
|
|
3973
4047
|
const payload = JSON.stringify(buildAgentPayload(profile, job, envelope));
|
|
3974
4048
|
const agentEnv = baseAgentEnv(profile, job);
|
|
3975
4049
|
// The harness command line: the profile command plus its structured switches
|
|
@@ -4643,7 +4717,12 @@ async function workAgent(req, flags) {
|
|
|
4643
4717
|
const n = Number.parseInt(String(v ?? ''), 10);
|
|
4644
4718
|
return Number.isFinite(n) && n > 0 ? n : dflt;
|
|
4645
4719
|
};
|
|
4646
|
-
|
|
4720
|
+
// One job per worker, hard-wired (there is deliberately no --max-parallel
|
|
4721
|
+
// flag): an agent harness holds a PTY + a git workspace for the whole life of
|
|
4722
|
+
// a job, so a worker must never lease a second job concurrently. The @camunda8
|
|
4723
|
+
// SDK derives maxJobsToActivate = maxParallelJobs - activeJobs, so 1 means
|
|
4724
|
+
// "activate one job, then stop polling until it completes".
|
|
4725
|
+
const maxParallelJobs = 1;
|
|
4647
4726
|
// The broker job-activation lock is NOT hardcoded up front. A fixed timeout is
|
|
4648
4727
|
// impossible to size for an agent: too short reclaims a still-working job (a
|
|
4649
4728
|
// second agent starts + the stale complete/fail is rejected 409), too long
|
|
@@ -4837,12 +4916,13 @@ async function workAgent(req, flags) {
|
|
|
4837
4916
|
}
|
|
4838
4917
|
const extraNote = extraJobTypes.length > 0 ? ` (${extraJobTypes.length} via --job-type)` : '';
|
|
4839
4918
|
logger.info(` listening on ${jobTypes.length} job type(s)${extraNote}: ${jobTypes.join(' ')}`);
|
|
4840
|
-
logger.info(`
|
|
4919
|
+
logger.info(` one job per worker; recovery window: ${recoveryWindowMs}ms; idle timeout: ${idleTimeoutMs}ms; hard cap: ${hardCapMs > 0 ? `${hardCapMs}ms` : 'off'}; poll timeout: ${pollTimeoutMs}ms`);
|
|
4841
4920
|
// Warm the gh-token cache now, off the job-handling path: githubCloneToken()
|
|
4842
4921
|
// may consult `gh auth token` (a synchronous spawn, up to 10s) as its default
|
|
4843
|
-
// credential fallback, and doing that inside a job handler would
|
|
4844
|
-
//
|
|
4845
|
-
// cost once at startup so every later lookup is a warm
|
|
4922
|
+
// credential fallback, and doing that inside a job handler would block the
|
|
4923
|
+
// event loop — stalling the lock heartbeat and delaying the job itself.
|
|
4924
|
+
// Priming here pays that cost once at startup so every later lookup is a warm
|
|
4925
|
+
// cache hit.
|
|
4846
4926
|
primeGhAuthToken();
|
|
4847
4927
|
logger.info('Polling for work — press Ctrl-C to stop.');
|
|
4848
4928
|
|
|
@@ -5063,6 +5143,17 @@ async function workAgent(req, flags) {
|
|
|
5063
5143
|
logger.info(` live terminal: ${roleTerminal === 'pty' ? 'PTY (streamed + steerable)' : 'pipe (streamed)'} on the relay lane.`);
|
|
5064
5144
|
}
|
|
5065
5145
|
|
|
5146
|
+
// #110: the role's harness protocol (pipe|acp) and ACP permission policy
|
|
5147
|
+
// (yolo|escalate|filter), resolved with the same env-override-then-profile
|
|
5148
|
+
// precedence as terminal. `NANO_AGENTIC_PROTOCOL`/`NANO_AGENTIC_PERMISSION`
|
|
5149
|
+
// override a one-off worker; otherwise the hire profile decides; else the safe
|
|
5150
|
+
// defaults (pipe/yolo). escalate/filter are carried through verbatim — the
|
|
5151
|
+
// acp-executor task enforces yolo and interim-handles the reserved policies.
|
|
5152
|
+
const envProtocol = (process.env.NANO_AGENTIC_PROTOCOL || '').trim().toLowerCase();
|
|
5153
|
+
const roleProtocol = resolveAgenticSetting(envProtocol, profile.protocol, PROTOCOLS, 'pipe');
|
|
5154
|
+
const envPermission = (process.env.NANO_AGENTIC_PERMISSION || '').trim().toLowerCase();
|
|
5155
|
+
const rolePermission = resolveAgenticSetting(envPermission, profile.permission, PERMISSION_MODES, 'yolo');
|
|
5156
|
+
|
|
5066
5157
|
// A per-job-type worker factory. Captures all the CLI-local + profile context
|
|
5067
5158
|
// in closure scope so the profile watcher below can (re)spawn a poller for any
|
|
5068
5159
|
// job type on demand without re-reading the flags.
|
|
@@ -5248,6 +5339,11 @@ async function workAgent(req, flags) {
|
|
|
5248
5339
|
// stream on the relay lane when a relay session exists (skipped when
|
|
5249
5340
|
// relaySession is null); only a PTY is interactively steerable.
|
|
5250
5341
|
terminal: roleTerminal,
|
|
5342
|
+
// #110: harness protocol + ACP permission policy threaded to
|
|
5343
|
+
// runAgentJob. Inert in this seam task (pipe/pty dispatch unchanged);
|
|
5344
|
+
// the acp-executor task acts on them.
|
|
5345
|
+
protocol: roleProtocol,
|
|
5346
|
+
permission: rolePermission,
|
|
5251
5347
|
relaySession,
|
|
5252
5348
|
// Route the --stream tee through c8ctl's output-mode-aware logger so
|
|
5253
5349
|
// spying never corrupts a structured/JSON output mode.
|
|
@@ -5620,10 +5716,10 @@ const SUPERVISOR_MONITOR_INTERVAL_MS = 1_000;
|
|
|
5620
5716
|
// extra daemon traffic.
|
|
5621
5717
|
const SUPERVISOR_LIVE_TICK_MS = 5_000;
|
|
5622
5718
|
|
|
5623
|
-
// The `nano work` flags forwarded
|
|
5719
|
+
// The `nano work` flags forwarded to each spawned child (reconstructed and
|
|
5720
|
+
// normalized by `reconstructWorkArgs`, not passed through byte-for-byte).
|
|
5624
5721
|
// kind: 'value' → `--flag v`; 'boolean' → `--flag`; 'list' → repeated `--flag v`.
|
|
5625
5722
|
const WORK_FORWARD_FLAGS = {
|
|
5626
|
-
'max-parallel': 'value',
|
|
5627
5723
|
'job-timeout': 'value',
|
|
5628
5724
|
'recovery-window': 'value',
|
|
5629
5725
|
'idle-timeout': 'value',
|
|
@@ -8934,6 +9030,7 @@ export {
|
|
|
8934
9030
|
export { setConfig, unsetConfig, readConfig, writeConfig, getConfigFile, SETTING_ALIASES };
|
|
8935
9031
|
export { buildNpmInvocation };
|
|
8936
9032
|
export { resolveAgenticConfig, LOCAL_AGENTIC_TOKEN };
|
|
9033
|
+
export { resolveAgenticSetting, PROTOCOLS, PERMISSION_MODES };
|
|
8937
9034
|
export { resolveAgenticTarget, discoverAgenticHubs, probeAgenticChannel, normalizeProjectApps, isLoopbackHost };
|
|
8938
9035
|
export { compareSemver, githubRepoSlug, filterReleasesSince, renderReleaseBody };
|
|
8939
9036
|
export {
|
|
@@ -9097,6 +9194,7 @@ export const metadata = {
|
|
|
9097
9194
|
{ command: 'c8ctl nano hire --list', description: 'List hired agent profiles' },
|
|
9098
9195
|
{ 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' },
|
|
9099
9196
|
{ command: 'c8ctl nano hire --name coder --rank senior --command copilot --terminal pty', description: 'Opt this role into a full, steerable live terminal (PTY) streamed on the agentic relay lane (default: pipe)' },
|
|
9197
|
+
{ command: 'c8ctl nano hire --name coder --rank senior --command copilot --protocol acp --permission yolo', description: 'Accept/persist ACP (JSON-RPC/stdio) for this role — RESERVED, not yet active in this build (acp is inert; the harness still runs on the transport selected by --terminal, pipe or pty); escalate/filter permission modes are likewise reserved/not yet active' },
|
|
9100
9198
|
{ command: 'c8ctl nano assign reviewer code-review,testing', description: 'Grant more capabilities (comma-separated, like hire) to an existing hire — additive; running workers hot-reload it' },
|
|
9101
9199
|
{ command: 'c8ctl nano work reviewer', description: 'Spawn Nano job workers for the "reviewer" profile and poll for work' },
|
|
9102
9200
|
{ command: 'c8ctl nano work coder --auto', description: 'Zero-config: serve every deployed agent job type read straight from the engine — no capability, no wiring (great for a local single-tenant plane)' },
|
|
@@ -9106,7 +9204,7 @@ export const metadata = {
|
|
|
9106
9204
|
{ command: 'c8ctl nano supervisor start --worker reviewer --worker coder', description: 'Start a detached supervisor managing several workers from one terminal' },
|
|
9107
9205
|
{ command: 'c8ctl nano supervisor', description: 'Attach an interactive console to the supervisor (detach with Ctrl-D, leaving it running)' },
|
|
9108
9206
|
{ command: 'c8ctl nano supervisor status', description: 'List supervised workers (state, ENGINE + AGENTIC visibility diagnostics, serviced job / idle, pid, restarts, uptime) without the console' },
|
|
9109
|
-
{ command: 'c8ctl nano supervisor add decider
|
|
9207
|
+
{ command: 'c8ctl nano supervisor add decider', description: 'Add a supervised worker (forwarding work flags) to the running supervisor' },
|
|
9110
9208
|
{ command: 'c8ctl nano supervisor add reviewer --instances 3', description: 'Add 3 distinct auto-named instances of a profile in one call' },
|
|
9111
9209
|
{ command: 'c8ctl nano supervisor restart reviewer', description: 'Restart a supervised worker by id or profile' },
|
|
9112
9210
|
{ command: 'c8ctl nano supervisor stop', description: 'Stop the supervisor daemon and all its workers' },
|
|
@@ -9159,6 +9257,8 @@ export const commands = {
|
|
|
9159
9257
|
sandbox: { type: 'string', description: 'hire/work: execution sandbox none|docker|podman (default none). Containers isolate each job.' },
|
|
9160
9258
|
image: { type: 'string', description: 'hire/work: container image the agent runs in (required for --sandbox docker|podman)' },
|
|
9161
9259
|
terminal: { type: 'string', description: 'hire: live-terminal mode for this role — pty (full terminal, streamed + steerable on the relay lane) or pipe (default). NANO_AGENTIC_TERMINAL overrides at work time.' },
|
|
9260
|
+
protocol: { type: 'string', description: 'hire: harness protocol pipe|acp (default pipe). acp is RESERVED — accepted and persisted for forward-compatibility but not yet implemented in this build (inert: the harness still runs on the transport selected by --terminal, pipe or pty; the ACP JSON-RPC-over-stdio executor lands downstream). NANO_AGENTIC_PROTOCOL overrides at work time.' },
|
|
9261
|
+
permission: { type: 'string', description: 'hire: ACP permission policy (default yolo). yolo auto-allows all permission requests. escalate|filter are RESERVED/not-yet-active in this build (pending nano-workforce#559): they are persisted but not enforced and effectively behave like yolo (auto-allow). NANO_AGENTIC_PERMISSION overrides at work time.' },
|
|
9162
9262
|
env: { type: 'string', multiple: true, description: 'hire/work: static env var for the harness as NAME=VALUE (repeatable); persisted on hire, work extends/overrides. E.g. permission toggles.' },
|
|
9163
9263
|
'secret-resolver': { type: 'string', description: 'work: secret resolver for task secretRefs (host = process env; default host)' },
|
|
9164
9264
|
'reap-age': { type: 'string', description: 'work: age in ms before a finished agent container or job workspace is reaped (default 3600000)' },
|
|
@@ -9168,7 +9268,6 @@ export const commands = {
|
|
|
9168
9268
|
'keep-runs': { type: 'boolean', description: 'work: keep per-job workspaces under <state>/agent-runs instead of deleting them after each job (debug)' },
|
|
9169
9269
|
stream: { type: 'boolean', description: 'work: tee each agent job\'s live stdout/stderr to this console, prefixed with the job type + key (spy/debug)' },
|
|
9170
9270
|
list: { type: 'boolean', description: 'hire: list existing agent profiles instead of creating one' },
|
|
9171
|
-
'max-parallel': { type: 'string', description: 'work: max concurrent jobs per worker (default 1)' },
|
|
9172
9271
|
'job-timeout': { type: 'string', description: 'work: OPTIONAL absolute hard cap on total harness runtime per job in ms; the process is killed past this. Default 0 = unlimited (the broker lock is auto-managed — see --recovery-window / --idle-timeout).' },
|
|
9173
9272
|
'recovery-window': { type: 'string', description: 'work: broker activation-lock window in ms, auto-refreshed while the agent runs; also the node-loss reclaim time (a dead/killed worker\'s job is re-activated within this). Default 300000.' },
|
|
9174
9273
|
'idle-timeout': { type: 'string', description: 'work: max ms an agent may produce no stdout/stderr before it is killed as wedged (stops lock extension → job reclaimed). Default 300000.' },
|
|
@@ -9332,9 +9431,9 @@ function printUsage() {
|
|
|
9332
9431
|
console.log(' c8ctl nano unset <bin|model-dir>');
|
|
9333
9432
|
console.log(' c8ctl nano config');
|
|
9334
9433
|
console.log(' c8ctl nano update [--check]');
|
|
9335
|
-
console.log(' c8ctl nano hire [--name <n>] [--rank <r>] [--command <c>] [--arg <switch> ...] [--model <m>] [--capabilities <a,b>] [--sandbox none|docker|podman] [--image <ref>] [--terminal pty|pipe] [--env NAME=VALUE ...] [--list]');
|
|
9434
|
+
console.log(' c8ctl nano hire [--name <n>] [--rank <r>] [--command <c>] [--arg <switch> ...] [--model <m>] [--capabilities <a,b>] [--sandbox none|docker|podman] [--image <ref>] [--terminal pty|pipe] [--protocol pipe|acp] [--permission yolo|escalate|filter] [--env NAME=VALUE ...] [--list]');
|
|
9336
9435
|
console.log(' c8ctl nano assign <profileName> <cap[,cap...]> [--name <n>] [--capabilities <a,b>]');
|
|
9337
|
-
console.log(' c8ctl nano work <profileName> [--auto [--auto-scope <p>]] [--arg <switch> ...] [--
|
|
9436
|
+
console.log(' c8ctl nano work <profileName> [--auto [--auto-scope <p>]] [--arg <switch> ...] [--recovery-window <ms>] [--idle-timeout <ms>] [--job-timeout <ms>] [--poll-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]');
|
|
9338
9437
|
console.log(' c8ctl nano supervisor [start|status|add|remove|restart|stop|logs|attach] ... (manage many workers from one terminal)');
|
|
9339
9438
|
console.log('');
|
|
9340
9439
|
console.log('Subcommands:');
|
|
@@ -9377,9 +9476,10 @@ function printUsage() {
|
|
|
9377
9476
|
console.log(' --sandbox <s> hire/work: execution sandbox none|docker|podman (default none)');
|
|
9378
9477
|
console.log(' --image <ref> hire/work: container image the agent runs in (required for docker|podman)');
|
|
9379
9478
|
console.log(' --terminal <m> hire: live-terminal mode pty|pipe (default pipe); pty streams a steerable terminal on the relay lane');
|
|
9479
|
+
console.log(' --protocol <p> hire: harness protocol pipe|acp (default pipe); acp is RESERVED — accepted/persisted but not yet implemented in this build (inert: the harness still runs on the transport selected by --terminal, pipe or pty). NANO_AGENTIC_PROTOCOL overrides at work time');
|
|
9480
|
+
console.log(' --permission <p> hire: ACP permission policy yolo|escalate|filter (default yolo); yolo auto-allows all requests. escalate|filter are RESERVED/not-yet-active (pending nano-workforce#559) — persisted but not enforced, effectively behave like yolo (auto-allow). NANO_AGENTIC_PERMISSION overrides at work time');
|
|
9380
9481
|
console.log(' --env NAME=VALUE hire/work: static env var for the harness (repeatable); persisted on hire, work extends/overrides');
|
|
9381
9482
|
console.log(' --list hire: list existing agent profiles instead of creating one');
|
|
9382
|
-
console.log(' --max-parallel <n> work: max concurrent jobs per worker (default 1)');
|
|
9383
9483
|
console.log(' --job-type <token> work: extra job type to service alongside the rank×capability matrix (repeatable)');
|
|
9384
9484
|
console.log(' --auto work: zero-config enrolment — serve ALL deployed agent job types read from the engine (no capability, no app enrol endpoint, no channel). NO capability gate: serves any deployed agent job on the engine.');
|
|
9385
9485
|
console.log(' --auto-scope <p> work: with --auto, narrow to agent job types whose bpmn:process id equals or is prefixed by <p> (one app/network); default all');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.40.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.40.0",
|
|
61
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.40.0",
|
|
62
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.40.0",
|
|
63
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.40.0",
|
|
64
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.40.0",
|
|
65
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.40.0",
|
|
66
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.40.0"
|
|
67
67
|
}
|
|
68
68
|
}
|