@ours.network/fleet 1.1.0-nightly.2 → 1.1.0-nightly.21
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 +204 -55
- package/dist/agent-recovery-gate.d.ts +17 -0
- package/dist/agent-recovery-gate.js +135 -0
- package/dist/application/capabilities.js +18 -6
- package/dist/application/fleet-query-service.js +20 -5
- package/dist/application/role-command-service.js +9 -0
- package/dist/application/role-creation-service.d.ts +6 -25
- package/dist/application/role-creation-service.js +34 -72
- package/dist/application/role-repository.d.ts +4 -2
- package/dist/application/role-repository.js +6 -3
- package/dist/application/session-control.d.ts +3 -1
- package/dist/application/session-control.js +4 -2
- package/dist/application/task-room-service.d.ts +58 -6
- package/dist/application/task-room-service.js +435 -79
- package/dist/briefing.js +74 -24
- package/dist/build-info.json +4 -4
- package/dist/canonical-json.d.ts +2 -0
- package/dist/canonical-json.js +10 -0
- package/dist/cli.js +241 -76
- package/dist/config-yaml.d.ts +1 -1
- package/dist/config.d.ts +75 -3
- package/dist/config.js +274 -34
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +3 -2
- package/dist/daemon-recovery.d.ts +93 -0
- package/dist/daemon-recovery.js +328 -0
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +192 -66
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +54 -4
- package/dist/fleet-command-audit.d.ts +165 -0
- package/dist/fleet-command-audit.js +555 -0
- package/dist/fleet-proxy.d.ts +7 -2
- package/dist/fleet-proxy.js +30 -8
- package/dist/harness/agent-session.d.ts +5 -0
- package/dist/harness/claude-code-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +6 -1
- package/dist/harness/claude-code.js +2 -0
- package/dist/harness/codex-app-server-proxy.d.ts +40 -0
- package/dist/harness/codex-app-server-proxy.js +348 -14
- package/dist/harness/codex-session.d.ts +11 -2
- package/dist/harness/codex-session.js +22 -2
- package/dist/harness/codex.d.ts +5 -1
- package/dist/harness/codex.js +110 -10
- package/dist/harness/types.d.ts +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/init-guidance.d.ts +1 -1
- package/dist/init-guidance.js +4 -3
- package/dist/init-wizard.d.ts +98 -0
- package/dist/init-wizard.js +629 -0
- package/dist/lifecycle-summary.d.ts +134 -0
- package/dist/lifecycle-summary.js +179 -0
- package/dist/loops/config.d.ts +10 -1
- package/dist/loops/config.js +38 -5
- package/dist/model-env.d.ts +2 -2
- package/dist/model-env.js +1 -1
- package/dist/model-recovery.d.ts +1 -1
- package/dist/ops.js +2 -17
- package/dist/owner-channel/channel.d.ts +58 -0
- package/dist/owner-channel/channel.js +321 -42
- package/dist/owner-channel/commands.d.ts +6 -1
- package/dist/owner-channel/commands.js +34 -19
- package/dist/owner-channel/state.d.ts +2 -0
- package/dist/owner-channel/state.js +8 -2
- package/dist/permissions.js +1 -1
- package/dist/preset-bootstrap.d.ts +10 -0
- package/dist/preset-bootstrap.js +85 -0
- package/dist/preset-migration.d.ts +42 -0
- package/dist/preset-migration.js +414 -0
- package/dist/reports/artifact.d.ts +10 -0
- package/dist/reports/artifact.js +32 -0
- package/dist/reports/index.d.ts +5 -0
- package/dist/reports/index.js +5 -0
- package/dist/reports/render.d.ts +6 -0
- package/dist/reports/render.js +240 -0
- package/dist/reports/service.d.ts +42 -0
- package/dist/reports/service.js +57 -0
- package/dist/reports/tasks.d.ts +52 -0
- package/dist/reports/tasks.js +177 -0
- package/dist/reports/types.d.ts +315 -0
- package/dist/reports/types.js +6 -0
- package/dist/resolved-plan.js +13 -1
- package/dist/rooms-tasks/cli.d.ts +2 -0
- package/dist/rooms-tasks/cli.js +514 -75
- package/dist/rooms-tasks/close.d.ts +9 -1
- package/dist/rooms-tasks/close.js +20 -4
- package/dist/rooms-tasks/config.js +16 -14
- package/dist/rooms-tasks/cowork-adapter.d.ts +1 -0
- package/dist/rooms-tasks/cowork-adapter.js +6 -0
- package/dist/rooms-tasks/deletion.d.ts +51 -0
- package/dist/rooms-tasks/deletion.js +217 -0
- package/dist/rooms-tasks/external-worker.d.ts +1 -0
- package/dist/rooms-tasks/external-worker.js +14 -9
- package/dist/rooms-tasks/launch-snapshot.d.ts +19 -0
- package/dist/rooms-tasks/launch-snapshot.js +181 -0
- package/dist/rooms-tasks/member-overrides.d.ts +30 -0
- package/dist/rooms-tasks/member-overrides.js +204 -0
- package/dist/rooms-tasks/provision.js +184 -49
- package/dist/rooms-tasks/room-state.d.ts +1 -0
- package/dist/rooms-tasks/room-state.js +12 -1
- package/dist/rooms-tasks/task-state.d.ts +115 -3
- package/dist/rooms-tasks/task-state.js +361 -11
- package/dist/rooms-tasks/templates.d.ts +4 -2
- package/dist/rooms-tasks/templates.js +42 -78
- package/dist/rooms-tasks/terminal.d.ts +3 -0
- package/dist/rooms-tasks/terminal.js +7 -3
- package/dist/rooms-tasks/types.d.ts +96 -17
- package/dist/rooms-tasks/types.js +14 -4
- package/dist/runner.d.ts +12 -2
- package/dist/runner.js +124 -43
- package/dist/session/acp.d.ts +9 -1
- package/dist/session/acp.js +35 -9
- package/dist/session/arbiter.d.ts +2 -1
- package/dist/session/arbiter.js +2 -0
- package/dist/session/codex-app-server-transport.d.ts +53 -0
- package/dist/session/codex-app-server-transport.js +184 -0
- package/dist/session/codex-app-server.d.ts +122 -0
- package/dist/session/codex-app-server.js +1031 -0
- package/dist/session/control.d.ts +14 -1
- package/dist/session/control.js +38 -0
- package/dist/session/conversation-types.d.ts +4 -4
- package/dist/session/types.d.ts +24 -6
- package/dist/session/types.js +28 -0
- package/dist/spawn.d.ts +15 -31
- package/dist/spawn.js +117 -237
- package/dist/temp-lifecycle.d.ts +1 -1
- package/dist/watchdog/config.d.ts +10 -7
- package/dist/watchdog/config.js +29 -19
- package/dist/watchdog/run.js +4 -13
- package/dist/web/fleet-config-service.d.ts +1 -0
- package/dist/web/fleet-config-service.js +27 -8
- package/dist/web/runtime.js +11 -6
- package/dist/web/server.js +28 -1
- package/dist/web/topology-promote.js +8 -1
- package/dist/web-app/assets/index-C0h3ALvs.js +10 -0
- package/dist/web-app/index.html +1 -1
- package/package.json +3 -2
- package/presets/brain-catalog.json +16 -0
- package/presets/fleet/agent_templates/Critic.yaml +4 -0
- package/presets/fleet/agent_templates/Developer.yaml +4 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -0
- package/presets/fleet/agents/FleetCoordinator.yaml +3 -0
- package/presets/fleet/brains/claude-default.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +30 -0
- package/presets/fleet/roles/Critic.yaml +19 -0
- package/presets/fleet/roles/Developer.yaml +19 -0
- package/presets/fleet/roles/LocalCoordinator.yaml +25 -0
- package/presets/fleet/room_templates/pair.yaml +10 -0
- package/presets/fleet/room_templates/single.yaml +7 -0
- package/presets/fleet/room_templates/team.yaml +12 -0
- package/presets/fleet.yaml +7 -0
- package/presets/manifest.json +6 -0
- package/dist/web-app/assets/index-BbE9EX6n.js +0 -10
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn as spawnChild } from 'node:child_process';
|
|
3
|
-
import {
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from 'node:fs';
|
|
4
5
|
import { realpathSync } from 'node:fs';
|
|
5
6
|
import { join as joinPath, resolve as resolvePath } from 'node:path';
|
|
6
7
|
import { createInterface } from 'node:readline';
|
|
7
8
|
import { Command } from 'commander';
|
|
8
9
|
import { VERSION } from './version.js';
|
|
9
10
|
import { INIT_COMPLETION_GUIDANCE } from './init-guidance.js';
|
|
11
|
+
import { migrateLegacyStarterPresets, migratePackagedRoleDefaults } from './preset-migration.js';
|
|
12
|
+
import { executeInitWizard, isInteractiveTerminal, publishSetup, TerminalPrompter, } from './init-wizard.js';
|
|
10
13
|
import { analyzeInstalls, buildInfo, buildLabel, discoverInstalls, runningLabel, } from './provenance.js';
|
|
11
|
-
import { agentDir, agentsRoot, tmpRoot, logsRoot, deriveXdgRuntimeDir } from './paths.js';
|
|
12
|
-
import { findRole, loadConfig } from './config.js';
|
|
14
|
+
import { agentDir, agentsRoot, tmpRoot, logsRoot, deriveXdgRuntimeDir, defaultConfigPath } from './paths.js';
|
|
15
|
+
import { findRole, loadConfig, ROLE_NAME_RE } from './config.js';
|
|
13
16
|
import { formatDuration } from './duration.js';
|
|
14
|
-
import { redactSensitive, resolvedPlan } from './resolved-plan.js';
|
|
17
|
+
import { redactSensitive, resolvedPlan, resolvedRolePlan } from './resolved-plan.js';
|
|
15
18
|
import { pickBackend } from './supervisor/index.js';
|
|
16
19
|
import { up, down } from './ops.js';
|
|
17
20
|
import { readRestartLedger, runSupervised, runTemp } from './runner.js';
|
|
@@ -23,11 +26,11 @@ import { acquireRunLock, latestReport, listRuns, readReport, releaseRunLock, rep
|
|
|
23
26
|
import { watchdogAddressable } from './watchdog/query.js';
|
|
24
27
|
import { lastProvenance } from './spawn.js';
|
|
25
28
|
import { stringify } from 'yaml';
|
|
26
|
-
import { resolvedRolePlan } from './resolved-plan.js';
|
|
27
29
|
import { creationBuildNote, formatProvenance, readProvenance } from './creation.js';
|
|
28
30
|
import { doctor } from './doctor.js';
|
|
29
31
|
import { allWarnings, analyzeFleetPermissions, effectivePermissionMode, formatNative, } from './permissions.js';
|
|
30
32
|
import { AI_DOCS } from './docs.js';
|
|
33
|
+
import { renderAgentConfiguration, selectionOrigin, summarizeResolvedLaunch } from './lifecycle-summary.js';
|
|
31
34
|
import { classifyActivity, describeSessionState } from './session/activity.js';
|
|
32
35
|
import { controlRequest, controlSocketPath, followControl, livenessNote, } from './session/control.js';
|
|
33
36
|
import { SessionControlError } from './session/types.js';
|
|
@@ -37,6 +40,7 @@ import { requestWebControl } from './web/control.js';
|
|
|
37
40
|
import { WebServiceManager } from './web/service.js';
|
|
38
41
|
import { WebAccessStore, passwordAccess, validatePublicOrigin } from './web/access.js';
|
|
39
42
|
import { FLEET_PROXY_CALLER_ENV, FLEET_PROXY_STATE_DIR_ENV, } from './fleet-proxy.js';
|
|
43
|
+
import { beginFleetAuditCollection, consumeFleetAuditCollection, FleetCliExit, } from './fleet-command-audit.js';
|
|
40
44
|
import './harness/claude-code.js'; // registers the claude-code adapter
|
|
41
45
|
import './harness/codex.js'; // registers the codex adapter
|
|
42
46
|
import { registerTemplateCommands, registerTaskCommands, registerRoomCommands } from './rooms-tasks/cli.js';
|
|
@@ -66,7 +70,10 @@ const roleLifecycle = (configPath, operationDeps) => {
|
|
|
66
70
|
return new RoleLifecycleService({ repository, ops: operationDeps, configPath,
|
|
67
71
|
status: async (roleId) => (await query.detail(roleId)).status });
|
|
68
72
|
};
|
|
69
|
-
const die = (e) => {
|
|
73
|
+
const die = (e) => {
|
|
74
|
+
console.error(String(e instanceof Error ? e.message : e));
|
|
75
|
+
throw new FleetCliExit(1);
|
|
76
|
+
};
|
|
70
77
|
/** Exec a child with our stdio (logs/attach). */
|
|
71
78
|
const passthrough = (cmd, args) => new Promise(resolve => {
|
|
72
79
|
const c = spawnChild(cmd, args, { stdio: 'inherit' });
|
|
@@ -74,8 +81,9 @@ const passthrough = (cmd, args) => new Promise(resolve => {
|
|
|
74
81
|
});
|
|
75
82
|
const program = new Command()
|
|
76
83
|
.name('ours-fleet')
|
|
77
|
-
.description('Fleet of persistent, identity-bound AI agents
|
|
84
|
+
.description('Fleet of persistent, identity-bound AI agents over provider-neutral managed sessions.')
|
|
78
85
|
.enablePositionalOptions()
|
|
86
|
+
.exitOverride()
|
|
79
87
|
.version(VERSION);
|
|
80
88
|
const cOpt = (cmd) => cmd.option('-c, --configuration <file>', 'manifest (default: ~/fleet.yaml; documents under ~/fleet/)');
|
|
81
89
|
const collect = (value, previous) => [...previous, value];
|
|
@@ -144,8 +152,8 @@ const MAX_INVITE_BYTES = 48 * 1024;
|
|
|
144
152
|
const MAX_OWNER_UPDATE_BYTES = 1_024;
|
|
145
153
|
function ownerChannelStateDir(roleName, configuration) {
|
|
146
154
|
const role = findRole(loadConfig(configuration), roleName);
|
|
147
|
-
if (role.session !== 'acp')
|
|
148
|
-
throw new Error(`role '${roleName}' uses session '${role.session}', but owner-channel management requires
|
|
155
|
+
if (role.session !== 'acp' && role.session !== 'codex-app-server')
|
|
156
|
+
throw new Error(`role '${roleName}' uses session '${role.session}', but owner-channel management requires managed control`);
|
|
149
157
|
if (!role.owner_channel)
|
|
150
158
|
throw new Error(`role '${roleName}' has no owner_channel configured`);
|
|
151
159
|
const stateDir = acpStateDir(roleName);
|
|
@@ -218,6 +226,24 @@ function parseCodexConfig(values) {
|
|
|
218
226
|
}
|
|
219
227
|
return out;
|
|
220
228
|
}
|
|
229
|
+
function parseAgentSelection(raw, kind) {
|
|
230
|
+
if (raw === undefined)
|
|
231
|
+
return undefined;
|
|
232
|
+
if (ROLE_NAME_RE.test(raw))
|
|
233
|
+
return { ref: raw };
|
|
234
|
+
if (!raw.startsWith('inline:'))
|
|
235
|
+
throw new Error(`invalid --${kind}; use a declared ID or inline:{...}`);
|
|
236
|
+
let value;
|
|
237
|
+
try {
|
|
238
|
+
value = JSON.parse(raw.slice('inline:'.length));
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
throw new Error(`invalid --${kind} inline mapping`);
|
|
242
|
+
}
|
|
243
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
244
|
+
throw new Error(`invalid --${kind} inline mapping`);
|
|
245
|
+
return { inline: value };
|
|
246
|
+
}
|
|
221
247
|
cOpt(program.command('config').description('validate + print the merged plan (no side effects)'))
|
|
222
248
|
.option('--json', 'emit the stable, versioned, secret-safe resolved plan')
|
|
223
249
|
.option('--yaml-mode <mode>', 'non-plain YAML policy: compat|strict', 'compat')
|
|
@@ -369,29 +395,26 @@ cOpt(program.command('force-restart [names...]').description('re-sync + bounce F
|
|
|
369
395
|
die(e);
|
|
370
396
|
}
|
|
371
397
|
});
|
|
372
|
-
program.command('ls').description('list running
|
|
373
|
-
.action(async () => {
|
|
398
|
+
cOpt(program.command('ls').description('list running declared persistent Agent sessions'))
|
|
399
|
+
.action(async (opts) => {
|
|
374
400
|
const acp = [];
|
|
375
|
-
|
|
376
|
-
|
|
401
|
+
const cfg = loadConfig(opts.configuration);
|
|
402
|
+
for (const { name } of cfg.roles) {
|
|
403
|
+
const stateDir = agentDir(name);
|
|
404
|
+
if (!existsSync(controlSocketPath(stateDir)))
|
|
377
405
|
continue;
|
|
378
|
-
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
// steered wake turn (FLEET-002), so `ls` reports what was observed.
|
|
388
|
-
const observed = classifyActivity(result.activity);
|
|
389
|
-
acp.push(`${name}: acp${observed.state === 'active' ? ' (working)'
|
|
390
|
-
: observed.state === 'quiet' ? ' (no recent agent activity)' : ''}`);
|
|
391
|
-
}
|
|
406
|
+
try {
|
|
407
|
+
const response = await controlRequest(stateDir, { command: 'status' }, 2_000);
|
|
408
|
+
const result = response.result;
|
|
409
|
+
if (response.ok && result?.alive) {
|
|
410
|
+
// Activity, not readiness: an idle-readiness role may be running a
|
|
411
|
+
// steered wake turn (FLEET-002), so `ls` reports what was observed.
|
|
412
|
+
const observed = classifyActivity(result.activity);
|
|
413
|
+
acp.push(`${name}: acp${observed.state === 'active' ? ' (working)'
|
|
414
|
+
: observed.state === 'quiet' ? ' (no recent agent activity)' : ''}`);
|
|
392
415
|
}
|
|
393
|
-
catch { /* ignore stale sockets */ }
|
|
394
416
|
}
|
|
417
|
+
catch { /* ignore stale sockets */ }
|
|
395
418
|
}
|
|
396
419
|
console.log(acp.join('\n') || '(none)');
|
|
397
420
|
});
|
|
@@ -501,8 +524,9 @@ program.command('logs <name>').description('show the role log').option('-f, --fo
|
|
|
501
524
|
const { cmd, args } = pickBackend().logsArgs(name, opts.follow === true);
|
|
502
525
|
process.exit(await passthrough(cmd, args));
|
|
503
526
|
});
|
|
504
|
-
program.command('status <name>').description('unit/
|
|
505
|
-
.action(async (name) => {
|
|
527
|
+
cOpt(program.command('status <name>').description('declared persistent Agent unit/session state'))
|
|
528
|
+
.action(async (name, opts) => {
|
|
529
|
+
findRole(loadConfig(opts.configuration), name);
|
|
506
530
|
console.log(await pickBackend().status(name));
|
|
507
531
|
// A role outlives the artifact that created it. If a different build is
|
|
508
532
|
// reporting now, its settings may resolve differently than at creation.
|
|
@@ -556,7 +580,7 @@ program.command('status <name>').description('unit/agent state')
|
|
|
556
580
|
}
|
|
557
581
|
}
|
|
558
582
|
catch {
|
|
559
|
-
console.log('session
|
|
583
|
+
console.log('managed session control unavailable');
|
|
560
584
|
}
|
|
561
585
|
}
|
|
562
586
|
// Loop health is asked of the live manager first: when its state writes are
|
|
@@ -712,13 +736,13 @@ cOpt(loopsCommand.command('status [role] [loop]').description('show live or stor
|
|
|
712
736
|
loopFailure(error, opts.json === true);
|
|
713
737
|
}
|
|
714
738
|
});
|
|
715
|
-
cOpt(loopsCommand.command('reload <role>').description('reload trusted scheduled-loop config in a live
|
|
739
|
+
cOpt(loopsCommand.command('reload <role>').description('reload trusted scheduled-loop config in a live managed role'))
|
|
716
740
|
.option('--json', 'emit stable JSON')
|
|
717
741
|
.action(async (roleName, opts) => {
|
|
718
742
|
try {
|
|
719
743
|
const { role } = selectLoopConfig(opts.configuration, roleName);
|
|
720
|
-
if (role.session !== 'acp')
|
|
721
|
-
throw new Error(`role '${roleName}'
|
|
744
|
+
if (role.session !== 'acp' && role.session !== 'codex-app-server')
|
|
745
|
+
throw new Error(`role '${roleName}' has no managed session control`);
|
|
722
746
|
const stateDir = permanentLoopControlDir(roleName);
|
|
723
747
|
if (!stateDir)
|
|
724
748
|
throw new SessionControlError('control-unavailable', `role '${roleName}' has no live authenticated ACP control socket`);
|
|
@@ -743,8 +767,8 @@ for (const command of ['run-now', 'disable', 'enable']) {
|
|
|
743
767
|
.action(async (roleName, loopName, opts) => {
|
|
744
768
|
try {
|
|
745
769
|
const { role, definitions } = selectLoopConfig(opts.configuration, roleName, loopName);
|
|
746
|
-
if (role.session !== 'acp')
|
|
747
|
-
throw new Error(`role '${roleName}'
|
|
770
|
+
if (role.session !== 'acp' && role.session !== 'codex-app-server')
|
|
771
|
+
throw new Error(`role '${roleName}' has no managed session control`);
|
|
748
772
|
const definition = definitions.find(loop => loop.name === loopName);
|
|
749
773
|
if (command === 'enable' && !definition.enabled)
|
|
750
774
|
throw new Error(`loop '${loopName}' is disabled in YAML; edit the config before enabling it`);
|
|
@@ -1112,51 +1136,37 @@ cOpt(program.command('rm <name>').description('stop + remove a role (temporary e
|
|
|
1112
1136
|
}
|
|
1113
1137
|
});
|
|
1114
1138
|
cOpt(program.command('spawn [name]').description('spawn a new agent (permanent by default)'))
|
|
1115
|
-
.option('--
|
|
1139
|
+
.option('--name <name>', 'agent name (alternative to the positional name)')
|
|
1140
|
+
.option('--brain <selection>', 'Brain ID or inline:{...} definition')
|
|
1141
|
+
.option('--role <selection>', 'Role ID or inline:{...} definition')
|
|
1116
1142
|
.option('--temp', 'temporary: independent transient supervisor, archived on retirement, gone on reboot')
|
|
1117
|
-
.option('--
|
|
1118
|
-
.option('--session <backend>', 'session backend: acp (default: acp)')
|
|
1119
|
-
.option('--mission <text>', 'one-line mission')
|
|
1120
|
-
.option('--mission-file <path>', 'UTF-8 mission text (mutually exclusive with --mission)')
|
|
1121
|
-
.option('--identity <name>', 'ours identity to bind (default: role name)')
|
|
1143
|
+
.option('--identity <name>', 'ours identity to bind (default: Agent name)')
|
|
1122
1144
|
.option('--cwd <dir>', 'working directory')
|
|
1123
1145
|
.option('--coordinator <name>', 'announce target')
|
|
1124
|
-
.option('--model <id>', 'model id to launch on (e.g. claude-fable-5); default: launcher default')
|
|
1125
|
-
.option('--permission-mode <mode>', 'harness permission mode (Codex: untrusted|on-request|never; Claude: native values)')
|
|
1126
1146
|
.option('--approval <mode>', 'fleet permission mode: ask|auto|allow (Codex ACP allow selects agent-full-access; deny is deprecated)')
|
|
1127
1147
|
.option('--filesystem <mode>', 'common filesystem intent: read-only|workspace|unrestricted')
|
|
1128
1148
|
.option('--unattended <mode>', 'permission behavior without a console: deny|wait')
|
|
1129
|
-
.option('--sandbox <mode>', 'Codex sandbox: read-only|workspace-write|danger-full-access')
|
|
1130
|
-
.option('--profile <name>', 'Codex profile file name ($CODEX_HOME/<name>.config.toml)')
|
|
1131
|
-
.option('--launcher <mode>', 'Codex launcher: auto|ours-codex|codex (default: auto)')
|
|
1132
|
-
.option('--search', 'enable Codex live web search')
|
|
1133
|
-
.option('--codex-config <key=value>', 'Codex config override (repeatable)', collect, [])
|
|
1134
|
-
.option('--add-dir <dir>', 'additional Codex writable directory (repeatable)', collect, [])
|
|
1135
|
-
.option('--monitor', 'legacy: consent to arm Codex\'s native monitor (wake owner is monitor.mode in YAML)')
|
|
1136
|
-
.option('--bio-file <file>', 'public bio (file)')
|
|
1137
|
-
.option('--persona-file <file>', 'persona / operating contract (file)')
|
|
1138
1149
|
.option('--isolation-file <path>', 'file holding an isolation: mapping (same schema as fleet.yaml)')
|
|
1150
|
+
.option('--loops-file <path>', 'owner-only YAML containing exactly loops: for this temporary agent')
|
|
1151
|
+
.option('--no-loops', 'explicitly disable temporary-agent loops')
|
|
1139
1152
|
.option('--dry-run', 'validate and print without reserving or creating anything')
|
|
1140
1153
|
.option('--json', 'with --dry-run, emit a stable secret-safe JSON result')
|
|
1141
1154
|
.action(async (name, opts) => {
|
|
1142
1155
|
try {
|
|
1143
|
-
const roleName = String(name ?? opts.
|
|
1156
|
+
const roleName = String(name ?? opts.name ?? '');
|
|
1144
1157
|
if (!roleName)
|
|
1145
|
-
throw new Error('
|
|
1146
|
-
if (name && opts.
|
|
1147
|
-
throw new Error(`positional
|
|
1158
|
+
throw new Error('agent name is required (positional or --name)');
|
|
1159
|
+
if (name && opts.name && name !== opts.name)
|
|
1160
|
+
throw new Error(`positional agent name conflicts with --name`);
|
|
1148
1161
|
const o = {
|
|
1149
|
-
name: roleName, temp: opts.temp,
|
|
1150
|
-
|
|
1162
|
+
name: roleName, temp: opts.temp,
|
|
1163
|
+
brain: parseAgentSelection(opts.brain, 'brain'), role: parseAgentSelection(opts.role, 'role'),
|
|
1151
1164
|
identity: opts.identity, cwd: opts.cwd, coordinator: opts.coordinator,
|
|
1152
|
-
|
|
1153
|
-
permissionMode: opts.permissionMode, approval: opts.approval,
|
|
1165
|
+
approval: opts.approval,
|
|
1154
1166
|
filesystem: opts.filesystem, unattended: opts.unattended,
|
|
1155
|
-
sandbox: opts.sandbox, profile: opts.profile,
|
|
1156
|
-
launcher: opts.launcher, search: opts.search,
|
|
1157
|
-
codexConfig: parseCodexConfig(opts.codexConfig), addDirs: opts.addDir, monitor: opts.monitor,
|
|
1158
|
-
bioFile: opts.bioFile, personaFile: opts.personaFile,
|
|
1159
1167
|
isolationFile: opts.isolationFile, configPath: opts.configuration,
|
|
1168
|
+
loopsFile: opts.loopsFile, noLoops: opts.loops === false,
|
|
1169
|
+
loopSource: opts.loopsFile || opts.loops === false ? 'cli' : 'omitted',
|
|
1160
1170
|
dryRun: opts.dryRun, json: opts.json,
|
|
1161
1171
|
};
|
|
1162
1172
|
if (o.json && !o.dryRun)
|
|
@@ -1170,7 +1180,7 @@ cOpt(program.command('spawn [name]').description('spawn a new agent (permanent b
|
|
|
1170
1180
|
process.stdout.write(`${JSON.stringify({
|
|
1171
1181
|
schemaVersion: result.schemaVersion,
|
|
1172
1182
|
warning: result.warning,
|
|
1173
|
-
roleDocument: result.roleDocument,
|
|
1183
|
+
roleDocument: redactSensitive(result.roleDocument),
|
|
1174
1184
|
resolvedRole: resolvedRolePlan(result.resolvedRole),
|
|
1175
1185
|
}, null, 2)}\n`);
|
|
1176
1186
|
}
|
|
@@ -1184,7 +1194,7 @@ cOpt(program.command('spawn [name]').description('spawn a new agent (permanent b
|
|
|
1184
1194
|
if (proxyStateDir) {
|
|
1185
1195
|
// Paths entered in the agent shell belong to that shell's cwd, not the
|
|
1186
1196
|
// supervisor process. Normalize before crossing the control boundary.
|
|
1187
|
-
for (const key of ['
|
|
1197
|
+
for (const key of ['isolationFile', 'loopsFile']) {
|
|
1188
1198
|
if (o[key])
|
|
1189
1199
|
o[key] = resolvePath(o[key]);
|
|
1190
1200
|
}
|
|
@@ -1205,6 +1215,8 @@ cOpt(program.command('spawn [name]').description('spawn a new agent (permanent b
|
|
|
1205
1215
|
+ `monitor=${result.monitor.mode} interrupt=${result.monitor.interrupt}`);
|
|
1206
1216
|
if (result.inherited.length)
|
|
1207
1217
|
console.log(` inherited omitted defaults from ${result.caller}: ${result.inherited.join(', ')}`);
|
|
1218
|
+
if (result.configuration)
|
|
1219
|
+
console.log(` ${renderAgentConfiguration(result.configuration)}`);
|
|
1208
1220
|
console.log(`→ watch it: ours-fleet peek ${result.role} | attach: ours-fleet attach ${result.role}`);
|
|
1209
1221
|
return;
|
|
1210
1222
|
}
|
|
@@ -1229,6 +1241,11 @@ cOpt(program.command('spawn [name]').description('spawn a new agent (permanent b
|
|
|
1229
1241
|
}
|
|
1230
1242
|
console.log(` permission=${plannedPermissionMode.fleetMode} `
|
|
1231
1243
|
+ `native=${plannedPermissionMode.nativeMode}`);
|
|
1244
|
+
console.log(` ${renderAgentConfiguration(summarizeResolvedLaunch(created.plan.preview.resolvedRole, {
|
|
1245
|
+
role: selectionOrigin(o.role ?? o.agentDefinition?.role),
|
|
1246
|
+
brain: selectionOrigin(o.brain ?? o.agentDefinition?.brain),
|
|
1247
|
+
permissionMode: plannedPermissionMode,
|
|
1248
|
+
}))}`);
|
|
1232
1249
|
console.log(`→ watch it: ours-fleet peek ${roleName} | attach: ours-fleet attach ${roleName}`);
|
|
1233
1250
|
}
|
|
1234
1251
|
catch (e) {
|
|
@@ -1248,15 +1265,83 @@ cOpt(program.command('doctor').description('prerequisite report'))
|
|
|
1248
1265
|
});
|
|
1249
1266
|
for (const c of rep.checks)
|
|
1250
1267
|
console.log(`${c.ok ? 'ok ' : 'MISS'} ${c.name.padEnd(22)} ${c.detail}`);
|
|
1251
|
-
|
|
1268
|
+
if (!rep.ok)
|
|
1269
|
+
throw new FleetCliExit(1);
|
|
1252
1270
|
});
|
|
1253
|
-
program.command('init').description('
|
|
1254
|
-
.action(async () => {
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1271
|
+
cOpt(program.command('init').description('interactively add missing Fleet defaults while preserving existing configuration'))
|
|
1272
|
+
.action(async (opts) => {
|
|
1273
|
+
const configuration = opts.configuration ?? defaultConfigPath();
|
|
1274
|
+
if (!isInteractiveTerminal(process.stdin, process.stdout))
|
|
1275
|
+
die('ours-fleet init requires an interactive terminal; no host setup ran and no configuration changed');
|
|
1276
|
+
try {
|
|
1277
|
+
const result = await executeInitWizard(new TerminalPrompter(process.stdin, process.stdout), configuration, {
|
|
1278
|
+
async hostSetup() {
|
|
1279
|
+
for (const d of [agentsRoot(), tmpRoot(), logsRoot()])
|
|
1280
|
+
mkdirSync(d, { recursive: true });
|
|
1281
|
+
for (const message of await pickBackend().init(binPath))
|
|
1282
|
+
console.log(message);
|
|
1283
|
+
},
|
|
1284
|
+
publish: publishSetup,
|
|
1285
|
+
});
|
|
1286
|
+
if (!result) {
|
|
1287
|
+
console.log('Fleet setup cancelled. No host setup ran and no configuration changed.');
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
const prior = result.manifestExisted && result.rootExisted ? 'manifest and split configuration'
|
|
1291
|
+
: result.manifestExisted ? 'manifest only'
|
|
1292
|
+
: result.rootExisted ? 'split configuration only' : 'no previous targets';
|
|
1293
|
+
console.log(`${result.replacedExisting ? 'Preserved existing files and added missing defaults to' : 'Created'} Fleet setup: ${result.configPath} and ${result.splitRoot}`);
|
|
1294
|
+
console.log(`Previous targets: ${prior}.`);
|
|
1295
|
+
console.log(`Private recovery record: ${result.recoveryPath}`);
|
|
1296
|
+
console.log(INIT_COMPLETION_GUIDANCE);
|
|
1297
|
+
}
|
|
1298
|
+
catch (error) {
|
|
1299
|
+
die(error);
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
cOpt(program.command('migrate-agent-templates')
|
|
1303
|
+
.description('dry-run the exact legacy starter split; add --write to apply atomically')
|
|
1304
|
+
.option('--write', 'apply the reviewed migration and retain a private recovery backup'))
|
|
1305
|
+
.action((opts) => {
|
|
1306
|
+
try {
|
|
1307
|
+
const result = migrateLegacyStarterPresets(opts.configuration ?? defaultConfigPath(), { write: opts.write });
|
|
1308
|
+
console.log(result.write ? 'Applied legacy starter migration.' : 'Dry run only; no files were changed.');
|
|
1309
|
+
for (const move of result.moves)
|
|
1310
|
+
console.log(`Move ${move.from} -> ${move.to}`);
|
|
1311
|
+
for (const addition of result.additions)
|
|
1312
|
+
console.log(`Add ${addition}`);
|
|
1313
|
+
console.log(`Staging path: ${result.stagingPath}`);
|
|
1314
|
+
console.log(`Recovery backup: ${result.backupPath}`);
|
|
1315
|
+
if (!result.write)
|
|
1316
|
+
console.log('Re-run with --write to apply this exact migration class.');
|
|
1317
|
+
}
|
|
1318
|
+
catch (error) {
|
|
1319
|
+
die(error);
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
cOpt(program.command('migrate-role-defaults')
|
|
1323
|
+
.description('dry-run adoption of exact revision-3 role defaults; add --write to apply atomically')
|
|
1324
|
+
.option('--write', 'apply the reviewed migration and retain a private recovery backup'))
|
|
1325
|
+
.action((opts) => {
|
|
1326
|
+
try {
|
|
1327
|
+
const result = migratePackagedRoleDefaults(opts.configuration ?? defaultConfigPath(), { write: opts.write });
|
|
1328
|
+
console.log(result.write ? 'Applied packaged role-default migration.' : 'Dry run only; no files were changed.');
|
|
1329
|
+
for (const path of result.removals)
|
|
1330
|
+
console.log(`Remove ${path}`);
|
|
1331
|
+
for (const path of result.replacements)
|
|
1332
|
+
console.log(`Replace ${path}`);
|
|
1333
|
+
for (const path of result.additions)
|
|
1334
|
+
console.log(`Add ${path}`);
|
|
1335
|
+
for (const path of result.preserved)
|
|
1336
|
+
console.log(`Preserve customized ${path}`);
|
|
1337
|
+
console.log(`Staging path: ${result.stagingPath}`);
|
|
1338
|
+
console.log(`Recovery backup: ${result.backupPath}`);
|
|
1339
|
+
if (!result.write)
|
|
1340
|
+
console.log('Re-run with --write to adopt only these exact recognized defaults.');
|
|
1341
|
+
}
|
|
1342
|
+
catch (error) {
|
|
1343
|
+
die(error);
|
|
1344
|
+
}
|
|
1260
1345
|
});
|
|
1261
1346
|
const webCommand = cOpt(program.command('web').description('start or open the secure localhost fleet web console'))
|
|
1262
1347
|
.enablePositionalOptions()
|
|
@@ -1497,4 +1582,84 @@ cOpt(program.command('_run-watchdogs', { hidden: true }))
|
|
|
1497
1582
|
die(e);
|
|
1498
1583
|
}
|
|
1499
1584
|
});
|
|
1500
|
-
|
|
1585
|
+
async function parseFleetCli() {
|
|
1586
|
+
const spawnIndex = process.argv.indexOf('spawn');
|
|
1587
|
+
if (spawnIndex >= 0 && process.argv.slice(spawnIndex + 1).some(arg => arg === '--harness' || arg.startsWith('--harness=') || arg === '--model' || arg.startsWith('--model='))) {
|
|
1588
|
+
console.error('error: --harness and --model were removed; select a Brain with --brain');
|
|
1589
|
+
throw new FleetCliExit(1);
|
|
1590
|
+
}
|
|
1591
|
+
try {
|
|
1592
|
+
await program.parseAsync(process.argv);
|
|
1593
|
+
}
|
|
1594
|
+
catch (error) {
|
|
1595
|
+
const commander = error;
|
|
1596
|
+
if (commander.exitCode === 0)
|
|
1597
|
+
return;
|
|
1598
|
+
if (typeof commander.exitCode === 'number')
|
|
1599
|
+
throw new FleetCliExit(commander.exitCode, 'validation', 'not_started');
|
|
1600
|
+
throw error;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
async function runFleetCli() {
|
|
1604
|
+
const stateDir = process.env[FLEET_PROXY_STATE_DIR_ENV];
|
|
1605
|
+
const caller = process.env[FLEET_PROXY_CALLER_ENV];
|
|
1606
|
+
if (!stateDir || !caller) {
|
|
1607
|
+
await parseFleetCli();
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
const requestId = randomUUID();
|
|
1611
|
+
let attempt;
|
|
1612
|
+
const begun = await controlRequest(stateDir, {
|
|
1613
|
+
command: 'fleet_audit_begin', audit: { requestId, argv: process.argv.slice(2) },
|
|
1614
|
+
});
|
|
1615
|
+
if (!begun.ok)
|
|
1616
|
+
throw new SessionControlError(begun.kind ?? 'rejected', begun.error ?? 'fleet command audit refused');
|
|
1617
|
+
attempt = begun.result;
|
|
1618
|
+
if (attempt.caller !== caller)
|
|
1619
|
+
throw new SessionControlError('rejected', `fleet audit caller mismatch: expected '${caller}', got '${attempt.caller}'`);
|
|
1620
|
+
let exitCode = 0;
|
|
1621
|
+
let outcomeClass = 'success';
|
|
1622
|
+
let effect = 'completed';
|
|
1623
|
+
beginFleetAuditCollection();
|
|
1624
|
+
if (attempt.classification.decision !== 'allow') {
|
|
1625
|
+
exitCode = 1;
|
|
1626
|
+
outcomeClass = 'denied';
|
|
1627
|
+
effect = 'not_started';
|
|
1628
|
+
console.error(`fleet supervisor proxy ${attempt.classification.decision}: ${attempt.classification.command}`);
|
|
1629
|
+
}
|
|
1630
|
+
else {
|
|
1631
|
+
const originalExit = process.exit;
|
|
1632
|
+
process.exit = ((code) => { throw new FleetCliExit(code ?? 0); });
|
|
1633
|
+
try {
|
|
1634
|
+
await parseFleetCli();
|
|
1635
|
+
}
|
|
1636
|
+
catch (error) {
|
|
1637
|
+
exitCode = error instanceof FleetCliExit ? error.exitCode : 1;
|
|
1638
|
+
outcomeClass = error instanceof FleetCliExit ? error.outcomeClass : 'runtime';
|
|
1639
|
+
effect = error instanceof FleetCliExit ? error.effect : 'unknown';
|
|
1640
|
+
if (!(error instanceof FleetCliExit))
|
|
1641
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1642
|
+
}
|
|
1643
|
+
finally {
|
|
1644
|
+
process.exit = originalExit;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
const metadata = consumeFleetAuditCollection();
|
|
1648
|
+
if (metadata.failure) {
|
|
1649
|
+
outcomeClass = metadata.failure.class;
|
|
1650
|
+
effect = metadata.failure.effect;
|
|
1651
|
+
}
|
|
1652
|
+
const finished = await controlRequest(stateDir, { command: 'fleet_audit_finish', audit: {
|
|
1653
|
+
correlationId: attempt.correlationId, class: outcomeClass, exitCode, effect,
|
|
1654
|
+
...(metadata.resourceIds ? { resourceIds: metadata.resourceIds } : {}),
|
|
1655
|
+
...(metadata.presentations ? { presentations: metadata.presentations } : {}),
|
|
1656
|
+
} });
|
|
1657
|
+
if (!finished.ok)
|
|
1658
|
+
throw new SessionControlError(finished.kind ?? 'backend', finished.error ?? `audit delivery failed after execution; effect status=${effect}`);
|
|
1659
|
+
process.exitCode = exitCode;
|
|
1660
|
+
}
|
|
1661
|
+
void runFleetCli().catch(error => {
|
|
1662
|
+
if (!(error instanceof FleetCliExit))
|
|
1663
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1664
|
+
process.exitCode = error instanceof FleetCliExit ? error.exitCode : 1;
|
|
1665
|
+
});
|
package/dist/config-yaml.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type YamlMode = 'compat' | 'strict';
|
|
2
|
-
export type ConfigDiagnosticKind = 'anchor' | 'alias' | 'explicit-tag' | 'non-scalar-key' | 'multiple-documents';
|
|
2
|
+
export type ConfigDiagnosticKind = 'anchor' | 'alias' | 'explicit-tag' | 'non-scalar-key' | 'multiple-documents' | 'deprecated-field';
|
|
3
3
|
export interface ConfigDiagnostic {
|
|
4
4
|
severity: 'warning';
|
|
5
5
|
kind: ConfigDiagnosticKind;
|
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ConfigDiagnostic, type YamlMode } from './config-yaml.js';
|
|
2
2
|
import type { IsolationConfig, WrapContext } from './isolation/types.js';
|
|
3
3
|
import type { ResolvedWatchdog } from './watchdog/config.js';
|
|
4
|
-
import type { ResolvedLoop, ResolvedRoleLoop } from './loops/config.js';
|
|
4
|
+
import type { AgentLoopsConfig, ResolvedLoop, ResolvedRoleLoop } from './loops/config.js';
|
|
5
5
|
export interface OverseeEntry {
|
|
6
6
|
agent: string;
|
|
7
7
|
interval: string;
|
|
@@ -25,7 +25,8 @@ export declare const NOTIFY_EVENT_TYPES: readonly ["message_received", "file_rec
|
|
|
25
25
|
export type NotifyEventType = (typeof NOTIFY_EVENT_TYPES)[number];
|
|
26
26
|
export type InjectMode = 'notification' | 'full';
|
|
27
27
|
export type MonitorMode = 'fleet' | 'native';
|
|
28
|
-
|
|
28
|
+
/** Concrete transport selected for a role. Keep provider-native transports explicit. */
|
|
29
|
+
export type SessionBackendId = 'acp' | 'codex-app-server';
|
|
29
30
|
/** Public, harness-neutral permission policy. */
|
|
30
31
|
export type FleetPermissionMode = 'ask' | 'auto' | 'allow';
|
|
31
32
|
/** `deny` is a deprecated, fail-closed compatibility alias retained for old fleet files. */
|
|
@@ -44,6 +45,10 @@ export interface SessionOptions {
|
|
|
44
45
|
/** ACP agent command and arguments. Defaults are supplied by the harness adapter. */
|
|
45
46
|
command?: string | string[];
|
|
46
47
|
};
|
|
48
|
+
codex_app_server?: {
|
|
49
|
+
/** App-server command and arguments. Defaults to `codex app-server`. */
|
|
50
|
+
command?: string | string[];
|
|
51
|
+
};
|
|
47
52
|
}
|
|
48
53
|
/** Resolved per-role supervisor-monitor config. */
|
|
49
54
|
export interface MonitorConfig {
|
|
@@ -137,6 +142,36 @@ export interface RoleConfig {
|
|
|
137
142
|
worklog?: WorklogPolicyInput;
|
|
138
143
|
auth_proxy?: Partial<AuthProxyConfig>;
|
|
139
144
|
}
|
|
145
|
+
export type AgentSelection<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
146
|
+
ref: string;
|
|
147
|
+
} | {
|
|
148
|
+
inline: T;
|
|
149
|
+
};
|
|
150
|
+
/** Canonical authoring contract shared by configured, spawned, and room agents. */
|
|
151
|
+
export interface AgentDefinition {
|
|
152
|
+
role: AgentSelection;
|
|
153
|
+
brain: AgentSelection;
|
|
154
|
+
permissions?: Partial<CommonPermissions>;
|
|
155
|
+
identity?: string;
|
|
156
|
+
cwd?: string;
|
|
157
|
+
coordinator?: string;
|
|
158
|
+
env?: Record<string, string>;
|
|
159
|
+
oversee?: OverseeEntry[];
|
|
160
|
+
isolation?: IsolationConfig;
|
|
161
|
+
monitor?: Partial<MonitorConfig>;
|
|
162
|
+
owner_channel?: OwnerChannelConfigInput;
|
|
163
|
+
worklog?: WorklogPolicyInput;
|
|
164
|
+
auth_proxy?: Partial<AuthProxyConfig>;
|
|
165
|
+
/** Scheduled turns scoped only to temporary launches; persistent Agents reject this field. */
|
|
166
|
+
loops?: AgentLoopsConfig;
|
|
167
|
+
}
|
|
168
|
+
/** Inert, reusable launch definition. It never owns an identity or runtime state. */
|
|
169
|
+
export type AgentTemplateDefinition = Omit<AgentDefinition, 'identity'>;
|
|
170
|
+
/** Explicit persistent instance reusing an inert template. */
|
|
171
|
+
export interface AgentTemplateInstance {
|
|
172
|
+
template: string;
|
|
173
|
+
overrides?: Partial<AgentDefinition>;
|
|
174
|
+
}
|
|
140
175
|
/** Internal first-boot payload for a Fleet-provisioned Cowork room member. */
|
|
141
176
|
export interface RoomMemberStartup {
|
|
142
177
|
room_id: string;
|
|
@@ -147,6 +182,7 @@ export interface RoomMemberStartup {
|
|
|
147
182
|
role: string;
|
|
148
183
|
task: string;
|
|
149
184
|
owner_seat_cid: string | null;
|
|
185
|
+
anonymous?: boolean;
|
|
150
186
|
}
|
|
151
187
|
export interface ResolvedRole extends Omit<RoleConfig, 'model' | 'owner_channel' | 'worklog'> {
|
|
152
188
|
name: string;
|
|
@@ -168,9 +204,20 @@ export interface ResolvedRole extends Omit<RoleConfig, 'model' | 'owner_channel'
|
|
|
168
204
|
worklog?: WorklogPolicy;
|
|
169
205
|
auth_proxy?: AuthProxyConfig;
|
|
170
206
|
loops?: ResolvedRoleLoop[];
|
|
207
|
+
/** Agent Template-local loops, kept separate from manifest loops until a temp launch. */
|
|
208
|
+
temporaryLoops?: ResolvedRoleLoop[];
|
|
209
|
+
/** Durable source of the temporary loop policy; internal and never user-authored. */
|
|
210
|
+
temporaryLoopSource?: 'agent-template' | 'cli' | 'omitted';
|
|
171
211
|
provenance?: Record<string, FieldProvenance>;
|
|
172
212
|
/** Internal/transient: never accepted as a user-authored RoleConfig key. */
|
|
173
213
|
roomMemberStartup?: RoomMemberStartup;
|
|
214
|
+
/** Original unresolved selections only; denied operational fields never enter inheritance state. */
|
|
215
|
+
agentSelections?: Pick<AgentDefinition, 'role' | 'brain'>;
|
|
216
|
+
agentTemplate?: {
|
|
217
|
+
id: string;
|
|
218
|
+
sourceFile: string;
|
|
219
|
+
contentHash: string;
|
|
220
|
+
};
|
|
174
221
|
}
|
|
175
222
|
export interface FieldProvenance {
|
|
176
223
|
sourceFile: string;
|
|
@@ -190,12 +237,20 @@ export interface FieldProvenance {
|
|
|
190
237
|
}
|
|
191
238
|
export interface FleetConfig {
|
|
192
239
|
roles: ResolvedRole[];
|
|
240
|
+
/** Canonical, variable-resolved Agent authoring documents keyed by stable Agent ID. */
|
|
241
|
+
agentDefinitions?: Record<string, AgentDefinition>;
|
|
242
|
+
/** Canonical inert templates keyed by stable template ID. */
|
|
243
|
+
agentTemplates?: Record<string, AgentTemplateDefinition>;
|
|
244
|
+
rolePresets?: Record<string, Record<string, unknown>>;
|
|
245
|
+
brainPresets?: Record<string, Record<string, unknown>>;
|
|
246
|
+
/** Required launch-boundary resolver for effective temporary Agent definitions. */
|
|
247
|
+
resolveAgentDefinition?: (id: string, definition: AgentDefinition) => ResolvedRole;
|
|
193
248
|
vars: Record<string, string>;
|
|
194
249
|
defaults: Record<string, unknown>;
|
|
195
250
|
files: string[];
|
|
196
251
|
configMode?: 'split-v2';
|
|
197
252
|
sourceDocuments?: Array<{
|
|
198
|
-
kind: 'Manifest' | 'Agent' | 'Role' | 'Brain';
|
|
253
|
+
kind: 'Manifest' | 'Agent' | 'AgentTemplate' | 'Role' | 'Brain' | 'RoomTemplate';
|
|
199
254
|
id?: string;
|
|
200
255
|
path: string;
|
|
201
256
|
}>;
|
|
@@ -229,11 +284,28 @@ export declare function resolveRoleModel(model: string | null | undefined, harne
|
|
|
229
284
|
*/
|
|
230
285
|
export declare function isolationContextFor(role: ResolvedRole): WrapContext;
|
|
231
286
|
export declare const ROLE_NAME_RE: RegExp;
|
|
287
|
+
export declare const ROLE_PRESET_KEYS: string[];
|
|
288
|
+
export declare const BRAIN_PRESET_KEYS: string[];
|
|
289
|
+
export declare const AGENT_KEYS: string[];
|
|
290
|
+
type BarePreset = Record<string, unknown>;
|
|
291
|
+
export declare function validateRoleValue(value: BarePreset, file: string, pointer: string): void;
|
|
292
|
+
export declare function validateBrainValue(value: BarePreset, file: string, pointer: string): void;
|
|
293
|
+
/** Pure launch-boundary validation for a fully resolved temporary Agent definition. */
|
|
294
|
+
export declare function validateEffectiveAgentTemplate(definition: AgentTemplateDefinition, id?: string): AgentTemplateDefinition;
|
|
295
|
+
export declare function assertBareKeys(value: unknown, allowed: string[], label: string): BarePreset;
|
|
232
296
|
export declare function splitRootFor(base: string): string;
|
|
233
297
|
/** Load a v2 manifest and bare Agent/Role/Brain documents from its stem directory. */
|
|
234
298
|
export declare function loadConfig(configPath?: string, options?: {
|
|
235
299
|
yamlMode?: YamlMode;
|
|
300
|
+
additionalAgent?: {
|
|
301
|
+
id: string;
|
|
302
|
+
definition: AgentDefinition;
|
|
303
|
+
temporary?: boolean;
|
|
304
|
+
};
|
|
305
|
+
skipWatchdogs?: boolean;
|
|
236
306
|
}): FleetConfig;
|
|
307
|
+
/** Full read-only Agent resolution used by launch dry-runs and room plan validation. */
|
|
308
|
+
export declare function resolveAgentDefinitionDryRun(configPath: string, id: string, definition: AgentDefinition): ResolvedRole;
|
|
237
309
|
/**
|
|
238
310
|
* Canonical form of a 64-hex container ID for authorization decisions. Hex
|
|
239
311
|
* case is not identity: two casings of one CID are the same peer, so every
|