@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/watchdog/run.js
CHANGED
|
@@ -10,7 +10,7 @@ import { applyRole } from '../ops.js';
|
|
|
10
10
|
import { daemonIdentityInventoryProvisioner, ensureIdentity, } from '../creation.js';
|
|
11
11
|
import { runOnce, START_STAGGER_FILE } from '../runner.js';
|
|
12
12
|
import { agentDir, tmpRoot } from '../paths.js';
|
|
13
|
-
import { loadConfig,
|
|
13
|
+
import { loadConfig, ROLE_NAME_RE, } from '../config.js';
|
|
14
14
|
import { getAdapter } from '../harness/registry.js';
|
|
15
15
|
import { redactLogLine } from '../application/log-service.js';
|
|
16
16
|
import { controlRequest, controlSocketPath } from '../session/control.js';
|
|
@@ -84,19 +84,10 @@ function readTail(runDir) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
/** The temp role every watchdog-family run launches under. Isolation is opt-in. */
|
|
87
|
-
function buildWatchdogRole(wd,
|
|
87
|
+
function buildWatchdogRole(wd, _cfg) {
|
|
88
88
|
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
identity: wd.identity, model: wd.model,
|
|
92
|
-
// Watchdogs are observe-only by contract, but their sanctioned status commands
|
|
93
|
-
// must reach host control sockets. Keep approvals/unattended escalation denied
|
|
94
|
-
// while disabling the harness's native filesystem/network sandbox.
|
|
95
|
-
permissions: { approval: 'deny', filesystem: 'unrestricted', unattended: 'deny' },
|
|
96
|
-
permissionsDeclared: true,
|
|
97
|
-
monitor: resolveMonitorConfig(cfg.defaults.monitor, undefined),
|
|
98
|
-
worklog: resolveWorklogPolicy(cfg.defaults.worklog, undefined),
|
|
99
|
-
isolation: wd.isolation,
|
|
89
|
+
...structuredClone(wd.resolvedAgent),
|
|
90
|
+
name: wd.identity, sourceFile: '(watchdog)', identity: wd.identity,
|
|
100
91
|
};
|
|
101
92
|
}
|
|
102
93
|
/** Discover temporary sessions that are live now, not merely stale dirs on disk. */
|
|
@@ -3,6 +3,7 @@ export declare const REDACTED_ENV_VALUE = "__OURS_FLEET_SECRET_REDACTED__";
|
|
|
3
3
|
export interface EditableFleetModel {
|
|
4
4
|
manifest: Record<string, unknown>;
|
|
5
5
|
agents: Record<string, Record<string, unknown>>;
|
|
6
|
+
agent_templates: Record<string, Record<string, unknown>>;
|
|
6
7
|
}
|
|
7
8
|
export interface ConfigReadResult {
|
|
8
9
|
path: string;
|
|
@@ -12,7 +12,7 @@ import { isSensitiveConfigKey } from '../sensitive-config.js';
|
|
|
12
12
|
export const REDACTED_ENV_VALUE = '__OURS_FLEET_SECRET_REDACTED__';
|
|
13
13
|
const MAX_CONFIG_BYTES = 256 * 1024;
|
|
14
14
|
const DIFF_CONTEXT_LINES = 3;
|
|
15
|
-
const KINDS = ['agents', 'roles', 'brains'];
|
|
15
|
+
const KINDS = ['agents', 'agent_templates', 'roles', 'brains', 'room_templates'];
|
|
16
16
|
const emptyReport = () => ({ ok: true, checks: [] });
|
|
17
17
|
export class FleetConfigService {
|
|
18
18
|
path;
|
|
@@ -176,7 +176,8 @@ function readSources(manifest) {
|
|
|
176
176
|
}
|
|
177
177
|
trustedDirectory(dir);
|
|
178
178
|
for (const name of readdirSync(dir).sort()) {
|
|
179
|
-
if (kind === 'agents'
|
|
179
|
+
if ((kind === 'agents' || kind === 'agent_templates' || kind === 'room_templates')
|
|
180
|
+
&& !['.yaml', '.yml'].includes(extname(name).toLowerCase()))
|
|
180
181
|
continue;
|
|
181
182
|
documents.set(join(kind, name), trustedFile(join(dir, name)));
|
|
182
183
|
}
|
|
@@ -187,20 +188,26 @@ function modelFrom(sources) {
|
|
|
187
188
|
const manifestKey = basename(sources.manifest);
|
|
188
189
|
const manifest = parseFleetDocument(sources.manifest, sources.documents.get(manifestKey), 'strict').value;
|
|
189
190
|
const agents = {};
|
|
191
|
+
const agent_templates = {};
|
|
190
192
|
for (const [rel, source] of sources.documents)
|
|
191
193
|
if (rel.startsWith(`agents/`)) {
|
|
192
194
|
const id = basename(rel, extname(rel));
|
|
193
195
|
agents[id] = parseFleetDocument(absoluteFor(sources.manifest, rel), source, 'strict').value;
|
|
194
196
|
}
|
|
195
|
-
|
|
197
|
+
for (const [rel, source] of sources.documents)
|
|
198
|
+
if (rel.startsWith(`agent_templates/`)) {
|
|
199
|
+
const id = basename(rel, extname(rel));
|
|
200
|
+
agent_templates[id] = parseFleetDocument(absoluteFor(sources.manifest, rel), source, 'strict').value;
|
|
201
|
+
}
|
|
202
|
+
return { manifest, agents, agent_templates };
|
|
196
203
|
}
|
|
197
204
|
function assertModel(value) {
|
|
198
205
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
199
206
|
throw new FleetError('invalid_request', 'model must be an object');
|
|
200
207
|
const input = value;
|
|
201
|
-
if (Object.keys(input).sort().join(',') !== 'agents,manifest')
|
|
202
|
-
throw new FleetError('invalid_request', 'model allows exactly manifest and
|
|
203
|
-
for (const key of ['manifest', 'agents'])
|
|
208
|
+
if (Object.keys(input).sort().join(',') !== 'agent_templates,agents,manifest')
|
|
209
|
+
throw new FleetError('invalid_request', 'model allows exactly manifest, agents, and agent_templates');
|
|
210
|
+
for (const key of ['manifest', 'agents', 'agent_templates'])
|
|
204
211
|
if (!input[key] || typeof input[key] !== 'object' || Array.isArray(input[key]))
|
|
205
212
|
throw new FleetError('invalid_request', `${key} must be an object`);
|
|
206
213
|
for (const [id, doc] of Object.entries(input.agents)) {
|
|
@@ -209,6 +216,12 @@ function assertModel(value) {
|
|
|
209
216
|
if (!doc || typeof doc !== 'object' || Array.isArray(doc))
|
|
210
217
|
throw new FleetError('invalid_request', `Agent '${id}' must be an object`);
|
|
211
218
|
}
|
|
219
|
+
for (const [id, doc] of Object.entries(input.agent_templates)) {
|
|
220
|
+
if (!ROLE_NAME_RE.test(id))
|
|
221
|
+
throw new FleetError('invalid_request', `invalid Agent Template ID '${id}'`);
|
|
222
|
+
if (!doc || typeof doc !== 'object' || Array.isArray(doc))
|
|
223
|
+
throw new FleetError('invalid_request', `Agent Template '${id}' must be an object`);
|
|
224
|
+
}
|
|
212
225
|
return structuredClone(input);
|
|
213
226
|
}
|
|
214
227
|
function renderProposal(current, model) {
|
|
@@ -221,8 +234,14 @@ function renderProposal(current, model) {
|
|
|
221
234
|
next.set(oldRel ?? join('agents', `${id}.yaml`), oldRel
|
|
222
235
|
? render(current.documents.get(oldRel), doc) : stringify(doc));
|
|
223
236
|
}
|
|
237
|
+
for (const [id, doc] of Object.entries(model.agent_templates).sort(([a], [b]) => a.localeCompare(b))) {
|
|
238
|
+
const oldRel = [...current.documents.keys()].find(rel => rel.startsWith('agent_templates/')
|
|
239
|
+
&& basename(rel, extname(rel)) === id);
|
|
240
|
+
next.set(oldRel ?? join('agent_templates', `${id}.yaml`), oldRel
|
|
241
|
+
? render(current.documents.get(oldRel), doc) : stringify(doc));
|
|
242
|
+
}
|
|
224
243
|
for (const [rel, source] of current.documents)
|
|
225
|
-
if (rel.startsWith('roles/') || rel.startsWith('brains/'))
|
|
244
|
+
if (rel.startsWith('roles/') || rel.startsWith('brains/') || rel.startsWith('room_templates/'))
|
|
226
245
|
next.set(rel, source);
|
|
227
246
|
return next;
|
|
228
247
|
}
|
|
@@ -424,7 +443,7 @@ function sourceSensitiveValues(sources) {
|
|
|
424
443
|
continue;
|
|
425
444
|
try {
|
|
426
445
|
const parsed = parse(source);
|
|
427
|
-
values.push(...sensitiveValues({ manifest: {}, agents: { source: parsed } }));
|
|
446
|
+
values.push(...sensitiveValues({ manifest: {}, agents: { source: parsed }, agent_templates: {} }));
|
|
428
447
|
}
|
|
429
448
|
catch { /* the authoritative parser reports malformed YAML */ }
|
|
430
449
|
}
|
package/dist/web/runtime.js
CHANGED
|
@@ -4,7 +4,7 @@ import { resolve } from 'node:path';
|
|
|
4
4
|
import { loadConfig } from '../config.js';
|
|
5
5
|
import { RoleRepository } from '../application/role-repository.js';
|
|
6
6
|
import { FleetQueryService } from '../application/fleet-query-service.js';
|
|
7
|
-
import {
|
|
7
|
+
import { RoleSessionControlAdapter } from '../application/session-control.js';
|
|
8
8
|
import { StructuredLogService } from '../application/log-service.js';
|
|
9
9
|
import { RoleCommandService } from '../application/role-command-service.js';
|
|
10
10
|
import { RoleCreationService } from '../application/role-creation-service.js';
|
|
@@ -64,18 +64,22 @@ export async function startWebConsole(options) {
|
|
|
64
64
|
const repository = new RoleRepository({
|
|
65
65
|
configPath: options.configPath,
|
|
66
66
|
probeBackend: async (name) => {
|
|
67
|
-
let
|
|
67
|
+
let backend;
|
|
68
68
|
const permanent = resolve(home(), '.ours-fleet', 'agents', name);
|
|
69
69
|
const temporary = resolve(home(), '.ours-fleet', 'tmp', name);
|
|
70
70
|
for (const dir of [permanent, temporary]) {
|
|
71
71
|
if (!existsSync(controlSocketPath(dir)))
|
|
72
72
|
continue;
|
|
73
73
|
try {
|
|
74
|
-
|
|
74
|
+
const response = await controlRequest(dir, { command: 'snapshot' }, 500);
|
|
75
|
+
const snapshot = response.result;
|
|
76
|
+
if (response.ok && (snapshot?.backend === 'acp'
|
|
77
|
+
|| snapshot?.backend === 'codex-app-server'))
|
|
78
|
+
backend = snapshot.backend;
|
|
75
79
|
}
|
|
76
80
|
catch { /* stale socket is evidence, not reachability */ }
|
|
77
81
|
}
|
|
78
|
-
return {
|
|
82
|
+
return { backend };
|
|
79
83
|
},
|
|
80
84
|
});
|
|
81
85
|
const events = new FleetEventBus();
|
|
@@ -161,11 +165,12 @@ export async function startWebConsole(options) {
|
|
|
161
165
|
const role = await repository.get(roleId);
|
|
162
166
|
if (!role)
|
|
163
167
|
throw new FleetError('role_not_found', `no such role '${roleId}'`);
|
|
164
|
-
if (role.configuredBackend === 'acp'
|
|
168
|
+
if (role.configuredBackend === 'acp'
|
|
169
|
+
|| role.configuredBackend === 'codex-app-server') {
|
|
165
170
|
const dir = repository.stateDir(role);
|
|
166
171
|
if (!dir)
|
|
167
172
|
throw new FleetError('control_unavailable', 'role state directory is unavailable');
|
|
168
|
-
return new
|
|
173
|
+
return new RoleSessionControlAdapter(dir);
|
|
169
174
|
}
|
|
170
175
|
throw new FleetError('capability_unavailable', 'role session backend is unavailable');
|
|
171
176
|
},
|
package/dist/web/server.js
CHANGED
|
@@ -183,12 +183,39 @@ export async function buildWebServer(services, boundary, options = {}) {
|
|
|
183
183
|
throw new FleetError('invalid_request', 'invalid task state filter');
|
|
184
184
|
if (query.groupByList !== undefined && !['true', 'false'].includes(query.groupByList))
|
|
185
185
|
throw new FleetError('invalid_request', 'groupByList must be true or false');
|
|
186
|
+
if (query.includeDeleting !== undefined && !['true', 'false'].includes(query.includeDeleting))
|
|
187
|
+
throw new FleetError('invalid_request', 'includeDeleting must be true or false');
|
|
186
188
|
const state = query.state && query.state !== 'all' ? query.state : undefined;
|
|
187
|
-
const filter = { ...(state ? { state } : {}), ...(query.list ? { list: query.list } : {})
|
|
189
|
+
const filter = { ...(state ? { state } : {}), ...(query.list ? { list: query.list } : {}),
|
|
190
|
+
...(query.includeDeleting === 'true' ? { includeDeleting: true } : {}) };
|
|
188
191
|
return taskApi(() => query.groupByList === 'true'
|
|
189
192
|
? { groups: requireTaskRooms().groupedTasks(filter) }
|
|
190
193
|
: { tasks: requireTaskRooms().listTasks(filter) });
|
|
191
194
|
});
|
|
195
|
+
app.delete('/api/v1/tasks/:id', async (request, reply) => {
|
|
196
|
+
auth.authenticate(request, true);
|
|
197
|
+
const taskId = request.params.id;
|
|
198
|
+
const confirm = request.query.confirm;
|
|
199
|
+
// Exact-ID-twice confirmation is validated before existence or idempotency.
|
|
200
|
+
if (confirm !== taskId)
|
|
201
|
+
throw new FleetError('invalid_request', 'confirm must exactly repeat the task id');
|
|
202
|
+
const accepted = await taskApi(() => requireTaskRooms().requestTaskDeletion({
|
|
203
|
+
actor: { kind: 'local_control', surface: 'web' }, taskId,
|
|
204
|
+
}));
|
|
205
|
+
if (accepted.status === 'already_absent')
|
|
206
|
+
return { task_id: taskId, deleted: false, already_absent: true };
|
|
207
|
+
// Cleanup runs in an external worker outside the request lifecycle; the
|
|
208
|
+
// request waits boundedly and reports pending — never fabricated success.
|
|
209
|
+
const outcome = await requireTaskRooms().launchTaskDeletionWorker({ taskId, waitMs: 5_000 });
|
|
210
|
+
if (outcome.deleted)
|
|
211
|
+
return { task_id: taskId, deleted: true };
|
|
212
|
+
reply.code(202);
|
|
213
|
+
return {
|
|
214
|
+
task_id: taskId, accepted: true, deletion: 'pending',
|
|
215
|
+
...(outcome.error ? { error: outcome.error } : {}),
|
|
216
|
+
recovery: `Repeat DELETE /api/v1/tasks/${taskId}?confirm=${taskId} or run 'ours-fleet task recover ${taskId}'.`,
|
|
217
|
+
};
|
|
218
|
+
});
|
|
192
219
|
app.post('/api/v1/tasks', async (request, reply) => {
|
|
193
220
|
auth.authenticate(request, true);
|
|
194
221
|
const body = request.body;
|
|
@@ -126,7 +126,14 @@ function agentEntry(node) {
|
|
|
126
126
|
*/
|
|
127
127
|
function watchdogEntry(node, merged) {
|
|
128
128
|
const scoped = linked(merged, node.id, 'watches');
|
|
129
|
-
return {
|
|
129
|
+
return {
|
|
130
|
+
...pick(node, WATCHDOG_FIELDS),
|
|
131
|
+
agent: {
|
|
132
|
+
role: { inline: {} },
|
|
133
|
+
brain: { inline: { harness: 'claude-code', ...pick(node, BRAIN_FIELDS) } },
|
|
134
|
+
},
|
|
135
|
+
...(scoped.length ? { watch: scoped } : {}),
|
|
136
|
+
};
|
|
130
137
|
}
|
|
131
138
|
function loopEntry(node, merged) {
|
|
132
139
|
const roles = linked(merged, node.id, 'targets');
|