@ours.network/fleet 1.1.0-nightly.2 → 1.1.0-nightly.20

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 (199) hide show
  1. package/README.md +169 -54
  2. package/dist/agent-recovery-gate.d.ts +17 -0
  3. package/dist/agent-recovery-gate.js +135 -0
  4. package/dist/application/capabilities.js +18 -6
  5. package/dist/application/fleet-query-service.js +20 -5
  6. package/dist/application/role-command-service.js +9 -0
  7. package/dist/application/role-creation-service.d.ts +6 -25
  8. package/dist/application/role-creation-service.js +34 -72
  9. package/dist/application/role-repository.d.ts +4 -2
  10. package/dist/application/role-repository.js +6 -3
  11. package/dist/application/session-control.d.ts +3 -1
  12. package/dist/application/session-control.js +4 -2
  13. package/dist/application/task-room-service.d.ts +58 -6
  14. package/dist/application/task-room-service.js +426 -78
  15. package/dist/briefing.js +74 -24
  16. package/dist/build-info.json +4 -4
  17. package/dist/canonical-json.d.ts +2 -0
  18. package/dist/canonical-json.js +10 -0
  19. package/dist/cli.js +227 -73
  20. package/dist/config-yaml.d.ts +1 -1
  21. package/dist/config.d.ts +67 -2
  22. package/dist/config.js +260 -30
  23. package/dist/daemon-recovery.d.ts +93 -0
  24. package/dist/daemon-recovery.js +328 -0
  25. package/dist/docs.d.ts +1 -1
  26. package/dist/docs.js +171 -66
  27. package/dist/doctor.d.ts +2 -0
  28. package/dist/doctor.js +54 -4
  29. package/dist/fleet-command-audit.d.ts +165 -0
  30. package/dist/fleet-command-audit.js +543 -0
  31. package/dist/fleet-proxy.d.ts +7 -2
  32. package/dist/fleet-proxy.js +30 -8
  33. package/dist/harness/agent-session.d.ts +5 -0
  34. package/dist/harness/claude-code-session.d.ts +2 -0
  35. package/dist/harness/claude-code-session.js +6 -1
  36. package/dist/harness/claude-code.js +2 -0
  37. package/dist/harness/codex-app-server-proxy.d.ts +40 -0
  38. package/dist/harness/codex-app-server-proxy.js +348 -14
  39. package/dist/harness/codex-session.d.ts +11 -2
  40. package/dist/harness/codex-session.js +22 -2
  41. package/dist/harness/codex.d.ts +5 -1
  42. package/dist/harness/codex.js +110 -10
  43. package/dist/harness/types.d.ts +1 -1
  44. package/dist/index.d.ts +5 -4
  45. package/dist/index.js +4 -3
  46. package/dist/init-guidance.d.ts +1 -1
  47. package/dist/init-guidance.js +4 -3
  48. package/dist/init-wizard.d.ts +98 -0
  49. package/dist/init-wizard.js +629 -0
  50. package/dist/lifecycle-summary.d.ts +118 -0
  51. package/dist/lifecycle-summary.js +161 -0
  52. package/dist/loops/config.js +3 -2
  53. package/dist/model-env.d.ts +2 -2
  54. package/dist/model-env.js +1 -1
  55. package/dist/model-recovery.d.ts +1 -1
  56. package/dist/ops.js +2 -17
  57. package/dist/owner-channel/channel.d.ts +58 -0
  58. package/dist/owner-channel/channel.js +321 -42
  59. package/dist/owner-channel/commands.d.ts +6 -1
  60. package/dist/owner-channel/commands.js +34 -19
  61. package/dist/owner-channel/state.d.ts +2 -0
  62. package/dist/owner-channel/state.js +8 -2
  63. package/dist/permissions.js +1 -1
  64. package/dist/preset-bootstrap.d.ts +10 -0
  65. package/dist/preset-bootstrap.js +85 -0
  66. package/dist/preset-migration.d.ts +42 -0
  67. package/dist/preset-migration.js +414 -0
  68. package/dist/reports/artifact.d.ts +10 -0
  69. package/dist/reports/artifact.js +32 -0
  70. package/dist/reports/index.d.ts +5 -0
  71. package/dist/reports/index.js +5 -0
  72. package/dist/reports/render.d.ts +6 -0
  73. package/dist/reports/render.js +240 -0
  74. package/dist/reports/service.d.ts +42 -0
  75. package/dist/reports/service.js +57 -0
  76. package/dist/reports/tasks.d.ts +52 -0
  77. package/dist/reports/tasks.js +177 -0
  78. package/dist/reports/types.d.ts +315 -0
  79. package/dist/reports/types.js +6 -0
  80. package/dist/resolved-plan.js +4 -0
  81. package/dist/rooms-tasks/cli.d.ts +2 -0
  82. package/dist/rooms-tasks/cli.js +503 -75
  83. package/dist/rooms-tasks/close.d.ts +9 -1
  84. package/dist/rooms-tasks/close.js +20 -4
  85. package/dist/rooms-tasks/config.js +16 -14
  86. package/dist/rooms-tasks/cowork-adapter.d.ts +1 -0
  87. package/dist/rooms-tasks/cowork-adapter.js +6 -0
  88. package/dist/rooms-tasks/deletion.d.ts +51 -0
  89. package/dist/rooms-tasks/deletion.js +217 -0
  90. package/dist/rooms-tasks/external-worker.d.ts +1 -0
  91. package/dist/rooms-tasks/external-worker.js +14 -9
  92. package/dist/rooms-tasks/launch-snapshot.d.ts +19 -0
  93. package/dist/rooms-tasks/launch-snapshot.js +176 -0
  94. package/dist/rooms-tasks/member-overrides.d.ts +27 -0
  95. package/dist/rooms-tasks/member-overrides.js +170 -0
  96. package/dist/rooms-tasks/provision.js +179 -49
  97. package/dist/rooms-tasks/room-state.d.ts +1 -0
  98. package/dist/rooms-tasks/room-state.js +12 -1
  99. package/dist/rooms-tasks/task-state.d.ts +115 -3
  100. package/dist/rooms-tasks/task-state.js +361 -11
  101. package/dist/rooms-tasks/templates.d.ts +4 -2
  102. package/dist/rooms-tasks/templates.js +42 -78
  103. package/dist/rooms-tasks/terminal.d.ts +3 -0
  104. package/dist/rooms-tasks/terminal.js +7 -3
  105. package/dist/rooms-tasks/types.d.ts +94 -17
  106. package/dist/rooms-tasks/types.js +14 -4
  107. package/dist/runner.d.ts +9 -2
  108. package/dist/runner.js +107 -40
  109. package/dist/session/acp.d.ts +9 -1
  110. package/dist/session/acp.js +35 -9
  111. package/dist/session/arbiter.d.ts +2 -1
  112. package/dist/session/arbiter.js +2 -0
  113. package/dist/session/codex-app-server-transport.d.ts +53 -0
  114. package/dist/session/codex-app-server-transport.js +184 -0
  115. package/dist/session/codex-app-server.d.ts +122 -0
  116. package/dist/session/codex-app-server.js +1031 -0
  117. package/dist/session/control.d.ts +14 -1
  118. package/dist/session/control.js +38 -0
  119. package/dist/session/conversation-types.d.ts +4 -4
  120. package/dist/session/types.d.ts +24 -6
  121. package/dist/session/types.js +28 -0
  122. package/dist/spawn.d.ts +6 -31
  123. package/dist/spawn.js +57 -234
  124. package/dist/temp-lifecycle.d.ts +1 -1
  125. package/dist/watchdog/config.d.ts +10 -7
  126. package/dist/watchdog/config.js +29 -19
  127. package/dist/watchdog/run.js +4 -13
  128. package/dist/web/fleet-config-service.d.ts +1 -0
  129. package/dist/web/fleet-config-service.js +27 -8
  130. package/dist/web/runtime.js +11 -6
  131. package/dist/web/server.js +28 -1
  132. package/dist/web/topology-promote.js +8 -1
  133. package/dist/web-app/assets/index-C0h3ALvs.js +10 -0
  134. package/dist/web-app/index.html +1 -1
  135. package/package.json +3 -2
  136. package/presets/brain-catalog.json +16 -0
  137. package/presets/fleet/agent_templates/Critic.yaml +4 -0
  138. package/presets/fleet/agent_templates/Developer.yaml +4 -0
  139. package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -0
  140. package/presets/fleet/agents/FleetCoordinator.yaml +3 -0
  141. package/presets/fleet/brains/claude-default.yaml +5 -0
  142. package/presets/fleet/brains/claude-fable-5-high.yaml +5 -0
  143. package/presets/fleet/brains/claude-fable-5-low.yaml +5 -0
  144. package/presets/fleet/brains/claude-fable-5-max.yaml +5 -0
  145. package/presets/fleet/brains/claude-fable-5-medium.yaml +5 -0
  146. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +5 -0
  147. package/presets/fleet/brains/claude-opus-5-high.yaml +5 -0
  148. package/presets/fleet/brains/claude-opus-5-low.yaml +5 -0
  149. package/presets/fleet/brains/claude-opus-5-max.yaml +5 -0
  150. package/presets/fleet/brains/claude-opus-5-medium.yaml +5 -0
  151. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +5 -0
  152. package/presets/fleet/brains/claude-sonnet-5-high.yaml +5 -0
  153. package/presets/fleet/brains/claude-sonnet-5-low.yaml +5 -0
  154. package/presets/fleet/brains/claude-sonnet-5-max.yaml +5 -0
  155. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +5 -0
  156. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +5 -0
  157. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +5 -0
  158. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +5 -0
  159. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +5 -0
  160. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +5 -0
  161. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +5 -0
  162. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +5 -0
  163. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +5 -0
  164. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +5 -0
  165. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +5 -0
  166. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +5 -0
  167. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +5 -0
  168. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +5 -0
  169. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +5 -0
  170. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +5 -0
  171. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +5 -0
  172. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +5 -0
  173. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +5 -0
  174. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +5 -0
  175. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +5 -0
  176. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +5 -0
  177. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +5 -0
  178. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +5 -0
  179. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +5 -0
  180. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +5 -0
  181. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +5 -0
  182. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +5 -0
  183. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +5 -0
  184. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +5 -0
  185. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +5 -0
  186. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +5 -0
  187. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +5 -0
  188. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +5 -0
  189. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +5 -0
  190. package/presets/fleet/roles/Coordinator.yaml +30 -0
  191. package/presets/fleet/roles/Critic.yaml +19 -0
  192. package/presets/fleet/roles/Developer.yaml +19 -0
  193. package/presets/fleet/roles/LocalCoordinator.yaml +25 -0
  194. package/presets/fleet/room_templates/pair.yaml +10 -0
  195. package/presets/fleet/room_templates/single.yaml +7 -0
  196. package/presets/fleet/room_templates/team.yaml +12 -0
  197. package/presets/fleet.yaml +7 -0
  198. package/presets/manifest.json +6 -0
  199. package/dist/web-app/assets/index-BbE9EX6n.js +0 -10
@@ -1,25 +1,18 @@
1
- import { type CommonPermissions, type MonitorConfig, type MonitorInterrupt, type NotifyEventType } from '../config.js';
1
+ import { type CommonPermissions, type MonitorConfig, type MonitorInterrupt, type NotifyEventType, type SessionBackendId } from '../config.js';
2
2
  import { type IdentityProvisioner } from '../creation.js';
3
3
  import { spawnDryRun, type SpawnOpts, type SupervisorLauncher } from '../spawn.js';
4
4
  import type { OpsDeps } from '../ops.js';
5
5
  import type { ResolvedRole } from '../config.js';
6
6
  import { FleetError } from './errors.js';
7
7
  import { type ManagedFleetSpawnResult } from '../fleet-proxy.js';
8
- import { type HarnessModelCatalog, type HarnessModelOption } from './model-catalog.js';
9
8
  export interface CreateRoleSessionRequest {
10
9
  name: string;
11
- harness: 'codex' | 'claude-code';
12
- /** null means the selected harness's own default; web blank fields send null. */
13
- model?: string | null;
14
- reasoningEffort?: string | null;
15
- session: 'acp';
10
+ brain: import('../config.js').AgentSelection;
11
+ role: import('../config.js').AgentSelection;
16
12
  cwd?: string;
17
13
  lifetime: 'permanent' | 'temporary';
18
- mission?: string;
19
14
  coordinator?: string;
20
15
  permissions: CommonPermissions;
21
- bio?: string;
22
- persona?: string;
23
16
  monitor?: WebCreationMonitor;
24
17
  openAfterCreate: boolean;
25
18
  highRiskAcknowledged?: boolean;
@@ -38,17 +31,6 @@ export type WebCreationMonitor = {
38
31
  export interface CreationCapabilities {
39
32
  available: boolean;
40
33
  reasons: string[];
41
- harnesses: Array<{
42
- id: 'codex' | 'claude-code';
43
- available: boolean;
44
- sessions: Array<'acp'>;
45
- defaultModel?: string;
46
- models: string[];
47
- modelOptions: HarnessModelOption[];
48
- catalogSource: string;
49
- customModelAllowed: true;
50
- warnings: string[];
51
- }>;
52
34
  lifetimes: Array<'permanent' | 'temporary'>;
53
35
  identityBootstrap: {
54
36
  mode: 'current-fleet-first-boot';
@@ -71,7 +53,7 @@ export interface CreationPreview {
71
53
  name: string;
72
54
  identity: string;
73
55
  harness: string;
74
- session: 'acp';
56
+ session: SessionBackendId;
75
57
  model?: string;
76
58
  reasoningEffort?: string;
77
59
  cwd?: string;
@@ -95,7 +77,7 @@ export interface CreationAction {
95
77
  actionId: string;
96
78
  requestHash: string;
97
79
  roleId: string;
98
- session: 'acp';
80
+ session: SessionBackendId;
99
81
  lifetime: 'permanent' | 'temporary';
100
82
  state: CreationStage;
101
83
  stages: Array<{
@@ -121,9 +103,8 @@ export interface RoleCreationServiceOptions {
121
103
  tempLauncher?: SupervisorLauncher;
122
104
  allowedCwdRoots?: string[];
123
105
  journalDir?: string;
124
- probeReady?: (name: string, session: 'acp') => Promise<'ready' | 'attention' | 'unknown'>;
106
+ probeReady?: (name: string, session: SessionBackendId) => Promise<'ready' | 'attention' | 'unknown'>;
125
107
  onProgress?: (action: CreationAction) => void;
126
- modelCatalogs?: Partial<Record<'codex' | 'claude-code', () => HarnessModelCatalog>>;
127
108
  /** Direct/managed callers must not create or restore the web action journal. */
128
109
  journal?: boolean;
129
110
  }
@@ -1,17 +1,16 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { mkdirSync, readFileSync, readdirSync, realpathSync, statSync } from 'node:fs';
3
3
  import { isAbsolute, relative } from 'node:path';
4
- import { loadConfig, NOTIFY_EVENT_TYPES, resolveMonitorConfig, resolveRoleModel, resolvePermissions, ROLE_NAME_RE, validateMonitorConfig, } from '../config.js';
4
+ import { loadConfig, NOTIFY_EVENT_TYPES, resolveMonitorConfig, resolvePermissions, ROLE_NAME_RE, validateMonitorConfig, } from '../config.js';
5
5
  import { daemonIdentityProvisioner, } from '../creation.js';
6
6
  import { replaceFileAtomically } from '../atomic-file.js';
7
7
  import { stateRoot } from '../paths.js';
8
- import { buildRoleConfig, spawnDryRun, spawnPermanent, spawnTemp, validateSpawnOpts, } from '../spawn.js';
8
+ import { spawnDryRun, spawnPermanent, spawnTemp, validateSpawnOpts, } from '../spawn.js';
9
9
  import { FleetError, normalizeError } from './errors.js';
10
10
  import { inheritCallerSpawnDefaults } from '../fleet-proxy.js';
11
11
  import { effectivePermissionMode } from '../permissions.js';
12
12
  import { effectiveRoleModel } from '../model-env.js';
13
- import { getAdapter } from '../harness/registry.js';
14
- import { claudeModelCatalog, codexModelCatalog, } from './model-catalog.js';
13
+ import { selectionOrigin, summarizeResolvedLaunch } from '../lifecycle-summary.js';
15
14
  const canonical = (value) => {
16
15
  if (Array.isArray(value))
17
16
  return `[${value.map(canonical).join(',')}]`;
@@ -63,14 +62,31 @@ export class RoleCreationService {
63
62
  const creationActionId = randomUUID();
64
63
  plan.options.creationActionId = creationActionId;
65
64
  const statePath = await this.launchSync(plan.options);
65
+ const selectionSummary = (kind) => {
66
+ const value = plan.options[kind];
67
+ const provenance = plan.inherited.includes(kind) ? 'inherited' : 'explicit';
68
+ if (!value)
69
+ return `unresolved (${provenance})`;
70
+ if ('ref' in value)
71
+ return `ref:${value.ref} (${provenance})`;
72
+ const fingerprint = hash(value.inline).slice(0, 16);
73
+ return `inline:sha256:${fingerprint} (${provenance})`;
74
+ };
75
+ const permissionMode = effectivePermissionMode(plan.preview.resolvedRole);
66
76
  return {
67
77
  caller: plan.caller, role: plan.options.name,
68
78
  lifetime: plan.options.temp ? 'temporary' : 'permanent', statePath,
69
79
  harness: plan.preview.resolvedRole.harness, session: plan.preview.resolvedRole.session,
70
80
  ...(effectiveRoleModel(plan.preview.resolvedRole) ? { model: effectiveRoleModel(plan.preview.resolvedRole) } : {}),
71
81
  monitor: { mode: plan.preview.resolvedRole.monitor.mode, interrupt: plan.preview.resolvedRole.monitor.interrupt },
72
- permissionMode: effectivePermissionMode(plan.preview.resolvedRole), inherited: plan.inherited,
82
+ permissionMode, inherited: plan.inherited,
73
83
  creationActionId,
84
+ brainSummary: selectionSummary('brain'), roleSummary: selectionSummary('role'),
85
+ configuration: summarizeResolvedLaunch(plan.preview.resolvedRole, {
86
+ role: selectionOrigin(plan.options.role ?? plan.options.agentDefinition?.role),
87
+ brain: selectionOrigin(plan.options.brain ?? plan.options.agentDefinition?.brain),
88
+ permissionMode,
89
+ }),
74
90
  };
75
91
  }
76
92
  launchSync(options, creation) {
@@ -81,47 +97,16 @@ export class RoleCreationService {
81
97
  async capabilities() {
82
98
  const reasons = [];
83
99
  let defaults = {};
84
- let roles = [];
85
100
  try {
86
101
  const config = loadConfig(this.options.configPath);
87
102
  defaults = config.defaults;
88
- roles = config.roles;
89
103
  }
90
104
  catch (error) {
91
105
  reasons.push(`configuration is invalid: ${error.message}`);
92
106
  }
93
- const modelsFor = (harness, catalog) => {
94
- const configured = roles.filter(role => role.harness === harness)
95
- .flatMap(role => [role.model, ...(role.model_chain ?? [])])
96
- .filter((model) => Boolean(model));
97
- const inherited = resolveRoleModel(undefined, harness, defaults);
98
- const configuredOptions = [...new Set([...(inherited ? [inherited] : []), ...configured])]
99
- .filter(id => !catalog.models.some(model => model.id === id))
100
- .map(id => ({ id, label: `${id} (configured)`, reasoningEfforts: [], source: 'fleet-config' }));
101
- const modelOptions = [...configuredOptions, ...catalog.models];
102
- return { modelOptions, models: modelOptions.map(model => model.id) };
103
- };
104
- const codexCatalog = this.options.modelCatalogs?.codex?.() ?? codexModelCatalog();
105
- const claudeCatalog = this.options.modelCatalogs?.['claude-code']?.() ?? claudeModelCatalog();
106
- const codexModels = modelsFor('codex', codexCatalog);
107
- const claudeModels = modelsFor('claude-code', claudeCatalog);
108
107
  return {
109
108
  available: reasons.length === 0,
110
109
  reasons,
111
- harnesses: [
112
- {
113
- id: 'codex', available: true, sessions: ['acp'],
114
- defaultModel: resolveRoleModel(undefined, 'codex', defaults),
115
- ...codexModels, catalogSource: 'codex-runtime-catalog', customModelAllowed: true,
116
- warnings: codexCatalog.warnings,
117
- },
118
- {
119
- id: 'claude-code', available: true, sessions: ['acp'],
120
- defaultModel: resolveRoleModel(undefined, 'claude-code', defaults),
121
- ...claudeModels, catalogSource: 'claude-adapter-2.1', customModelAllowed: true,
122
- warnings: claudeCatalog.warnings,
123
- },
124
- ],
125
110
  lifetimes: ['permanent', 'temporary'],
126
111
  identityBootstrap: {
127
112
  mode: 'current-fleet-first-boot',
@@ -145,14 +130,12 @@ export class RoleCreationService {
145
130
  const defaults = cfg.defaults;
146
131
  const opts = this.spawnOptions(request);
147
132
  validateSpawnOpts(opts);
148
- buildRoleConfig(opts, defaults.harness);
133
+ const resolved = spawnDryRun(opts).resolvedRole;
149
134
  const cwd = request.cwd ? this.resolveCwd(request.cwd) : undefined;
150
135
  const effective = {
151
136
  name: request.name, identity: request.name,
152
- harness: request.harness ?? defaults.harness ?? 'claude-code',
153
- session: request.session ?? defaults.session ?? 'acp',
154
- model: resolveRoleModel(request.model, request.harness, defaults),
155
- reasoningEffort: request.reasoningEffort ?? undefined,
137
+ harness: resolved.harness, session: resolved.session, model: resolved.model,
138
+ reasoningEffort: resolved.effort,
156
139
  cwd, lifetime: request.lifetime,
157
140
  permissions: resolvePermissions(defaults.permissions, request.permissions),
158
141
  monitor: resolveMonitorConfig(defaults.monitor, request.monitor),
@@ -184,9 +167,7 @@ export class RoleCreationService {
184
167
  if (existingIdentity === 'unknown' && !request.unverifiedIdentityAcknowledged)
185
168
  prerequisites.push('confirm creation with an unverified identity preflight');
186
169
  const provenance = {
187
- harness: 'request', session: 'request', identity: 'built-in',
188
- model: request.model !== undefined ? 'request'
189
- : resolveRoleModel(undefined, request.harness, defaults) ? 'fleet-default' : 'built-in',
170
+ brain: 'request', role: 'request', identity: 'built-in',
190
171
  cwd: request.cwd ? 'request' : 'built-in', permissions: 'request',
191
172
  monitor: request.monitor ? 'request' : defaults.monitor ? 'fleet-default' : 'built-in',
192
173
  };
@@ -297,8 +278,8 @@ export class RoleCreationService {
297
278
  }
298
279
  validate(input) {
299
280
  const allowed = new Set([
300
- 'name', 'harness', 'model', 'reasoningEffort', 'session', 'cwd', 'lifetime', 'mission',
301
- 'coordinator', 'permissions', 'bio', 'persona', 'monitor', 'openAfterCreate',
281
+ 'name', 'brain', 'role', 'cwd', 'lifetime',
282
+ 'coordinator', 'permissions', 'monitor', 'openAfterCreate',
302
283
  'highRiskAcknowledged', 'reuseExistingIdentityAcknowledged',
303
284
  'unverifiedIdentityAcknowledged',
304
285
  ]);
@@ -308,26 +289,11 @@ export class RoleCreationService {
308
289
  throw new FleetError('invalid_request', `unsupported web creation field: ${unsupported[0]}`);
309
290
  if (!ROLE_NAME_RE.test(input.name))
310
291
  throw new FleetError('invalid_request', 'invalid role name');
311
- if (!['codex', 'claude-code'].includes(input.harness))
312
- throw new FleetError('invalid_request', 'unsupported harness');
313
- if (input.session !== 'acp')
314
- throw new FleetError('invalid_request', 'unsupported session backend');
292
+ if (!input.brain || !input.role)
293
+ throw new FleetError('invalid_request', 'brain and role selections are required');
315
294
  if (!['permanent', 'temporary'].includes(input.lifetime))
316
295
  throw new FleetError('invalid_request', 'unsupported lifetime');
317
- bounded(input.model ?? undefined, 'model', 128);
318
- bounded(input.reasoningEffort ?? undefined, 'reasoning effort', 16);
319
- if (input.reasoningEffort != null) {
320
- try {
321
- getAdapter(input.harness).agentSession.resolveBrain({ effort: input.reasoningEffort });
322
- }
323
- catch (error) {
324
- throw new FleetError('invalid_request', error.message);
325
- }
326
- }
327
- bounded(input.mission, 'mission', 4_096);
328
296
  bounded(input.coordinator, 'coordinator', 128);
329
- bounded(input.bio, 'bio', 8_192);
330
- bounded(input.persona, 'persona', 16_384);
331
297
  resolvePermissions(undefined, input.permissions);
332
298
  if (input.monitor) {
333
299
  const problems = validateMonitorConfig(input.monitor);
@@ -337,10 +303,8 @@ export class RoleCreationService {
337
303
  throw new FleetError('invalid_request', 'web creation supports monitor.inject=notification only');
338
304
  }
339
305
  return {
340
- ...input, model: input.model === null ? null : input.model?.trim() || undefined,
341
- reasoningEffort: input.reasoningEffort === null ? null : input.reasoningEffort?.trim() || undefined,
342
- mission: input.mission?.trim() || undefined, coordinator: input.coordinator?.trim() || undefined,
343
- bio: input.bio?.trim() || undefined, persona: input.persona?.trim() || undefined,
306
+ ...input, brain: structuredClone(input.brain), role: structuredClone(input.role),
307
+ coordinator: input.coordinator?.trim() || undefined,
344
308
  monitor: input.monitor ? structuredClone(input.monitor) : undefined,
345
309
  };
346
310
  }
@@ -367,12 +331,10 @@ export class RoleCreationService {
367
331
  spawnOptions(request, creationActionId) {
368
332
  return {
369
333
  name: request.name, temp: request.lifetime === 'temporary',
370
- identity: request.name, harness: request.harness,
371
- model: request.model, session: request.session, cwd: request.cwd,
372
- reasoningEffort: request.reasoningEffort,
373
- mission: request.mission, coordinator: request.coordinator,
334
+ identity: request.name, brain: request.brain, role: request.role, cwd: request.cwd,
335
+ coordinator: request.coordinator,
374
336
  approval: request.permissions.approval, filesystem: request.permissions.filesystem,
375
- unattended: request.permissions.unattended, bio: request.bio, persona: request.persona,
337
+ unattended: request.permissions.unattended,
376
338
  monitorConfig: request.monitor,
377
339
  configPath: this.options.configPath,
378
340
  surface: creationActionId ? 'web' : undefined, creationActionId,
@@ -1,10 +1,12 @@
1
+ import { type SessionBackendId } from '../config.js';
1
2
  import type { RoleRecord } from './types.js';
2
3
  export interface RoleRepositoryOptions {
3
4
  configPath?: string;
4
5
  permanentRoot?: string;
5
6
  temporaryRoot?: string;
6
- probeBackend?: (name: string, intended?: 'acp') => Promise<{
7
- acp: boolean;
7
+ probeBackend?: (name: string, intended?: SessionBackendId) => Promise<{
8
+ acp?: boolean;
9
+ backend?: SessionBackendId;
8
10
  }>;
9
11
  concurrency?: number;
10
12
  timeoutMs?: number;
@@ -44,9 +44,10 @@ function snapshot(path, name) {
44
44
  throw new Error('snapshot must be a mapping');
45
45
  if (raw.session === 'tmux')
46
46
  throw new Error('session: tmux is no longer supported; use session: acp with the Codex or Claude Code adapter');
47
- if (raw.session !== undefined && raw.session !== 'acp')
48
- throw new Error(`unsupported session '${String(raw.session)}'; expected session: acp`);
49
- const session = 'acp';
47
+ if (raw.session !== undefined && raw.session !== 'acp'
48
+ && raw.session !== 'codex-app-server')
49
+ throw new Error(`unsupported session '${String(raw.session)}'; expected session: acp or codex-app-server`);
50
+ const session = raw.session ?? 'acp';
50
51
  return {
51
52
  role: {
52
53
  ...raw, name, harness: typeof raw.harness === 'string' ? raw.harness : 'claude-code',
@@ -173,6 +174,8 @@ export class RoleRepository {
173
174
  this.options.probeBackend(name, intended),
174
175
  new Promise(resolve => setTimeout(() => resolve({ acp: false }), timeoutMs)),
175
176
  ]).catch(() => ({ acp: false }));
177
+ if (result.backend)
178
+ return result.backend;
176
179
  if (result.acp)
177
180
  return 'acp';
178
181
  return 'none';
@@ -71,7 +71,7 @@ export interface RoleSessionControl {
71
71
  onClose(reason?: string): void;
72
72
  }): Promise<ConversationFollowHandle>;
73
73
  }
74
- export declare class AcpRoleSessionAdapter implements RoleSessionControl {
74
+ export declare class RoleSessionControlAdapter implements RoleSessionControl {
75
75
  private readonly stateDir;
76
76
  private readonly request;
77
77
  constructor(stateDir: string, request?: typeof controlRequest);
@@ -119,3 +119,5 @@ export declare class AcpRoleSessionAdapter implements RoleSessionControl {
119
119
  }>;
120
120
  private call;
121
121
  }
122
+ /** @deprecated Compatibility name; control is provider-neutral. */
123
+ export { RoleSessionControlAdapter as AcpRoleSessionAdapter };
@@ -1,7 +1,7 @@
1
1
  import { controlRequest, followConversation } from '../session/control.js';
2
2
  import { FleetError, normalizeError } from './errors.js';
3
3
  const visibleEvents = (events) => events.filter(event => event.kind !== 'thought');
4
- export class AcpRoleSessionAdapter {
4
+ export class RoleSessionControlAdapter {
5
5
  stateDir;
6
6
  request;
7
7
  constructor(stateDir, request = controlRequest) {
@@ -12,7 +12,7 @@ export class AcpRoleSessionAdapter {
12
12
  const response = await this.call('snapshot');
13
13
  const result = response;
14
14
  return {
15
- backend: 'acp', protocolVersion: result.protocolVersion ?? 1,
15
+ backend: result.backend, protocolVersion: result.protocolVersion ?? 1,
16
16
  features: result.features ?? [], snapshot: result,
17
17
  };
18
18
  }
@@ -147,3 +147,5 @@ export class AcpRoleSessionAdapter {
147
147
  }
148
148
  }
149
149
  }
150
+ /** @deprecated Compatibility name; control is provider-neutral. */
151
+ export { RoleSessionControlAdapter as AcpRoleSessionAdapter };
@@ -2,7 +2,10 @@ import { type FleetConfig } from '../config.js';
2
2
  import { type CoworkAdapter } from '../rooms-tasks/cowork-adapter.js';
3
3
  import { provisionMembers } from '../rooms-tasks/provision.js';
4
4
  import { moveTaskToList } from '../rooms-tasks/task-state.js';
5
- import type { RoomOrchestrationRecord, TaskListRecord, TaskOrigin, TaskOutcome, TaskRecord, TaskState } from '../rooms-tasks/types.js';
5
+ import { type MemberOverrides } from '../rooms-tasks/member-overrides.js';
6
+ import { type TaskDeletionSettleResult } from '../rooms-tasks/deletion.js';
7
+ import type { RoomLaunchPolicy, RoomOrchestrationRecord, TaskListRecord, TaskOrigin, TaskOutcome, TaskRecord, TaskState, TemplateSnapshot } from '../rooms-tasks/types.js';
8
+ import type { TaskDeletionAcceptance } from '../rooms-tasks/task-state.js';
6
9
  export type TaskRoomActor = {
7
10
  kind: 'local_control';
8
11
  surface: 'cli' | 'web';
@@ -37,14 +40,17 @@ export interface TaskRecoveryResult {
37
40
  export type TaskRecoveryBegin = {
38
41
  kind: 'terminal_worker_required';
39
42
  taskId: string;
43
+ } | {
44
+ kind: 'deletion_worker_required';
45
+ taskId: string;
40
46
  } | {
41
47
  kind: 'final';
42
48
  result: TaskRecoveryResult;
43
49
  };
44
50
  export declare class TaskRoomApplicationError extends Error {
45
- readonly code: 'template_not_found' | 'task_template_drift' | 'template_mismatch' | 'task_terminal' | 'task_terminal_already' | 'task_non_resumable' | 'room_not_found' | 'room_record_not_found';
51
+ readonly code: 'template_not_found' | 'task_template_drift' | 'template_mismatch' | 'task_terminal' | 'task_terminal_already' | 'task_non_resumable' | 'task_deleting' | 'room_not_found' | 'room_record_not_found';
46
52
  readonly fields: Readonly<Record<string, string>>;
47
- constructor(code: 'template_not_found' | 'task_template_drift' | 'template_mismatch' | 'task_terminal' | 'task_terminal_already' | 'task_non_resumable' | 'room_not_found' | 'room_record_not_found', message: string, fields?: Readonly<Record<string, string>>);
53
+ constructor(code: 'template_not_found' | 'task_template_drift' | 'template_mismatch' | 'task_terminal' | 'task_terminal_already' | 'task_non_resumable' | 'task_deleting' | 'room_not_found' | 'room_record_not_found', message: string, fields?: Readonly<Record<string, string>>);
48
54
  }
49
55
  export interface CreateTaskRequest {
50
56
  actor: TaskRoomActor;
@@ -57,6 +63,8 @@ export interface CreateTaskRequest {
57
63
  idempotencyKey?: string;
58
64
  origin: TaskOrigin;
59
65
  list?: string;
66
+ members?: MemberOverrides;
67
+ anonymous?: boolean;
60
68
  }
61
69
  export interface CreateRoomRequest {
62
70
  actor: TaskRoomActor;
@@ -65,13 +73,19 @@ export interface CreateRoomRequest {
65
73
  goal?: string;
66
74
  brief?: string;
67
75
  briefFile?: string;
76
+ members?: MemberOverrides;
77
+ anonymous?: boolean;
68
78
  }
79
+ export declare function resolveRoomLaunchPolicy(template: TemplateSnapshot | undefined, override: boolean | undefined): RoomLaunchPolicy;
69
80
  export interface TaskRoomServiceDeps {
70
81
  loadConfiguration?(path?: string): FleetConfig;
71
82
  cowork?(config: FleetConfig): CoworkAdapter;
72
83
  binPath?(): string;
73
84
  provisionMembers?: typeof provisionMembers;
74
85
  moveTaskToList?: typeof moveTaskToList;
86
+ launchDeletionWorker?(taskId: string): Promise<void>;
87
+ sleep?(ms: number): Promise<void>;
88
+ now?(): number;
75
89
  }
76
90
  /** Exact extraction of the previously CLI-owned task create/start behavior. */
77
91
  export declare class TaskRoomApplicationService {
@@ -84,15 +98,20 @@ export declare class TaskRoomApplicationService {
84
98
  startTask(input: {
85
99
  actor: TaskRoomActor;
86
100
  taskId: string;
101
+ template?: string;
102
+ members?: MemberOverrides;
103
+ anonymous?: boolean;
87
104
  }): Promise<TaskRecord>;
88
105
  listTasks(filter?: {
89
106
  state?: TaskState | TaskState[];
90
107
  list?: string;
108
+ includeDeleting?: boolean;
91
109
  }): TaskRecord[];
92
110
  listTaskLists(): TaskListRecord[];
93
111
  groupedTasks(filter?: {
94
112
  state?: TaskState | TaskState[];
95
113
  list?: string;
114
+ includeDeleting?: boolean;
96
115
  }): Array<{
97
116
  list: TaskListRecord;
98
117
  tasks: TaskRecord[];
@@ -137,10 +156,40 @@ export declare class TaskRoomApplicationService {
137
156
  actor: TaskRoomActor;
138
157
  taskId: string;
139
158
  }): TaskRecord;
140
- deleteTask(input: {
159
+ private deletionActor;
160
+ /** Accept a permanent deletion in any lifecycle state; audit at acceptance. */
161
+ requestTaskDeletion(input: {
162
+ actor: TaskRoomActor;
163
+ taskId: string;
164
+ }): Promise<TaskDeletionAcceptance>;
165
+ /** Worker entry: converge an accepted deletion; Cowork is resolved lazily. */
166
+ settleTaskDeletion(input: {
167
+ actor: {
168
+ kind: 'internal_worker';
169
+ surface: 'cli';
170
+ };
171
+ taskId: string;
172
+ }): Promise<TaskDeletionSettleResult>;
173
+ /**
174
+ * Launch the external deletion worker outside the caller's lifecycle and
175
+ * wait boundedly for physical absence. Timeouts and launch failures report
176
+ * a pending, recoverable state — never success. A concurrent worker that
177
+ * already removed the record reads as settled.
178
+ */
179
+ launchTaskDeletionWorker(input: {
180
+ taskId: string;
181
+ waitMs?: number;
182
+ }): Promise<{
183
+ deleted: boolean;
184
+ pending: boolean;
185
+ error?: string;
186
+ }>;
187
+ recordDeletionError(input: {
141
188
  actor: TaskRoomActor;
142
189
  taskId: string;
143
- }): boolean;
190
+ error: string;
191
+ recoveryHint: string;
192
+ }): Promise<TaskRecord>;
144
193
  completeTask(input: {
145
194
  actor: TaskRoomActor;
146
195
  taskId: string;
@@ -179,7 +228,7 @@ export declare class TaskRoomApplicationService {
179
228
  name: string;
180
229
  version: number;
181
230
  description: string;
182
- builtin?: boolean;
231
+ sourceFile?: string;
183
232
  room?: import("../rooms-tasks/types.js").TemplateRoomConfig;
184
233
  contract?: string;
185
234
  members: import("../rooms-tasks/types.js").TemplateMemberSlot[];
@@ -197,6 +246,7 @@ export declare class TaskRoomApplicationService {
197
246
  identity_cid: string;
198
247
  room_name: string;
199
248
  state: "provisioning" | "active" | "closing" | "closed";
249
+ anonymous: boolean;
200
250
  seats: import("../rooms-tasks/cowork-adapter.js").CoworkSeatInfo[];
201
251
  goal?: string;
202
252
  briefing?: string;
@@ -252,6 +302,8 @@ export declare class TaskRoomApplicationService {
252
302
  actor: TaskRoomActor;
253
303
  taskId: string;
254
304
  template?: string;
305
+ members?: MemberOverrides;
306
+ anonymous?: boolean;
255
307
  }): Promise<{
256
308
  task: TaskRecord;
257
309
  status: 'ready' | 'already_active';