@ours.network/fleet 1.1.0-nightly.13 → 1.1.0-nightly.15
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 +7 -0
- package/dist/application/task-room-service.d.ts +7 -1
- package/dist/application/task-room-service.js +40 -9
- package/dist/briefing.js +3 -3
- package/dist/build-info.json +4 -4
- package/dist/config.d.ts +1 -0
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +7 -0
- package/dist/harness/codex-app-server-proxy.d.ts +40 -0
- package/dist/harness/codex-app-server-proxy.js +348 -14
- package/dist/rooms-tasks/cli.js +19 -0
- package/dist/rooms-tasks/config.js +5 -1
- package/dist/rooms-tasks/cowork-adapter.d.ts +1 -0
- package/dist/rooms-tasks/cowork-adapter.js +6 -0
- package/dist/rooms-tasks/provision.js +17 -6
- package/dist/rooms-tasks/room-state.d.ts +1 -0
- package/dist/rooms-tasks/room-state.js +8 -1
- package/dist/rooms-tasks/task-state.js +12 -4
- package/dist/rooms-tasks/types.d.ts +10 -0
- package/dist/rooms-tasks/types.js +12 -0
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from 'node:f
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { replaceFileAtomically } from '../atomic-file.js';
|
|
4
4
|
import { stateRoot } from '../paths.js';
|
|
5
|
+
import { storedRoomLaunchPolicy } from './types.js';
|
|
5
6
|
import { releaseLaunchSnapshot } from './launch-snapshot.js';
|
|
6
7
|
export const roomsDir = () => join(stateRoot(), 'rooms');
|
|
7
8
|
function roomPath(id) { return join(roomsDir(), `${id}.json`); }
|
|
@@ -19,8 +20,13 @@ function writeRoom(record) {
|
|
|
19
20
|
}
|
|
20
21
|
export function createRoomRecord(input) {
|
|
21
22
|
const existing = getRoomRecord(input.room_id);
|
|
22
|
-
if (existing)
|
|
23
|
+
if (existing) {
|
|
24
|
+
const before = storedRoomLaunchPolicy(existing.room_policy);
|
|
25
|
+
const requested = storedRoomLaunchPolicy(input.room_policy);
|
|
26
|
+
if (JSON.stringify(before) !== JSON.stringify(requested))
|
|
27
|
+
throw new RoomStateError(`room ${input.room_id} launch policy mismatch`);
|
|
23
28
|
return existing;
|
|
29
|
+
}
|
|
24
30
|
const record = {
|
|
25
31
|
room_id: input.room_id,
|
|
26
32
|
room_name: input.room_name,
|
|
@@ -28,6 +34,7 @@ export function createRoomRecord(input) {
|
|
|
28
34
|
room_identity_cid: input.room_identity_cid,
|
|
29
35
|
task_id: input.task_id,
|
|
30
36
|
template_snapshot: input.template_snapshot,
|
|
37
|
+
room_policy: input.room_policy,
|
|
31
38
|
saga: { phase: 'persist_intent', step_index: 0 },
|
|
32
39
|
member_seats: [],
|
|
33
40
|
state: 'provisioning',
|
|
@@ -3,7 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { replaceFileAtomically } from '../atomic-file.js';
|
|
5
5
|
import { stateRoot } from '../paths.js';
|
|
6
|
-
import { TASK_TERMINAL_STATES, TASK_CANCELLABLE_STATES } from './types.js';
|
|
6
|
+
import { storedRoomLaunchPolicy, TASK_TERMINAL_STATES, TASK_CANCELLABLE_STATES } from './types.js';
|
|
7
7
|
import { DEFAULT_TASK_LIST_ID, readTaskLists } from './task-lists.js';
|
|
8
8
|
export const tasksDir = () => join(stateRoot(), 'tasks');
|
|
9
9
|
function taskPath(id) { return join(tasksDir(), `${id}.json`); }
|
|
@@ -131,7 +131,9 @@ export function createTask(input) {
|
|
|
131
131
|
if (existing) {
|
|
132
132
|
const existingPlan = existing.execution_plan?.plan_hash;
|
|
133
133
|
const requestedPlan = input.execution_plan?.plan_hash;
|
|
134
|
-
|
|
134
|
+
const existingPolicy = storedRoomLaunchPolicy(existing.execution_plan?.room_policy);
|
|
135
|
+
const requestedPolicy = storedRoomLaunchPolicy(input.execution_plan?.room_policy);
|
|
136
|
+
if (existingPlan !== requestedPlan || JSON.stringify(existingPolicy) !== JSON.stringify(requestedPolicy))
|
|
135
137
|
throw new TaskStateError(`idempotency key '${key}' was already used with a different execution plan`);
|
|
136
138
|
return existing;
|
|
137
139
|
}
|
|
@@ -161,8 +163,14 @@ export function updateTaskExecutionPlan(id, executionPlan) {
|
|
|
161
163
|
return withTaskLock(id, () => {
|
|
162
164
|
const task = readTask(id);
|
|
163
165
|
assertNoPendingDeletion(task);
|
|
164
|
-
if (task.execution_plan
|
|
165
|
-
|
|
166
|
+
if (task.execution_plan) {
|
|
167
|
+
if (task.execution_plan.plan_hash !== executionPlan.plan_hash)
|
|
168
|
+
throw new TaskStateError(`task ${id} execution plan mismatch`);
|
|
169
|
+
const before = storedRoomLaunchPolicy(task.execution_plan.room_policy);
|
|
170
|
+
const after = storedRoomLaunchPolicy(executionPlan.room_policy);
|
|
171
|
+
if (task.room_id && JSON.stringify(before) !== JSON.stringify(after))
|
|
172
|
+
throw new TaskStateError(`task ${id} Room launch policy cannot change after Room creation`);
|
|
173
|
+
}
|
|
166
174
|
task.execution_plan = executionPlan;
|
|
167
175
|
task.template = { name: executionPlan.snapshot.name, version: executionPlan.snapshot.version,
|
|
168
176
|
content_hash: executionPlan.snapshot.content_hash };
|
|
@@ -101,6 +101,7 @@ export interface TaskRecord {
|
|
|
101
101
|
execution_plan?: {
|
|
102
102
|
schema_version: 1;
|
|
103
103
|
snapshot: TemplateSnapshot;
|
|
104
|
+
room_policy?: RoomLaunchPolicy;
|
|
104
105
|
overrides: Record<string, unknown>;
|
|
105
106
|
overrides_hash: string;
|
|
106
107
|
plan_hash: string;
|
|
@@ -232,6 +233,8 @@ export interface RoomOrchestrationRecord {
|
|
|
232
233
|
goal?: string;
|
|
233
234
|
task_id?: string;
|
|
234
235
|
template_snapshot?: TemplateSnapshot;
|
|
236
|
+
/** Resolved once at launch; legacy absence means non-anonymous. */
|
|
237
|
+
room_policy?: RoomLaunchPolicy;
|
|
235
238
|
saga: SagaCursor;
|
|
236
239
|
provisioning_detail?: ProvisioningDetail;
|
|
237
240
|
owner_seat_cid?: string;
|
|
@@ -256,6 +259,12 @@ export interface TemplateRoomConfig {
|
|
|
256
259
|
quiet_membership?: boolean;
|
|
257
260
|
anonymous?: boolean;
|
|
258
261
|
}
|
|
262
|
+
export interface RoomLaunchPolicy {
|
|
263
|
+
anonymous: boolean;
|
|
264
|
+
}
|
|
265
|
+
export declare const LEGACY_ROOM_LAUNCH_POLICY: Readonly<RoomLaunchPolicy>;
|
|
266
|
+
/** Validate durable policy before it can influence room creation or recovery. */
|
|
267
|
+
export declare function storedRoomLaunchPolicy(value: RoomLaunchPolicy | undefined): RoomLaunchPolicy;
|
|
259
268
|
export interface TemplateDefinition {
|
|
260
269
|
name: string;
|
|
261
270
|
version: number;
|
|
@@ -319,5 +328,6 @@ export declare const ROOMS_COWORK_KEYS: readonly ["config"];
|
|
|
319
328
|
export declare const ROOMS_DEFAULTS_KEYS: readonly ["template", "attach_owner", "close_when_task_done"];
|
|
320
329
|
export declare const TASKS_KEYS: readonly ["default_room_template", "create_mode", "close_room_on_done", "retain_completed_for"];
|
|
321
330
|
export declare const TEMPLATE_KEYS: readonly ["version", "description", "room", "contract", "members", "override_builtin"];
|
|
331
|
+
export declare const TEMPLATE_ROOM_KEYS: readonly ["quiet_membership", "anonymous"];
|
|
322
332
|
/** `agent` is accepted only so validation can emit its actionable migration error. */
|
|
323
333
|
export declare const TEMPLATE_MEMBER_KEYS: readonly ["slot", "role", "count", "agent_template", "agent"];
|
|
@@ -7,6 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export const TASK_TERMINAL_STATES = ['done', 'cancelled', 'failed'];
|
|
9
9
|
export const TASK_CANCELLABLE_STATES = ['backlog', 'provisioning', 'active', 'review'];
|
|
10
|
+
export const LEGACY_ROOM_LAUNCH_POLICY = Object.freeze({
|
|
11
|
+
anonymous: false,
|
|
12
|
+
});
|
|
13
|
+
/** Validate durable policy before it can influence room creation or recovery. */
|
|
14
|
+
export function storedRoomLaunchPolicy(value) {
|
|
15
|
+
if (value === undefined)
|
|
16
|
+
return { ...LEGACY_ROOM_LAUNCH_POLICY };
|
|
17
|
+
if (typeof value.anonymous !== 'boolean')
|
|
18
|
+
throw new Error('invalid durable Room launch policy; anonymous must be a boolean');
|
|
19
|
+
return { ...value };
|
|
20
|
+
}
|
|
10
21
|
// ── Validation keys ─────────────────────────────────────────────────────
|
|
11
22
|
export const ROOMS_KEYS = ['cowork', 'owner', 'defaults'];
|
|
12
23
|
export const ROOMS_OWNER_KEYS = ['provider', 'public_invite', 'public_invite_file', 'expected_cid', 'role'];
|
|
@@ -14,5 +25,6 @@ export const ROOMS_COWORK_KEYS = ['config'];
|
|
|
14
25
|
export const ROOMS_DEFAULTS_KEYS = ['template', 'attach_owner', 'close_when_task_done'];
|
|
15
26
|
export const TASKS_KEYS = ['default_room_template', 'create_mode', 'close_room_on_done', 'retain_completed_for'];
|
|
16
27
|
export const TEMPLATE_KEYS = ['version', 'description', 'room', 'contract', 'members', 'override_builtin'];
|
|
28
|
+
export const TEMPLATE_ROOM_KEYS = ['quiet_membership', 'anonymous'];
|
|
17
29
|
/** `agent` is accepted only so validation can emit its actionable migration error. */
|
|
18
30
|
export const TEMPLATE_MEMBER_KEYS = ['slot', 'role', 'count', 'agent_template', 'agent'];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.1.0-nightly.
|
|
3
|
+
"version": "1.1.0-nightly.15",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|