@ours.network/fleet 1.1.0-nightly.3 → 1.1.0-nightly.30
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 +244 -40
- package/dist/agent-recovery-gate.d.ts +17 -0
- package/dist/agent-recovery-gate.js +135 -0
- package/dist/application/capabilities.js +18 -6
- package/dist/application/fleet-query-service.js +20 -5
- package/dist/application/role-command-service.js +9 -0
- package/dist/application/role-creation-service.d.ts +4 -4
- package/dist/application/role-creation-service.js +19 -1
- package/dist/application/role-repository.d.ts +4 -2
- package/dist/application/role-repository.js +6 -3
- package/dist/application/session-control.d.ts +3 -1
- package/dist/application/session-control.js +4 -2
- package/dist/application/task-room-service.d.ts +93 -40
- package/dist/application/task-room-service.js +579 -173
- package/dist/briefing.js +85 -24
- package/dist/build-info.json +4 -4
- package/dist/canonical-json.d.ts +2 -0
- package/dist/canonical-json.js +10 -0
- package/dist/cli.js +217 -51
- package/dist/config-yaml.d.ts +1 -1
- package/dist/config.d.ts +38 -3
- package/dist/config.js +240 -28
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +7 -4
- 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 +213 -42
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +54 -4
- package/dist/fleet-command-audit.d.ts +181 -0
- package/dist/fleet-command-audit.js +738 -0
- package/dist/fleet-proxy.d.ts +7 -2
- package/dist/harness/agent-session.d.ts +5 -0
- package/dist/harness/claude-code-session.d.ts +2 -0
- package/dist/harness/claude-code-session.js +6 -1
- package/dist/harness/claude-code.js +2 -0
- package/dist/harness/codex-app-server-proxy.d.ts +40 -0
- package/dist/harness/codex-app-server-proxy.js +348 -14
- package/dist/harness/codex-session.d.ts +11 -2
- package/dist/harness/codex-session.js +22 -2
- package/dist/harness/codex.d.ts +5 -1
- package/dist/harness/codex.js +110 -10
- package/dist/harness/types.d.ts +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/init-guidance.d.ts +1 -1
- package/dist/init-guidance.js +4 -3
- package/dist/init-wizard.d.ts +98 -0
- package/dist/init-wizard.js +631 -0
- package/dist/lifecycle-summary.d.ts +134 -0
- package/dist/lifecycle-summary.js +179 -0
- package/dist/loops/config.d.ts +10 -1
- package/dist/loops/config.js +38 -5
- package/dist/model-recovery.d.ts +1 -1
- package/dist/ops.js +2 -17
- package/dist/owner-channel/channel.d.ts +75 -3
- package/dist/owner-channel/channel.js +531 -123
- package/dist/owner-channel/commands.d.ts +28 -6
- package/dist/owner-channel/commands.js +112 -36
- package/dist/owner-channel/lifecycle-outbox.d.ts +24 -0
- package/dist/owner-channel/lifecycle-outbox.js +87 -0
- package/dist/owner-channel/ours-client.d.ts +19 -0
- package/dist/owner-channel/ours-client.js +3 -0
- package/dist/owner-channel/state.d.ts +2 -0
- package/dist/owner-channel/state.js +8 -2
- package/dist/permissions.js +1 -1
- package/dist/preset-bootstrap.d.ts +10 -0
- package/dist/preset-bootstrap.js +85 -0
- package/dist/preset-migration.d.ts +42 -0
- package/dist/preset-migration.js +450 -0
- package/dist/reports/artifact.d.ts +10 -0
- package/dist/reports/artifact.js +32 -0
- package/dist/reports/index.d.ts +5 -0
- package/dist/reports/index.js +5 -0
- package/dist/reports/render.d.ts +6 -0
- package/dist/reports/render.js +240 -0
- package/dist/reports/service.d.ts +42 -0
- package/dist/reports/service.js +57 -0
- package/dist/reports/tasks.d.ts +52 -0
- package/dist/reports/tasks.js +177 -0
- package/dist/reports/types.d.ts +315 -0
- package/dist/reports/types.js +6 -0
- package/dist/resolved-plan.js +13 -1
- package/dist/rooms-tasks/cli.d.ts +2 -0
- package/dist/rooms-tasks/cli.js +519 -261
- package/dist/rooms-tasks/close.d.ts +9 -1
- package/dist/rooms-tasks/close.js +23 -7
- package/dist/rooms-tasks/config.js +16 -29
- package/dist/rooms-tasks/cowork-adapter.d.ts +5 -0
- package/dist/rooms-tasks/cowork-adapter.js +13 -0
- package/dist/rooms-tasks/deletion.d.ts +51 -0
- package/dist/rooms-tasks/deletion.js +217 -0
- package/dist/rooms-tasks/external-worker.d.ts +9 -0
- package/dist/rooms-tasks/external-worker.js +52 -9
- package/dist/rooms-tasks/launch-snapshot.d.ts +19 -0
- package/dist/rooms-tasks/launch-snapshot.js +181 -0
- package/dist/rooms-tasks/member-overrides.d.ts +30 -0
- package/dist/rooms-tasks/member-overrides.js +204 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +9 -2
- package/dist/rooms-tasks/provision.js +146 -56
- package/dist/rooms-tasks/room-state.d.ts +1 -0
- package/dist/rooms-tasks/room-state.js +12 -1
- package/dist/rooms-tasks/task-room-name.d.ts +12 -0
- package/dist/rooms-tasks/task-room-name.js +61 -0
- package/dist/rooms-tasks/task-state.d.ts +115 -3
- package/dist/rooms-tasks/task-state.js +361 -11
- package/dist/rooms-tasks/templates.d.ts +4 -2
- package/dist/rooms-tasks/templates.js +42 -78
- package/dist/rooms-tasks/terminal.d.ts +3 -0
- package/dist/rooms-tasks/terminal.js +10 -4
- package/dist/rooms-tasks/types.d.ts +94 -8
- package/dist/rooms-tasks/types.js +14 -1
- package/dist/runner.d.ts +12 -2
- package/dist/runner.js +167 -56
- package/dist/session/acp.d.ts +9 -1
- package/dist/session/acp.js +35 -9
- package/dist/session/arbiter.d.ts +2 -1
- package/dist/session/arbiter.js +2 -0
- package/dist/session/codex-app-server-transport.d.ts +53 -0
- package/dist/session/codex-app-server-transport.js +184 -0
- package/dist/session/codex-app-server.d.ts +122 -0
- package/dist/session/codex-app-server.js +1031 -0
- package/dist/session/control.d.ts +14 -1
- package/dist/session/control.js +51 -0
- package/dist/session/conversation-types.d.ts +4 -4
- package/dist/session/types.d.ts +24 -6
- package/dist/session/types.js +28 -0
- package/dist/spawn.d.ts +9 -0
- package/dist/spawn.js +77 -9
- package/dist/temp-lifecycle.d.ts +1 -1
- package/dist/web/fleet-config-service.d.ts +1 -0
- package/dist/web/fleet-config-service.js +27 -8
- package/dist/web/runtime.js +11 -6
- package/dist/web/server.js +28 -1
- package/dist/web-app/assets/{index-BbTc5KtZ.js → index-C0h3ALvs.js} +8 -8
- package/dist/web-app/index.html +1 -1
- package/package.json +5 -4
- package/presets/brain-catalog.json +17 -0
- package/presets/fleet/agent_templates/Critic.yaml +5 -0
- package/presets/fleet/agent_templates/Developer.yaml +5 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +50 -0
- package/presets/fleet/agents/FleetCoordinator.yaml +3 -0
- package/presets/fleet/brains/claude-default.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +30 -0
- package/presets/fleet/roles/Critic.yaml +28 -0
- package/presets/fleet/roles/Developer.yaml +28 -0
- package/presets/fleet/roles/LocalCoordinator.yaml +35 -0
- package/presets/fleet/room_templates/pair.yaml +13 -0
- package/presets/fleet/room_templates/single.yaml +9 -0
- package/presets/fleet/room_templates/team.yaml +16 -0
- package/presets/fleet.yaml +7 -0
- package/presets/manifest.json +6 -0
|
@@ -4,6 +4,7 @@ import { classifyActivity } from '../session/activity.js';
|
|
|
4
4
|
import { controlRequest } from '../session/control.js';
|
|
5
5
|
import { SessionControlError } from '../session/types.js';
|
|
6
6
|
import { readExitRecord, readRestartLedger } from '../runner.js';
|
|
7
|
+
import { readDaemonRecoveryStatus } from '../daemon-recovery.js';
|
|
7
8
|
import { roleCapabilities } from './capabilities.js';
|
|
8
9
|
import { FleetError } from './errors.js';
|
|
9
10
|
const clean = (value, max = 512) => value.replace(/[\0-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '').trim().slice(0, max);
|
|
@@ -46,7 +47,8 @@ function readIsolation(dir) {
|
|
|
46
47
|
function sessionOverall(supervisor, session, restart, monitor, isolation, problems) {
|
|
47
48
|
if (restart.circuit === 'open' || monitor.health === 'failed' || monitor.health === 'degraded'
|
|
48
49
|
|| isolation.degraded
|
|
49
|
-
|| problems.some(problem => problem.severity === 'error'
|
|
50
|
+
|| problems.some(problem => problem.severity === 'error'
|
|
51
|
+
|| problem.source === 'watchdog' || problem.source === 'daemon-recovery')
|
|
50
52
|
|| session.readiness === 'failed')
|
|
51
53
|
return 'attention';
|
|
52
54
|
// A reachable agent session is the user's live interaction surface. Its
|
|
@@ -74,7 +76,8 @@ export class FleetQueryService {
|
|
|
74
76
|
this.control = options.control ?? controlRequest;
|
|
75
77
|
}
|
|
76
78
|
async list() {
|
|
77
|
-
const roles = await this.options.repository.list()
|
|
79
|
+
const roles = (await this.options.repository.list())
|
|
80
|
+
.filter(role => role.configured && role.lifetime === 'permanent');
|
|
78
81
|
return Promise.all(roles.map(async (role) => {
|
|
79
82
|
const status = await this.status(role);
|
|
80
83
|
return { role, status, capabilities: roleCapabilities(role, status, this.options.capabilityContext) };
|
|
@@ -103,6 +106,16 @@ export class FleetQueryService {
|
|
|
103
106
|
const lastExit = dir ? readExitRecord(join(dir, '.exit-status')) ?? undefined : undefined;
|
|
104
107
|
const session = await this.session(role, dir, live.state);
|
|
105
108
|
const problems = [...role.problems];
|
|
109
|
+
const recovery = dir ? readDaemonRecoveryStatus(dir) : undefined;
|
|
110
|
+
if (recovery && recovery.state !== 'recovered') {
|
|
111
|
+
const paths = ['agent', 'owner']
|
|
112
|
+
.filter(name => recovery.paths[name].state !== 'recovered')
|
|
113
|
+
.map(name => `${name}:${recovery.paths[name].state}`);
|
|
114
|
+
problems.push({
|
|
115
|
+
code: 'daemon_recovery', severity: 'warning', source: 'daemon-recovery',
|
|
116
|
+
detail: `${recovery.state}; ${paths.join(', ') || 'no degraded path'}; epoch ${recovery.epoch || 'unavailable'}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
106
119
|
if (live.state === 'running' && session.reachability !== 'online')
|
|
107
120
|
problems.push({
|
|
108
121
|
code: 'supervisor_session_disagreement', severity: 'warning',
|
|
@@ -141,14 +154,16 @@ export class FleetQueryService {
|
|
|
141
154
|
}
|
|
142
155
|
async session(role, dir, supervisor) {
|
|
143
156
|
const intended = role.configuredBackend;
|
|
144
|
-
if (intended
|
|
157
|
+
if (intended && dir) {
|
|
145
158
|
try {
|
|
146
159
|
const response = await this.control(dir, { command: 'snapshot' }, 2_000);
|
|
147
160
|
if (!response.ok)
|
|
148
161
|
throw new SessionControlError(response.kind ?? 'backend', response.error ?? 'snapshot failed');
|
|
149
162
|
const snapshot = response.result;
|
|
163
|
+
if (snapshot.backend !== intended)
|
|
164
|
+
throw new SessionControlError('backend', `live session reports backend '${String(snapshot.backend)}', expected '${intended}'`);
|
|
150
165
|
return {
|
|
151
|
-
backend:
|
|
166
|
+
backend: intended, reachability: snapshot.alive ? 'online' : 'offline',
|
|
152
167
|
readiness: snapshot.readiness, evidence: 'authoritative',
|
|
153
168
|
sessionId: snapshot.sessionId, lastError: snapshot.lastError,
|
|
154
169
|
pendingPermissionId: snapshot.pendingPermissionId,
|
|
@@ -162,7 +177,7 @@ export class FleetQueryService {
|
|
|
162
177
|
const failure = error instanceof SessionControlError ? error.kind : 'backend';
|
|
163
178
|
const offline = failure === 'offline';
|
|
164
179
|
return {
|
|
165
|
-
backend:
|
|
180
|
+
backend: intended,
|
|
166
181
|
reachability: offline ? 'offline'
|
|
167
182
|
: failure === 'control-unavailable' ? 'unavailable' : 'unknown',
|
|
168
183
|
readiness: offline ? 'failed' : 'unknown',
|
|
@@ -12,6 +12,10 @@ export class RoleLifecycleService {
|
|
|
12
12
|
const config = input.config ?? loadConfig(this.options.configPath);
|
|
13
13
|
const selected = input.roleIds.length ? input.roleIds : config.roles.map(role => role.name);
|
|
14
14
|
for (const roleId of selected) {
|
|
15
|
+
if (config.agentTemplates?.[roleId] && !config.roles.some(role => role.name === roleId))
|
|
16
|
+
throw new FleetError('capability_unavailable', `'${roleId}' is an inert Agent Template; lifecycle commands target only persistent fleet/agents instances`);
|
|
17
|
+
if (!config.roles.some(role => role.name === roleId))
|
|
18
|
+
throw new FleetError('role_not_found', `no such role '${roleId}'`);
|
|
15
19
|
const role = await this.options.repository.get(roleId);
|
|
16
20
|
if (!role)
|
|
17
21
|
throw new FleetError('role_not_found', `no such role '${roleId}'`);
|
|
@@ -51,6 +55,11 @@ export class RoleCommandService {
|
|
|
51
55
|
throw new FleetError('idempotency_conflict', 'action ID already belongs to another operation');
|
|
52
56
|
return prior;
|
|
53
57
|
}
|
|
58
|
+
const config = loadConfig(this.options.configPath);
|
|
59
|
+
if (config.agentTemplates?.[input.roleId] && !config.roles.some(role => role.name === input.roleId))
|
|
60
|
+
throw new FleetError('capability_unavailable', `'${input.roleId}' is an inert Agent Template; lifecycle commands target only persistent fleet/agents instances`);
|
|
61
|
+
if (!config.roles.some(role => role.name === input.roleId))
|
|
62
|
+
throw new FleetError('role_not_found', `no such role '${input.roleId}'`);
|
|
54
63
|
const role = await this.options.repository.get(input.roleId);
|
|
55
64
|
if (!role)
|
|
56
65
|
throw new FleetError('role_not_found', `no such role '${input.roleId}'`);
|
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
@@ -53,7 +53,7 @@ export interface CreationPreview {
|
|
|
53
53
|
name: string;
|
|
54
54
|
identity: string;
|
|
55
55
|
harness: string;
|
|
56
|
-
session:
|
|
56
|
+
session: SessionBackendId;
|
|
57
57
|
model?: string;
|
|
58
58
|
reasoningEffort?: string;
|
|
59
59
|
cwd?: string;
|
|
@@ -77,7 +77,7 @@ export interface CreationAction {
|
|
|
77
77
|
actionId: string;
|
|
78
78
|
requestHash: string;
|
|
79
79
|
roleId: string;
|
|
80
|
-
session:
|
|
80
|
+
session: SessionBackendId;
|
|
81
81
|
lifetime: 'permanent' | 'temporary';
|
|
82
82
|
state: CreationStage;
|
|
83
83
|
stages: Array<{
|
|
@@ -103,7 +103,7 @@ export interface RoleCreationServiceOptions {
|
|
|
103
103
|
tempLauncher?: SupervisorLauncher;
|
|
104
104
|
allowedCwdRoots?: string[];
|
|
105
105
|
journalDir?: string;
|
|
106
|
-
probeReady?: (name: string, session:
|
|
106
|
+
probeReady?: (name: string, session: SessionBackendId) => Promise<'ready' | 'attention' | 'unknown'>;
|
|
107
107
|
onProgress?: (action: CreationAction) => void;
|
|
108
108
|
/** Direct/managed callers must not create or restore the web action journal. */
|
|
109
109
|
journal?: boolean;
|
|
@@ -10,6 +10,7 @@ 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 { selectionOrigin, summarizeResolvedLaunch } from '../lifecycle-summary.js';
|
|
13
14
|
const canonical = (value) => {
|
|
14
15
|
if (Array.isArray(value))
|
|
15
16
|
return `[${value.map(canonical).join(',')}]`;
|
|
@@ -61,14 +62,31 @@ export class RoleCreationService {
|
|
|
61
62
|
const creationActionId = randomUUID();
|
|
62
63
|
plan.options.creationActionId = creationActionId;
|
|
63
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);
|
|
64
76
|
return {
|
|
65
77
|
caller: plan.caller, role: plan.options.name,
|
|
66
78
|
lifetime: plan.options.temp ? 'temporary' : 'permanent', statePath,
|
|
67
79
|
harness: plan.preview.resolvedRole.harness, session: plan.preview.resolvedRole.session,
|
|
68
80
|
...(effectiveRoleModel(plan.preview.resolvedRole) ? { model: effectiveRoleModel(plan.preview.resolvedRole) } : {}),
|
|
69
81
|
monitor: { mode: plan.preview.resolvedRole.monitor.mode, interrupt: plan.preview.resolvedRole.monitor.interrupt },
|
|
70
|
-
permissionMode
|
|
82
|
+
permissionMode, inherited: plan.inherited,
|
|
71
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
|
+
}),
|
|
72
90
|
};
|
|
73
91
|
}
|
|
74
92
|
launchSync(options, creation) {
|
|
@@ -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?:
|
|
7
|
-
acp
|
|
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
|
-
|
|
49
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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';
|
|
@@ -18,8 +21,8 @@ export interface TaskSettlementPlan {
|
|
|
18
21
|
task: TaskRecord;
|
|
19
22
|
settlementRequired: boolean;
|
|
20
23
|
}
|
|
21
|
-
export type
|
|
22
|
-
code: '
|
|
24
|
+
export type TaskProvisioningContinuationIssue = {
|
|
25
|
+
code: 'waiting_cowork' | 'waiting_owner_authorization' | 'waiting_owner_invite' | 'owner_cid_mismatch' | 'waiting_seats' | 'provisioning_resumed';
|
|
23
26
|
} | {
|
|
24
27
|
code: 'member_failed';
|
|
25
28
|
stepIndex: number;
|
|
@@ -27,24 +30,36 @@ export type TaskRecoveryIssue = {
|
|
|
27
30
|
code: 'resume_failed';
|
|
28
31
|
error: string;
|
|
29
32
|
};
|
|
30
|
-
export interface
|
|
31
|
-
kind: 'provisioning_resumed' | 'provisioning_resume_failed' | 'provisioning_non_resumable' | '
|
|
33
|
+
export interface TaskProvisioningContinuationResult {
|
|
34
|
+
kind: 'provisioning_resumed' | 'provisioning_resume_failed' | 'provisioning_non_resumable' | 'no_op';
|
|
32
35
|
task: TaskRecord;
|
|
33
36
|
room: RoomOrchestrationRecord | undefined;
|
|
34
|
-
issues:
|
|
37
|
+
issues: TaskProvisioningContinuationIssue[];
|
|
35
38
|
reason?: 'missing_room' | 'missing_durable_template' | 'non_resumable_phase';
|
|
36
39
|
}
|
|
37
|
-
export
|
|
38
|
-
kind: '
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
export interface TaskProvisioningOutcome {
|
|
41
|
+
kind: 'ready' | 'in_progress' | 'failed';
|
|
42
|
+
task: TaskRecord;
|
|
43
|
+
room?: RoomOrchestrationRecord;
|
|
44
|
+
launch: {
|
|
45
|
+
template?: string;
|
|
46
|
+
anonymous: boolean;
|
|
47
|
+
owner_attached: boolean;
|
|
48
|
+
};
|
|
49
|
+
members: {
|
|
50
|
+
expected: number;
|
|
51
|
+
active: number;
|
|
52
|
+
launched: number;
|
|
53
|
+
};
|
|
54
|
+
blocker?: string;
|
|
55
|
+
next_action?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Repairable terminal observation derived entirely from durable Task/Room state. */
|
|
58
|
+
export declare function recordTaskProvisioningOutcome(outcome: TaskProvisioningOutcome): void;
|
|
44
59
|
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';
|
|
60
|
+
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
61
|
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>>);
|
|
62
|
+
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
63
|
}
|
|
49
64
|
export interface CreateTaskRequest {
|
|
50
65
|
actor: TaskRoomActor;
|
|
@@ -57,6 +72,8 @@ export interface CreateTaskRequest {
|
|
|
57
72
|
idempotencyKey?: string;
|
|
58
73
|
origin: TaskOrigin;
|
|
59
74
|
list?: string;
|
|
75
|
+
members?: MemberOverrides;
|
|
76
|
+
anonymous?: boolean;
|
|
60
77
|
}
|
|
61
78
|
export interface CreateRoomRequest {
|
|
62
79
|
actor: TaskRoomActor;
|
|
@@ -65,34 +82,44 @@ export interface CreateRoomRequest {
|
|
|
65
82
|
goal?: string;
|
|
66
83
|
brief?: string;
|
|
67
84
|
briefFile?: string;
|
|
85
|
+
members?: MemberOverrides;
|
|
86
|
+
anonymous?: boolean;
|
|
68
87
|
}
|
|
88
|
+
export declare function resolveRoomLaunchPolicy(template: TemplateSnapshot | undefined, override: boolean | undefined): RoomLaunchPolicy;
|
|
69
89
|
export interface TaskRoomServiceDeps {
|
|
70
90
|
loadConfiguration?(path?: string): FleetConfig;
|
|
71
91
|
cowork?(config: FleetConfig): CoworkAdapter;
|
|
72
92
|
binPath?(): string;
|
|
73
93
|
provisionMembers?: typeof provisionMembers;
|
|
74
94
|
moveTaskToList?: typeof moveTaskToList;
|
|
95
|
+
launchDeletionWorker?(taskId: string): Promise<void>;
|
|
96
|
+
sleep?(ms: number): Promise<void>;
|
|
97
|
+
now?(): number;
|
|
75
98
|
}
|
|
76
99
|
/** Exact extraction of the previously CLI-owned task create/start behavior. */
|
|
77
100
|
export declare class TaskRoomApplicationService {
|
|
78
101
|
private readonly configurationPath?;
|
|
79
102
|
private readonly deps;
|
|
80
|
-
private recovery?;
|
|
81
103
|
constructor(configurationPath?: string | undefined, deps?: TaskRoomServiceDeps);
|
|
82
104
|
createTask(request: CreateTaskRequest): Promise<TaskRecord>;
|
|
83
105
|
createRoom(request: CreateRoomRequest): Promise<RoomOrchestrationRecord>;
|
|
84
106
|
startTask(input: {
|
|
85
107
|
actor: TaskRoomActor;
|
|
86
108
|
taskId: string;
|
|
109
|
+
template?: string;
|
|
110
|
+
members?: MemberOverrides;
|
|
111
|
+
anonymous?: boolean;
|
|
87
112
|
}): Promise<TaskRecord>;
|
|
88
113
|
listTasks(filter?: {
|
|
89
114
|
state?: TaskState | TaskState[];
|
|
90
115
|
list?: string;
|
|
116
|
+
includeDeleting?: boolean;
|
|
91
117
|
}): TaskRecord[];
|
|
92
118
|
listTaskLists(): TaskListRecord[];
|
|
93
119
|
groupedTasks(filter?: {
|
|
94
120
|
state?: TaskState | TaskState[];
|
|
95
121
|
list?: string;
|
|
122
|
+
includeDeleting?: boolean;
|
|
96
123
|
}): Array<{
|
|
97
124
|
list: TaskListRecord;
|
|
98
125
|
tasks: TaskRecord[];
|
|
@@ -124,6 +151,12 @@ export declare class TaskRoomApplicationService {
|
|
|
124
151
|
task: TaskRecord;
|
|
125
152
|
orchestration: RoomOrchestrationRecord | undefined;
|
|
126
153
|
};
|
|
154
|
+
taskProvisioningOutcome(taskId: string): TaskProvisioningOutcome;
|
|
155
|
+
awaitTaskProvisioning(input: {
|
|
156
|
+
actor: TaskRoomActor;
|
|
157
|
+
taskId: string;
|
|
158
|
+
waitMs?: number;
|
|
159
|
+
}): Promise<TaskProvisioningOutcome>;
|
|
127
160
|
blockTask(input: {
|
|
128
161
|
actor: TaskRoomActor;
|
|
129
162
|
taskId: string;
|
|
@@ -137,10 +170,40 @@ export declare class TaskRoomApplicationService {
|
|
|
137
170
|
actor: TaskRoomActor;
|
|
138
171
|
taskId: string;
|
|
139
172
|
}): TaskRecord;
|
|
140
|
-
|
|
173
|
+
private deletionActor;
|
|
174
|
+
/** Accept a permanent deletion in any lifecycle state; audit at acceptance. */
|
|
175
|
+
requestTaskDeletion(input: {
|
|
141
176
|
actor: TaskRoomActor;
|
|
142
177
|
taskId: string;
|
|
143
|
-
}):
|
|
178
|
+
}): Promise<TaskDeletionAcceptance>;
|
|
179
|
+
/** Worker entry: converge an accepted deletion; Cowork is resolved lazily. */
|
|
180
|
+
settleTaskDeletion(input: {
|
|
181
|
+
actor: {
|
|
182
|
+
kind: 'internal_worker';
|
|
183
|
+
surface: 'cli';
|
|
184
|
+
};
|
|
185
|
+
taskId: string;
|
|
186
|
+
}): Promise<TaskDeletionSettleResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Launch the external deletion worker outside the caller's lifecycle and
|
|
189
|
+
* wait boundedly for physical absence. Timeouts and launch failures report
|
|
190
|
+
* a pending, recoverable state — never success. A concurrent worker that
|
|
191
|
+
* already removed the record reads as settled.
|
|
192
|
+
*/
|
|
193
|
+
launchTaskDeletionWorker(input: {
|
|
194
|
+
taskId: string;
|
|
195
|
+
waitMs?: number;
|
|
196
|
+
}): Promise<{
|
|
197
|
+
deleted: boolean;
|
|
198
|
+
pending: boolean;
|
|
199
|
+
error?: string;
|
|
200
|
+
}>;
|
|
201
|
+
recordDeletionError(input: {
|
|
202
|
+
actor: TaskRoomActor;
|
|
203
|
+
taskId: string;
|
|
204
|
+
error: string;
|
|
205
|
+
recoveryHint: string;
|
|
206
|
+
}): Promise<TaskRecord>;
|
|
144
207
|
completeTask(input: {
|
|
145
208
|
actor: TaskRoomActor;
|
|
146
209
|
taskId: string;
|
|
@@ -163,15 +226,14 @@ export declare class TaskRoomApplicationService {
|
|
|
163
226
|
error: string;
|
|
164
227
|
recoveryHint: string;
|
|
165
228
|
}): Promise<TaskRecord>;
|
|
166
|
-
|
|
167
|
-
actor:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
actor: TaskRoomActor;
|
|
229
|
+
continueTaskProvisioning(input: {
|
|
230
|
+
actor: {
|
|
231
|
+
kind: 'internal_worker';
|
|
232
|
+
surface: 'cli';
|
|
233
|
+
};
|
|
172
234
|
taskId: string;
|
|
173
|
-
|
|
174
|
-
|
|
235
|
+
}): Promise<TaskProvisioningContinuationResult>;
|
|
236
|
+
private reconcileProvisioningOwner;
|
|
175
237
|
private acceptTerminal;
|
|
176
238
|
listTemplates(): import("../rooms-tasks/types.js").TemplateDefinition[];
|
|
177
239
|
getTemplate(name: string): {
|
|
@@ -179,7 +241,7 @@ export declare class TaskRoomApplicationService {
|
|
|
179
241
|
name: string;
|
|
180
242
|
version: number;
|
|
181
243
|
description: string;
|
|
182
|
-
|
|
244
|
+
sourceFile?: string;
|
|
183
245
|
room?: import("../rooms-tasks/types.js").TemplateRoomConfig;
|
|
184
246
|
contract?: string;
|
|
185
247
|
members: import("../rooms-tasks/types.js").TemplateMemberSlot[];
|
|
@@ -197,6 +259,7 @@ export declare class TaskRoomApplicationService {
|
|
|
197
259
|
identity_cid: string;
|
|
198
260
|
room_name: string;
|
|
199
261
|
state: "provisioning" | "active" | "closing" | "closed";
|
|
262
|
+
anonymous: boolean;
|
|
200
263
|
seats: import("../rooms-tasks/cowork-adapter.js").CoworkSeatInfo[];
|
|
201
264
|
goal?: string;
|
|
202
265
|
briefing?: string;
|
|
@@ -231,18 +294,6 @@ export declare class TaskRoomApplicationService {
|
|
|
231
294
|
error: string;
|
|
232
295
|
recoveryHint: string;
|
|
233
296
|
}): Promise<RoomOrchestrationRecord>;
|
|
234
|
-
recoverRoom(input: {
|
|
235
|
-
actor: TaskRoomActor;
|
|
236
|
-
roomId: string;
|
|
237
|
-
}): Promise<{
|
|
238
|
-
kind: 'deletion_worker_required';
|
|
239
|
-
roomId: string;
|
|
240
|
-
} | {
|
|
241
|
-
kind: 'recovered' | 'provisioning_resumed' | 'provisioning_resume_failed';
|
|
242
|
-
room: Awaited<ReturnType<CoworkAdapter['recoverRoom']>>;
|
|
243
|
-
orchestration: RoomOrchestrationRecord | undefined;
|
|
244
|
-
issues: string[];
|
|
245
|
-
}>;
|
|
246
297
|
finishTask(input: {
|
|
247
298
|
actor: TaskRoomActor;
|
|
248
299
|
taskId: string;
|
|
@@ -252,9 +303,11 @@ export declare class TaskRoomApplicationService {
|
|
|
252
303
|
actor: TaskRoomActor;
|
|
253
304
|
taskId: string;
|
|
254
305
|
template?: string;
|
|
306
|
+
members?: MemberOverrides;
|
|
307
|
+
anonymous?: boolean;
|
|
255
308
|
}): Promise<{
|
|
256
309
|
task: TaskRecord;
|
|
257
|
-
status: 'ready' | 'already_active';
|
|
310
|
+
status: 'ready' | 'already_active' | 'in_progress';
|
|
258
311
|
}>;
|
|
259
312
|
private createTemplate;
|
|
260
313
|
private existingTemplate;
|