@ours.network/fleet 1.0.5 → 1.1.0-nightly.10
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 +122 -133
- package/dist/agent-recovery-gate.d.ts +17 -0
- package/dist/agent-recovery-gate.js +135 -0
- package/dist/application/capabilities.d.ts +0 -1
- package/dist/application/capabilities.js +3 -13
- package/dist/application/fleet-query-service.d.ts +0 -3
- package/dist/application/fleet-query-service.js +14 -25
- package/dist/application/role-creation-service.d.ts +5 -24
- package/dist/application/role-creation-service.js +27 -67
- package/dist/application/role-removal-service.js +6 -3
- package/dist/application/role-repository.d.ts +1 -2
- package/dist/application/role-repository.js +7 -7
- package/dist/application/session-control.d.ts +0 -12
- package/dist/application/session-control.js +0 -42
- package/dist/application/session-mutations.d.ts +5 -5
- package/dist/application/task-room-service.d.ts +1 -1
- package/dist/application/task-room-service.js +154 -16
- package/dist/application/types.d.ts +1 -8
- package/dist/briefing.js +12 -11
- package/dist/build-info.json +5 -5
- package/dist/cli.js +143 -63
- package/dist/config-yaml.d.ts +1 -1
- package/dist/config.d.ts +66 -6
- package/dist/config.js +398 -43
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +2 -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 +103 -127
- package/dist/doctor.js +18 -11
- package/dist/fleet-command-audit.d.ts +160 -0
- package/dist/fleet-command-audit.js +433 -0
- package/dist/fleet-proxy.d.ts +3 -1
- package/dist/fleet-proxy.js +30 -8
- package/dist/generated-agent-source.d.ts +9 -0
- package/dist/generated-agent-source.js +53 -0
- package/dist/harness/acp-session-transport.d.ts +8 -0
- package/dist/harness/acp-session-transport.js +3 -0
- package/dist/harness/agent-session.d.ts +51 -0
- package/dist/harness/agent-session.js +1 -0
- package/dist/harness/claude-code-session.d.ts +24 -0
- package/dist/harness/claude-code-session.js +36 -0
- package/dist/harness/claude-code.d.ts +2 -1
- package/dist/harness/claude-code.js +41 -81
- package/dist/harness/codex-session.d.ts +24 -0
- package/dist/harness/codex-session.js +36 -0
- package/dist/harness/codex.d.ts +2 -1
- package/dist/harness/codex.js +55 -45
- package/dist/harness/registry.js +4 -0
- package/dist/harness/types.d.ts +6 -38
- package/dist/index.d.ts +4 -6
- package/dist/index.js +2 -4
- package/dist/init-guidance.d.ts +1 -0
- package/dist/init-guidance.js +6 -0
- package/dist/isolation/resources.d.ts +3 -7
- package/dist/isolation/resources.js +3 -7
- package/dist/model-env.d.ts +4 -6
- package/dist/model-env.js +5 -8
- package/dist/monitor.d.ts +1 -24
- package/dist/monitor.js +5 -140
- package/dist/ops.js +4 -2
- package/dist/owner-channel/channel.d.ts +58 -2
- package/dist/owner-channel/channel.js +269 -29
- package/dist/owner-channel/commands.d.ts +2 -0
- package/dist/owner-channel/commands.js +31 -13
- package/dist/owner-channel/state.d.ts +2 -0
- package/dist/owner-channel/state.js +8 -2
- package/dist/preset-bootstrap.d.ts +10 -0
- package/dist/preset-bootstrap.js +85 -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.d.ts +3 -2
- package/dist/resolved-plan.js +21 -5
- package/dist/rooms-tasks/cli.js +225 -40
- package/dist/rooms-tasks/config.js +24 -13
- package/dist/rooms-tasks/external-worker.d.ts +1 -0
- package/dist/rooms-tasks/external-worker.js +14 -9
- package/dist/rooms-tasks/provision.js +98 -36
- package/dist/rooms-tasks/templates.d.ts +0 -1
- package/dist/rooms-tasks/templates.js +9 -76
- package/dist/rooms-tasks/types.d.ts +10 -16
- package/dist/rooms-tasks/types.js +1 -4
- package/dist/runner.d.ts +13 -16
- package/dist/runner.js +110 -122
- package/dist/sensitive-config.d.ts +2 -0
- package/dist/sensitive-config.js +4 -0
- package/dist/session/acp.d.ts +7 -2
- package/dist/session/acp.js +29 -6
- package/dist/session/activity.d.ts +2 -3
- package/dist/session/activity.js +2 -3
- package/dist/session/arbiter.d.ts +4 -4
- package/dist/session/control.d.ts +17 -4
- package/dist/session/control.js +35 -0
- package/dist/session/types.d.ts +11 -5
- package/dist/spawn.d.ts +8 -33
- package/dist/spawn.js +53 -213
- package/dist/supervisor/none.d.ts +1 -1
- package/dist/supervisor/none.js +2 -2
- package/dist/temp-lifecycle.d.ts +1 -1
- package/dist/tmux.d.ts +1 -14
- package/dist/tmux.js +1 -51
- package/dist/watchdog/config.d.ts +10 -7
- package/dist/watchdog/config.js +30 -18
- package/dist/watchdog/run.js +12 -36
- package/dist/web/auth.d.ts +1 -1
- package/dist/web/fleet-config-service.d.ts +11 -8
- package/dist/web/fleet-config-service.js +384 -183
- package/dist/web/runtime.js +4 -15
- package/dist/web/server.d.ts +1 -3
- package/dist/web/server.js +3 -14
- package/dist/web/topology-promote.js +26 -19
- package/dist/web/topology.js +2 -2
- package/dist/web/yaml-document-edit.js +2 -0
- package/dist/web-app/assets/index-59GF-gsZ.css +1 -0
- package/dist/web-app/assets/index-BbTc5KtZ.js +10 -0
- package/dist/web-app/index.html +2 -2
- package/examples/fleet/agents/Alice.yaml +11 -0
- package/examples/fleet/agents/FleetCoordinator.yaml +7 -0
- package/examples/fleet/brains/claude-default.yaml +5 -0
- package/examples/fleet/roles/coordinator.yaml +5 -0
- package/examples/fleet/roles/developer.yaml +3 -0
- package/examples/fleet.yaml +74 -0
- package/package.json +5 -8
- package/presets/fleet/agents/Agent.yaml +3 -0
- package/presets/fleet/agents/Architect.yaml +3 -0
- package/presets/fleet/agents/Critic.yaml +3 -0
- package/presets/fleet/agents/Developer.yaml +3 -0
- package/presets/fleet/agents/Secretary.yaml +3 -0
- package/presets/fleet/agents/Tester.yaml +3 -0
- package/presets/fleet/brains/claude-default.yaml +5 -0
- package/presets/fleet/roles/Agent.yaml +6 -0
- package/presets/fleet/roles/Architect.yaml +6 -0
- package/presets/fleet/roles/Critic.yaml +6 -0
- package/presets/fleet/roles/Developer.yaml +6 -0
- package/presets/fleet/roles/Secretary.yaml +6 -0
- package/presets/fleet/roles/Tester.yaml +6 -0
- package/presets/fleet/room_templates/pair.yaml +11 -0
- package/presets/fleet/room_templates/single.yaml +8 -0
- package/presets/fleet/room_templates/team.yaml +12 -0
- package/presets/fleet.yaml +7 -0
- package/presets/manifest.json +5 -0
- package/dist/session/tmux.d.ts +0 -28
- package/dist/session/tmux.js +0 -80
- package/dist/web/terminal/bridge.d.ts +0 -27
- package/dist/web/terminal/bridge.js +0 -317
- package/dist/web-app/assets/TerminalView-C_G1ID2P.js +0 -9
- package/dist/web-app/assets/index-BCBK78hw.js +0 -10
- package/dist/web-app/assets/index-DuC-xnX4.css +0 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
2
3
|
import { ConfigError, loadConfig } from '../config.js';
|
|
3
4
|
import { CoworkProtocolError, CoworkUnavailableError, createCoworkAdapter, } from '../rooms-tasks/cowork-adapter.js';
|
|
4
5
|
import { getBinPath, provisionMembers } from '../rooms-tasks/provision.js';
|
|
5
6
|
import { activateRoom, advanceSaga, createRoomRecord, getRoomRecord, listRoomRecords, setOwnerSeat, setSagaError, } from '../rooms-tasks/room-state.js';
|
|
6
7
|
import { activateTask, blockTask as persistBlockTask, createTask as persistTask, deleteTask as persistDeleteTask, getTask as readTask, listTasks as readTasks, moveTaskToList, reviewTask as persistReviewTask, startTask as transitionTask, TaskStateError, unblockTask as persistUnblockTask, updateTaskRoom, updateTaskTemplate, } from '../rooms-tasks/task-state.js';
|
|
7
8
|
import { createTaskListLocked, DEFAULT_TASK_LIST_ID, deleteTaskListRecordLocked, readTaskLists, renameTaskListLocked, resolveTaskList, TaskListError, withTaskListsLock, } from '../rooms-tasks/task-lists.js';
|
|
9
|
+
import { recordFleetAuditPresentation } from '../fleet-command-audit.js';
|
|
8
10
|
import { hashTemplate, listTemplates, resolveTemplate, snapshotTemplate } from '../rooms-tasks/templates.js';
|
|
9
11
|
import { acceptManagedRoomClose, deleteLegacyClosedRooms, deleteManagedRoom, recordManagedRoomCloseError, } from '../rooms-tasks/close.js';
|
|
10
12
|
import { acceptTaskTerminalIntent, recordTaskTerminalIntentError, settleTaskTerminalIntent, } from '../rooms-tasks/terminal.js';
|
|
@@ -19,6 +21,47 @@ export class TaskRoomApplicationError extends Error {
|
|
|
19
21
|
this.name = 'TaskRoomApplicationError';
|
|
20
22
|
}
|
|
21
23
|
}
|
|
24
|
+
function launchSelection(definition, key) {
|
|
25
|
+
const selected = definition?.[key];
|
|
26
|
+
if (!selected || typeof selected !== 'object' || Array.isArray(selected))
|
|
27
|
+
return undefined;
|
|
28
|
+
const value = selected;
|
|
29
|
+
if (value.kind === 'ref' && typeof value.id === 'string')
|
|
30
|
+
return `ref:${value.id} (reference)`;
|
|
31
|
+
if (value.kind === 'inline' && typeof value.fingerprint === 'string')
|
|
32
|
+
return `inline:${value.fingerprint} (inline)`;
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
function launchPermissions(definition) {
|
|
36
|
+
const selected = definition?.permissions;
|
|
37
|
+
if (!selected || typeof selected !== 'object' || Array.isArray(selected))
|
|
38
|
+
return undefined;
|
|
39
|
+
const value = selected;
|
|
40
|
+
const fields = ['approval', 'filesystem', 'unattended'].flatMap(key => typeof value[key] === 'string' ? [`${key}=${value[key]}`] : []);
|
|
41
|
+
return fields.length ? fields.join(',') : undefined;
|
|
42
|
+
}
|
|
43
|
+
function roomParticipants(room) {
|
|
44
|
+
return [...room.member_seats].sort((a, b) => a.role_name.localeCompare(b.role_name)).map(seat => ({
|
|
45
|
+
name: seat.role_name, id: seat.identity_cid,
|
|
46
|
+
brain: launchSelection(seat.launch?.agent_definition, 'brain'),
|
|
47
|
+
role: launchSelection(seat.launch?.agent_definition, 'role') ?? seat.cowork_role,
|
|
48
|
+
permissions: launchPermissions(seat.launch?.agent_definition),
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
function taskAgents(task) {
|
|
52
|
+
const room = task.room_id ? getRoomRecord(task.room_id) : undefined;
|
|
53
|
+
const seats = new Map(room?.member_seats.map(seat => [seat.role_name, seat]) ?? []);
|
|
54
|
+
return [...task.member_roles].sort((a, b) => a.name.localeCompare(b.name)).map(member => {
|
|
55
|
+
const seat = seats.get(member.name);
|
|
56
|
+
return { name: member.name, brain: launchSelection(seat?.launch?.agent_definition, 'brain'),
|
|
57
|
+
role: launchSelection(seat?.launch?.agent_definition, 'role') ?? member.cowork_role,
|
|
58
|
+
permissions: launchPermissions(seat?.launch?.agent_definition) };
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function roomFailureEventId(room) {
|
|
62
|
+
const evidence = `${room.created_at}\0${room.saga.phase}\0${room.saga.step_index}\0${room.saga.error ?? ''}`;
|
|
63
|
+
return `sha256:${createHash('sha256').update(evidence).digest('hex')}`;
|
|
64
|
+
}
|
|
22
65
|
/** Exact extraction of the previously CLI-owned task create/start behavior. */
|
|
23
66
|
export class TaskRoomApplicationService {
|
|
24
67
|
configurationPath;
|
|
@@ -43,16 +86,34 @@ export class TaskRoomApplicationService {
|
|
|
43
86
|
start: !request.backlog, no_room: request.noRoom, listId: list.list_id,
|
|
44
87
|
});
|
|
45
88
|
});
|
|
89
|
+
recordFleetAuditPresentation({ kind: 'task', operation: 'create', id: task.task_id,
|
|
90
|
+
title: task.title, previousState: 'none', newState: task.state, revision: task.created_at,
|
|
91
|
+
list: task.list_name ?? 'default', roomId: task.room_id,
|
|
92
|
+
template: task.template ? `${task.template.name}@${task.template.version}` : undefined,
|
|
93
|
+
agents: [] });
|
|
46
94
|
if (!request.backlog && !request.noRoom && ref && !task.room_id) {
|
|
47
95
|
try {
|
|
48
|
-
await this.provisionRoom(cfg, task, template,
|
|
49
|
-
task = updateTaskRoom(task.task_id,
|
|
96
|
+
const room = await this.provisionRoom(cfg, task, template, created => {
|
|
97
|
+
task = updateTaskRoom(task.task_id, created.room_id, created.room_identity_cid);
|
|
50
98
|
});
|
|
51
99
|
task = readTask(task.task_id);
|
|
100
|
+
if (task.state === 'active' && room.state === 'active')
|
|
101
|
+
recordFleetAuditPresentation({ kind: 'task', operation: 'work', id: task.task_id,
|
|
102
|
+
title: task.title, previousState: 'provisioning', newState: task.state,
|
|
103
|
+
revision: getRoomRecord(task.room_id)?.activated_at ?? task.started_at ?? task.created_at,
|
|
104
|
+
list: task.list_name ?? 'default', roomId: task.room_id,
|
|
105
|
+
template: task.template ? `${task.template.name}@${task.template.version}` : undefined,
|
|
106
|
+
agents: taskAgents(task) });
|
|
107
|
+
else
|
|
108
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task', id: task.task_id,
|
|
109
|
+
state: task.state, category: 'provision_pending', eventId: roomFailureEventId(room) });
|
|
52
110
|
}
|
|
53
111
|
catch (error) {
|
|
54
112
|
if (error instanceof CoworkUnavailableError)
|
|
55
113
|
persistBlockTask(task.task_id, 'Cowork management socket is unavailable');
|
|
114
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task',
|
|
115
|
+
id: task.task_id, state: readTask(task.task_id).state, category: 'provision_failed',
|
|
116
|
+
eventId: task.room_id ? roomFailureEventId(getRoomRecord(task.room_id)) : task.created_at });
|
|
56
117
|
throw error;
|
|
57
118
|
}
|
|
58
119
|
}
|
|
@@ -75,12 +136,36 @@ export class TaskRoomApplicationService {
|
|
|
75
136
|
async startTask(input) {
|
|
76
137
|
const cfg = (this.deps.loadConfiguration ?? loadConfig)(this.configurationPath);
|
|
77
138
|
let task = transitionTask(input.taskId);
|
|
139
|
+
recordFleetAuditPresentation({ kind: 'task', operation: 'start', id: task.task_id,
|
|
140
|
+
title: task.title, previousState: 'backlog', newState: task.state,
|
|
141
|
+
revision: task.started_at ?? task.created_at, list: task.list_name ?? 'default',
|
|
142
|
+
template: task.template ? `${task.template.name}@${task.template.version}` : undefined,
|
|
143
|
+
agents: [] });
|
|
78
144
|
if (task.template && !task.room_id) {
|
|
79
145
|
const template = this.existingTemplate(cfg, task);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
146
|
+
try {
|
|
147
|
+
const room = await this.provisionRoom(cfg, task, template, created => {
|
|
148
|
+
task = updateTaskRoom(task.task_id, created.room_id, created.room_identity_cid);
|
|
149
|
+
});
|
|
150
|
+
task = readTask(task.task_id);
|
|
151
|
+
if (task.state === 'active' && room.state === 'active')
|
|
152
|
+
recordFleetAuditPresentation({ kind: 'task', operation: 'work', id: task.task_id,
|
|
153
|
+
title: task.title, previousState: 'provisioning', newState: task.state,
|
|
154
|
+
revision: getRoomRecord(task.room_id)?.activated_at ?? task.started_at ?? task.created_at,
|
|
155
|
+
list: task.list_name ?? 'default', roomId: task.room_id,
|
|
156
|
+
template: task.template ? `${task.template.name}@${task.template.version}` : undefined,
|
|
157
|
+
agents: taskAgents(task) });
|
|
158
|
+
else
|
|
159
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task', id: task.task_id,
|
|
160
|
+
state: task.state, category: 'provision_pending', eventId: roomFailureEventId(room) });
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const failed = task.room_id ? getRoomRecord(task.room_id) : undefined;
|
|
164
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task', id: task.task_id,
|
|
165
|
+
state: readTask(task.task_id).state, category: 'provision_failed',
|
|
166
|
+
eventId: failed ? roomFailureEventId(failed) : task.created_at });
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
84
169
|
}
|
|
85
170
|
return task;
|
|
86
171
|
}
|
|
@@ -259,8 +344,13 @@ export class TaskRoomApplicationService {
|
|
|
259
344
|
validateTemplates() {
|
|
260
345
|
const cfg = (this.deps.loadConfiguration ?? loadConfig)(this.configurationPath);
|
|
261
346
|
return listTemplates(cfg.roomTemplates ?? {}).flatMap(template => {
|
|
262
|
-
const issues = template.members.flatMap(member =>
|
|
263
|
-
|
|
347
|
+
const issues = template.members.flatMap(member => {
|
|
348
|
+
if (!('ref' in member.agent))
|
|
349
|
+
return [];
|
|
350
|
+
const ref = member.agent.ref;
|
|
351
|
+
return cfg.roles.some(role => role.name === ref)
|
|
352
|
+
? [] : [`member ${member.slot}: Agent ref '${ref}' not found`];
|
|
353
|
+
});
|
|
264
354
|
return issues.length ? [{ template: `${template.name}@${template.version}`, issues }] : [];
|
|
265
355
|
});
|
|
266
356
|
}
|
|
@@ -461,8 +551,13 @@ export class TaskRoomApplicationService {
|
|
|
461
551
|
});
|
|
462
552
|
if (!task.template || task.template.name !== snapshot.name || task.template.content_hash !== snapshot.content_hash)
|
|
463
553
|
task = updateTaskTemplate(task.task_id, { name: snapshot.name, version: snapshot.version, content_hash: snapshot.content_hash });
|
|
464
|
-
if (task.state === 'backlog')
|
|
554
|
+
if (task.state === 'backlog') {
|
|
465
555
|
task = transitionTask(task.task_id);
|
|
556
|
+
recordFleetAuditPresentation({ kind: 'task', operation: 'start', id: task.task_id,
|
|
557
|
+
title: task.title, previousState: 'backlog', newState: task.state,
|
|
558
|
+
revision: task.started_at ?? task.created_at, list: task.list_name ?? 'default',
|
|
559
|
+
template: `${snapshot.name}@${snapshot.version}`, agents: [] });
|
|
560
|
+
}
|
|
466
561
|
if (!task.room_id) {
|
|
467
562
|
try {
|
|
468
563
|
await this.provisionRoom(cfg, task, snapshot, created => {
|
|
@@ -473,6 +568,9 @@ export class TaskRoomApplicationService {
|
|
|
473
568
|
catch (error) {
|
|
474
569
|
if (error instanceof CoworkUnavailableError)
|
|
475
570
|
persistBlockTask(task.task_id, 'Cowork management socket is unavailable');
|
|
571
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task',
|
|
572
|
+
id: task.task_id, state: readTask(task.task_id).state, category: 'provision_failed',
|
|
573
|
+
eventId: task.room_id ? roomFailureEventId(getRoomRecord(task.room_id)) : task.created_at });
|
|
476
574
|
throw error;
|
|
477
575
|
}
|
|
478
576
|
}
|
|
@@ -491,9 +589,23 @@ export class TaskRoomApplicationService {
|
|
|
491
589
|
catch (error) {
|
|
492
590
|
if (error instanceof CoworkUnavailableError)
|
|
493
591
|
persistBlockTask(task.task_id, 'Cowork management socket is unavailable');
|
|
592
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task',
|
|
593
|
+
id: task.task_id, state: readTask(task.task_id).state, category: 'provision_failed',
|
|
594
|
+
eventId: roomFailureEventId(getRoomRecord(task.room_id)) });
|
|
494
595
|
throw error;
|
|
495
596
|
}
|
|
496
597
|
}
|
|
598
|
+
const resultingRoom = getRoomRecord(task.room_id);
|
|
599
|
+
if (task.state === 'active' && resultingRoom?.state === 'active')
|
|
600
|
+
recordFleetAuditPresentation({ kind: 'task', operation: 'work', id: task.task_id,
|
|
601
|
+
title: task.title, previousState: 'provisioning', newState: task.state,
|
|
602
|
+
revision: getRoomRecord(task.room_id)?.activated_at ?? task.started_at ?? task.created_at,
|
|
603
|
+
list: task.list_name ?? 'default', roomId: task.room_id,
|
|
604
|
+
template: task.template ? `${task.template.name}@${task.template.version}` : undefined,
|
|
605
|
+
agents: taskAgents(task) });
|
|
606
|
+
else if (resultingRoom)
|
|
607
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Task',
|
|
608
|
+
id: task.task_id, state: task.state, category: 'provision_pending', eventId: roomFailureEventId(resultingRoom) });
|
|
497
609
|
return { task, status: 'ready' };
|
|
498
610
|
}
|
|
499
611
|
createTemplate(cfg, requested, noRoom) {
|
|
@@ -539,6 +651,11 @@ export class TaskRoomApplicationService {
|
|
|
539
651
|
room_id: created.room_id, room_name: task.title, room_identity_cid: created.identity_cid,
|
|
540
652
|
task_id: task.task_id, template_snapshot: template,
|
|
541
653
|
});
|
|
654
|
+
recordFleetAuditPresentation({ kind: 'room', operation: 'create', id: room.room_id,
|
|
655
|
+
name: room.room_name, previousState: 'none', newState: 'provisioning',
|
|
656
|
+
revision: room.created_at, taskId: room.task_id,
|
|
657
|
+
template: room.template_snapshot ? `${room.template_snapshot.name}@${room.template_snapshot.version}` : undefined,
|
|
658
|
+
participants: [] });
|
|
542
659
|
onCreated(room);
|
|
543
660
|
room = advanceSaga(room.room_id, 'create_room', 1);
|
|
544
661
|
if (attachOwner) {
|
|
@@ -553,18 +670,39 @@ export class TaskRoomApplicationService {
|
|
|
553
670
|
const mismatch = error instanceof CoworkProtocolError && /CID|expected/i.test(error.message);
|
|
554
671
|
setSagaError(room.room_id, error instanceof Error ? error.message : String(error), mismatch ? 'Verify rooms.owner.expected_cid and rotate the configured invite if necessary.'
|
|
555
672
|
: 'Rotate rooms.owner.public_invite or public_invite_file, then run room recover.', mismatch ? 'owner_cid_mismatch' : 'waiting_owner_invite');
|
|
673
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Room',
|
|
674
|
+
id: room.room_id, state: getRoomRecord(room.room_id)?.state ?? 'provisioning',
|
|
675
|
+
category: 'provision_failed', eventId: roomFailureEventId(getRoomRecord(room.room_id) ?? room) });
|
|
556
676
|
throw error;
|
|
557
677
|
}
|
|
558
678
|
}
|
|
559
679
|
room = advanceSaga(room.room_id, 'create_members', 3);
|
|
560
680
|
if (template?.members.length)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
681
|
+
try {
|
|
682
|
+
room = await (this.deps.provisionMembers ?? provisionMembers)({
|
|
683
|
+
cfg, cowork, roomId: room.room_id, taskId: task.task_id, template,
|
|
684
|
+
binPath: (this.deps.binPath ?? getBinPath)(), brief: task.brief,
|
|
685
|
+
goal: task.task_id ? task.title : task.goal,
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
catch (error) {
|
|
689
|
+
const failed = getRoomRecord(room.room_id) ?? room;
|
|
690
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Room', id: failed.room_id,
|
|
691
|
+
state: failed.state, category: 'provision_failed', eventId: roomFailureEventId(failed) });
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
else
|
|
695
|
+
room = activateRoom(room.room_id);
|
|
696
|
+
if (room.state === 'active')
|
|
697
|
+
recordFleetAuditPresentation({ kind: 'room', operation: 'activate', id: room.room_id,
|
|
698
|
+
name: room.room_name, previousState: 'provisioning', newState: 'active',
|
|
699
|
+
revision: room.activated_at ?? room.created_at, taskId: room.task_id,
|
|
700
|
+
template: room.template_snapshot ? `${room.template_snapshot.name}@${room.template_snapshot.version}` : undefined,
|
|
701
|
+
participants: roomParticipants(room) });
|
|
702
|
+
else
|
|
703
|
+
recordFleetAuditPresentation({ kind: 'lifecycle_failure', resource: 'Room', id: room.room_id,
|
|
704
|
+
state: room.state, category: 'provision_pending', eventId: roomFailureEventId(room) });
|
|
705
|
+
if (task.task_id && !template?.members.length)
|
|
568
706
|
activateTask(task.task_id);
|
|
569
707
|
return room;
|
|
570
708
|
}
|
|
@@ -18,7 +18,7 @@ export interface ResolvedRoleView {
|
|
|
18
18
|
sandbox?: string;
|
|
19
19
|
};
|
|
20
20
|
oversee?: Array<{
|
|
21
|
-
|
|
21
|
+
agent: string;
|
|
22
22
|
interval: string;
|
|
23
23
|
}>;
|
|
24
24
|
}
|
|
@@ -117,7 +117,6 @@ export interface RoleCapabilities {
|
|
|
117
117
|
};
|
|
118
118
|
input: {
|
|
119
119
|
text: boolean;
|
|
120
|
-
rawKeys: boolean;
|
|
121
120
|
interrupt: boolean;
|
|
122
121
|
steering: boolean;
|
|
123
122
|
};
|
|
@@ -125,12 +124,6 @@ export interface RoleCapabilities {
|
|
|
125
124
|
observe: boolean;
|
|
126
125
|
respond: boolean;
|
|
127
126
|
};
|
|
128
|
-
terminal: {
|
|
129
|
-
available: boolean;
|
|
130
|
-
reason?: 'wrong_backend' | 'pty_unavailable' | 'offline' | 'incompatible_runner';
|
|
131
|
-
multiViewer: boolean;
|
|
132
|
-
writerLease: boolean;
|
|
133
|
-
};
|
|
134
127
|
lifecycle: {
|
|
135
128
|
start: boolean;
|
|
136
129
|
stop: boolean;
|
package/dist/briefing.js
CHANGED
|
@@ -172,12 +172,16 @@ export function generateBriefing(role, v, opts) {
|
|
|
172
172
|
if (role.session === 'acp') {
|
|
173
173
|
L.push('', '### Managed fleet commands');
|
|
174
174
|
L.push('This ACP role has a supervisor-scoped ours-fleet proxy. Use the ordinary');
|
|
175
|
-
L.push('`ours-fleet
|
|
176
|
-
L.push('
|
|
177
|
-
L.push('
|
|
178
|
-
L.push('
|
|
175
|
+
L.push('`ours-fleet` command; the CLI routes public commands through your live supervisor.');
|
|
176
|
+
L.push('Your existing OS sandbox remains the executor and ordinary CLI validation still applies.');
|
|
177
|
+
L.push('Reads, help, validation failures, retries, and command invocations are silent in the');
|
|
178
|
+
L.push('Owner channel. Only confirmed Agent, Task, and Room lifecycle changes are announced.');
|
|
179
|
+
L.push('A minimal call is `ours-fleet spawn DeveloperName --temp`.');
|
|
180
|
+
L.push('For omitted settings, the supervisor inherits your canonical Brain and Role selections,');
|
|
179
181
|
L.push('working directory, neutral permissions, coordinator, and fleet monitor policy. Every');
|
|
180
|
-
L.push('explicit
|
|
182
|
+
L.push('explicit option wins; identity/session-local and secret material never inherit.');
|
|
183
|
+
L.push('All public CLI surfaces are available; hidden worker entry points remain internal.');
|
|
184
|
+
L.push('Lifecycle notice delivery failures stay in service diagnostics and never rerun effects.');
|
|
181
185
|
L.push('This proxy is attribution and convenience, not a security boundary for unisolated roles.');
|
|
182
186
|
}
|
|
183
187
|
if (role.coordinator) {
|
|
@@ -190,21 +194,18 @@ export function generateBriefing(role, v, opts) {
|
|
|
190
194
|
L.push(`7. Await messages. When the monitor wakes you (or the owner requests a manual check),`);
|
|
191
195
|
L.push(` call **${v.getMessagesTool}**, act on them,`);
|
|
192
196
|
L.push(` and reply with ${v.sendTool}. No coordinator is configured — the owner drives you`);
|
|
193
|
-
// NOT `tmux attach -t <name>`: each role's pane lives on its own tmux
|
|
194
|
-
// socket (#32), so a bare attach finds no server. `ours-fleet attach`
|
|
195
|
-
// addresses the right one.
|
|
196
197
|
L.push(` via \`ours-fleet attach ${role.name}\` or by messaging "${id}".`);
|
|
197
198
|
}
|
|
198
199
|
if (role.oversee?.length) {
|
|
199
200
|
L.push('', '## Oversight assignments');
|
|
200
201
|
L.push('These agents are your wards — you keep them unstuck:');
|
|
201
202
|
for (const o of role.oversee)
|
|
202
|
-
L.push(`- **${o.
|
|
203
|
+
L.push(`- **${o.agent}** — check every ${o.interval}`);
|
|
203
204
|
L.push('');
|
|
204
205
|
L.push('Procedure (see also the oversee-agents skill if available). On each tick, for each ward');
|
|
205
206
|
L.push('run BOTH — they answer different questions:');
|
|
206
207
|
for (const o of role.oversee)
|
|
207
|
-
L.push(`\`ours-fleet status ${o.
|
|
208
|
+
L.push(`\`ours-fleet status ${o.agent}\` then \`ours-fleet peek ${o.agent}\``);
|
|
208
209
|
L.push('');
|
|
209
210
|
L.push('**One console command is not a liveness verdict.** A `peek` or `send` that fails tells');
|
|
210
211
|
L.push('you what happened to YOUR REQUEST, and only one of its outcomes says the agent is gone.');
|
|
@@ -221,7 +222,7 @@ export function generateBriefing(role, v, opts) {
|
|
|
221
222
|
L.push('idle or stalled from `readiness=idle` alone.');
|
|
222
223
|
L.push('');
|
|
223
224
|
L.push('Then judge the console content: stuck on a prompt/menu/trust dialog → answer it directly');
|
|
224
|
-
L.push('with `ours-fleet send <Name> "<text>"
|
|
225
|
+
L.push('with `ours-fleet send <Name> "<text>"`; idle with work');
|
|
225
226
|
L.push('assigned → nudge; actively working → do nothing, and do not mistake a long turn for a');
|
|
226
227
|
L.push('stall. Escalate over ours messaging only when you cannot resolve it yourself.');
|
|
227
228
|
}
|
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
3
|
-
"buildId": "
|
|
4
|
-
"commit": "
|
|
5
|
-
"dirty":
|
|
6
|
-
"builtAt": "2026-08-
|
|
2
|
+
"version": "1.1.0-nightly.10",
|
|
3
|
+
"buildId": "7fbfbd6e4119",
|
|
4
|
+
"commit": "006179e6e9ae9d9e846045a658a64686c8169ebe",
|
|
5
|
+
"dirty": true,
|
|
6
|
+
"builtAt": "2026-08-31T14:07:48.123Z",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"monitor.interrupt.after_tool"
|
|
9
9
|
]
|