@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.
Files changed (159) hide show
  1. package/README.md +122 -133
  2. package/dist/agent-recovery-gate.d.ts +17 -0
  3. package/dist/agent-recovery-gate.js +135 -0
  4. package/dist/application/capabilities.d.ts +0 -1
  5. package/dist/application/capabilities.js +3 -13
  6. package/dist/application/fleet-query-service.d.ts +0 -3
  7. package/dist/application/fleet-query-service.js +14 -25
  8. package/dist/application/role-creation-service.d.ts +5 -24
  9. package/dist/application/role-creation-service.js +27 -67
  10. package/dist/application/role-removal-service.js +6 -3
  11. package/dist/application/role-repository.d.ts +1 -2
  12. package/dist/application/role-repository.js +7 -7
  13. package/dist/application/session-control.d.ts +0 -12
  14. package/dist/application/session-control.js +0 -42
  15. package/dist/application/session-mutations.d.ts +5 -5
  16. package/dist/application/task-room-service.d.ts +1 -1
  17. package/dist/application/task-room-service.js +154 -16
  18. package/dist/application/types.d.ts +1 -8
  19. package/dist/briefing.js +12 -11
  20. package/dist/build-info.json +5 -5
  21. package/dist/cli.js +143 -63
  22. package/dist/config-yaml.d.ts +1 -1
  23. package/dist/config.d.ts +66 -6
  24. package/dist/config.js +398 -43
  25. package/dist/creation.d.ts +1 -1
  26. package/dist/creation.js +2 -2
  27. package/dist/daemon-recovery.d.ts +93 -0
  28. package/dist/daemon-recovery.js +328 -0
  29. package/dist/docs.d.ts +1 -1
  30. package/dist/docs.js +103 -127
  31. package/dist/doctor.js +18 -11
  32. package/dist/fleet-command-audit.d.ts +160 -0
  33. package/dist/fleet-command-audit.js +433 -0
  34. package/dist/fleet-proxy.d.ts +3 -1
  35. package/dist/fleet-proxy.js +30 -8
  36. package/dist/generated-agent-source.d.ts +9 -0
  37. package/dist/generated-agent-source.js +53 -0
  38. package/dist/harness/acp-session-transport.d.ts +8 -0
  39. package/dist/harness/acp-session-transport.js +3 -0
  40. package/dist/harness/agent-session.d.ts +51 -0
  41. package/dist/harness/agent-session.js +1 -0
  42. package/dist/harness/claude-code-session.d.ts +24 -0
  43. package/dist/harness/claude-code-session.js +36 -0
  44. package/dist/harness/claude-code.d.ts +2 -1
  45. package/dist/harness/claude-code.js +41 -81
  46. package/dist/harness/codex-session.d.ts +24 -0
  47. package/dist/harness/codex-session.js +36 -0
  48. package/dist/harness/codex.d.ts +2 -1
  49. package/dist/harness/codex.js +55 -45
  50. package/dist/harness/registry.js +4 -0
  51. package/dist/harness/types.d.ts +6 -38
  52. package/dist/index.d.ts +4 -6
  53. package/dist/index.js +2 -4
  54. package/dist/init-guidance.d.ts +1 -0
  55. package/dist/init-guidance.js +6 -0
  56. package/dist/isolation/resources.d.ts +3 -7
  57. package/dist/isolation/resources.js +3 -7
  58. package/dist/model-env.d.ts +4 -6
  59. package/dist/model-env.js +5 -8
  60. package/dist/monitor.d.ts +1 -24
  61. package/dist/monitor.js +5 -140
  62. package/dist/ops.js +4 -2
  63. package/dist/owner-channel/channel.d.ts +58 -2
  64. package/dist/owner-channel/channel.js +269 -29
  65. package/dist/owner-channel/commands.d.ts +2 -0
  66. package/dist/owner-channel/commands.js +31 -13
  67. package/dist/owner-channel/state.d.ts +2 -0
  68. package/dist/owner-channel/state.js +8 -2
  69. package/dist/preset-bootstrap.d.ts +10 -0
  70. package/dist/preset-bootstrap.js +85 -0
  71. package/dist/reports/artifact.d.ts +10 -0
  72. package/dist/reports/artifact.js +32 -0
  73. package/dist/reports/index.d.ts +5 -0
  74. package/dist/reports/index.js +5 -0
  75. package/dist/reports/render.d.ts +6 -0
  76. package/dist/reports/render.js +240 -0
  77. package/dist/reports/service.d.ts +42 -0
  78. package/dist/reports/service.js +57 -0
  79. package/dist/reports/tasks.d.ts +52 -0
  80. package/dist/reports/tasks.js +177 -0
  81. package/dist/reports/types.d.ts +315 -0
  82. package/dist/reports/types.js +6 -0
  83. package/dist/resolved-plan.d.ts +3 -2
  84. package/dist/resolved-plan.js +21 -5
  85. package/dist/rooms-tasks/cli.js +225 -40
  86. package/dist/rooms-tasks/config.js +24 -13
  87. package/dist/rooms-tasks/external-worker.d.ts +1 -0
  88. package/dist/rooms-tasks/external-worker.js +14 -9
  89. package/dist/rooms-tasks/provision.js +98 -36
  90. package/dist/rooms-tasks/templates.d.ts +0 -1
  91. package/dist/rooms-tasks/templates.js +9 -76
  92. package/dist/rooms-tasks/types.d.ts +10 -16
  93. package/dist/rooms-tasks/types.js +1 -4
  94. package/dist/runner.d.ts +13 -16
  95. package/dist/runner.js +110 -122
  96. package/dist/sensitive-config.d.ts +2 -0
  97. package/dist/sensitive-config.js +4 -0
  98. package/dist/session/acp.d.ts +7 -2
  99. package/dist/session/acp.js +29 -6
  100. package/dist/session/activity.d.ts +2 -3
  101. package/dist/session/activity.js +2 -3
  102. package/dist/session/arbiter.d.ts +4 -4
  103. package/dist/session/control.d.ts +17 -4
  104. package/dist/session/control.js +35 -0
  105. package/dist/session/types.d.ts +11 -5
  106. package/dist/spawn.d.ts +8 -33
  107. package/dist/spawn.js +53 -213
  108. package/dist/supervisor/none.d.ts +1 -1
  109. package/dist/supervisor/none.js +2 -2
  110. package/dist/temp-lifecycle.d.ts +1 -1
  111. package/dist/tmux.d.ts +1 -14
  112. package/dist/tmux.js +1 -51
  113. package/dist/watchdog/config.d.ts +10 -7
  114. package/dist/watchdog/config.js +30 -18
  115. package/dist/watchdog/run.js +12 -36
  116. package/dist/web/auth.d.ts +1 -1
  117. package/dist/web/fleet-config-service.d.ts +11 -8
  118. package/dist/web/fleet-config-service.js +384 -183
  119. package/dist/web/runtime.js +4 -15
  120. package/dist/web/server.d.ts +1 -3
  121. package/dist/web/server.js +3 -14
  122. package/dist/web/topology-promote.js +26 -19
  123. package/dist/web/topology.js +2 -2
  124. package/dist/web/yaml-document-edit.js +2 -0
  125. package/dist/web-app/assets/index-59GF-gsZ.css +1 -0
  126. package/dist/web-app/assets/index-BbTc5KtZ.js +10 -0
  127. package/dist/web-app/index.html +2 -2
  128. package/examples/fleet/agents/Alice.yaml +11 -0
  129. package/examples/fleet/agents/FleetCoordinator.yaml +7 -0
  130. package/examples/fleet/brains/claude-default.yaml +5 -0
  131. package/examples/fleet/roles/coordinator.yaml +5 -0
  132. package/examples/fleet/roles/developer.yaml +3 -0
  133. package/examples/fleet.yaml +74 -0
  134. package/package.json +5 -8
  135. package/presets/fleet/agents/Agent.yaml +3 -0
  136. package/presets/fleet/agents/Architect.yaml +3 -0
  137. package/presets/fleet/agents/Critic.yaml +3 -0
  138. package/presets/fleet/agents/Developer.yaml +3 -0
  139. package/presets/fleet/agents/Secretary.yaml +3 -0
  140. package/presets/fleet/agents/Tester.yaml +3 -0
  141. package/presets/fleet/brains/claude-default.yaml +5 -0
  142. package/presets/fleet/roles/Agent.yaml +6 -0
  143. package/presets/fleet/roles/Architect.yaml +6 -0
  144. package/presets/fleet/roles/Critic.yaml +6 -0
  145. package/presets/fleet/roles/Developer.yaml +6 -0
  146. package/presets/fleet/roles/Secretary.yaml +6 -0
  147. package/presets/fleet/roles/Tester.yaml +6 -0
  148. package/presets/fleet/room_templates/pair.yaml +11 -0
  149. package/presets/fleet/room_templates/single.yaml +8 -0
  150. package/presets/fleet/room_templates/team.yaml +12 -0
  151. package/presets/fleet.yaml +7 -0
  152. package/presets/manifest.json +5 -0
  153. package/dist/session/tmux.d.ts +0 -28
  154. package/dist/session/tmux.js +0 -80
  155. package/dist/web/terminal/bridge.d.ts +0 -27
  156. package/dist/web/terminal/bridge.js +0 -317
  157. package/dist/web-app/assets/TerminalView-C_G1ID2P.js +0 -9
  158. package/dist/web-app/assets/index-BCBK78hw.js +0 -10
  159. 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, room => {
49
- task = updateTaskRoom(task.task_id, room.room_id, room.room_identity_cid);
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
- await this.provisionRoom(cfg, task, template, room => {
81
- task = updateTaskRoom(task.task_id, room.room_id, room.room_identity_cid);
82
- });
83
- task = readTask(task.task_id);
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 => cfg.roles.some(role => role.name === member.role_ref)
263
- ? [] : [`member ${member.slot}: role_ref '${member.role_ref}' not found in fleet roles`]);
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
- return (this.deps.provisionMembers ?? provisionMembers)({
562
- cfg, cowork, roomId: room.room_id, taskId: task.task_id, template,
563
- binPath: (this.deps.binPath ?? getBinPath)(), brief: task.brief,
564
- goal: task.task_id ? task.title : task.goal,
565
- });
566
- room = activateRoom(room.room_id);
567
- if (task.task_id)
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
- role: string;
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 spawn` command; the CLI routes it through your live supervisor, which');
176
- L.push('records you as the caller and reports successful creation to your owner channel.');
177
- L.push('A minimal call is `ours-fleet spawn --role DeveloperName --temp`.');
178
- L.push('For omitted execution settings, the supervisor inherits your harness, session, model,');
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 spawn option wins. An explicit different harness does not inherit your model.');
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.role}** — check every ${o.interval}`);
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.role}\` then \`ours-fleet peek ${o.role}\``);
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>"` (or `--key <K>` for raw keys); idle with work');
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
  }
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "1.0.5",
3
- "buildId": "233dcfbef2e0",
4
- "commit": "5846aa20eb58d5c4ecf8a98bb6a7d3f578afdc2b",
5
- "dirty": false,
6
- "builtAt": "2026-08-26T08:39:49.505Z",
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
  ]