@ours.network/fleet 2.2.5 → 2.3.0
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/dist/application/task-room-service.d.ts +11 -0
- package/dist/application/task-room-service.js +37 -14
- package/dist/atomic-file.d.ts +2 -0
- package/dist/atomic-file.js +2 -1
- package/dist/build-info.json +4 -4
- package/dist/config.d.ts +6 -0
- package/dist/config.js +6 -3
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +37 -0
- package/dist/owner-channel/commands.js +25 -12
- package/dist/reports/tasks.js +4 -3
- package/dist/rooms-tasks/add-member.js +17 -6
- package/dist/rooms-tasks/cli.js +79 -5
- package/dist/rooms-tasks/config.js +11 -0
- package/dist/rooms-tasks/layout-member-retirement.d.ts +15 -0
- package/dist/rooms-tasks/layout-member-retirement.js +26 -1
- package/dist/rooms-tasks/layout-service.d.ts +2 -1
- package/dist/rooms-tasks/layout-service.js +10 -4
- package/dist/rooms-tasks/layout.d.ts +4 -2
- package/dist/rooms-tasks/layout.js +21 -4
- package/dist/rooms-tasks/member-naming.d.ts +43 -0
- package/dist/rooms-tasks/member-naming.js +186 -0
- package/dist/rooms-tasks/member-overrides.js +1 -0
- package/dist/rooms-tasks/mission-keys.d.ts +83 -0
- package/dist/rooms-tasks/mission-keys.js +250 -0
- package/dist/rooms-tasks/provision.d.ts +4 -0
- package/dist/rooms-tasks/provision.js +37 -3
- package/dist/rooms-tasks/task-lists.d.ts +18 -2
- package/dist/rooms-tasks/task-lists.js +60 -5
- package/dist/rooms-tasks/task-room-name.d.ts +7 -2
- package/dist/rooms-tasks/task-room-name.js +13 -4
- package/dist/rooms-tasks/task-state.d.ts +40 -0
- package/dist/rooms-tasks/task-state.js +288 -45
- package/dist/rooms-tasks/types.d.ts +35 -1
- package/dist/rooms-tasks/types.js +1 -1
- package/dist/web/runtime.js +4 -1
- package/dist/web/server.js +62 -27
- package/package.json +5 -5
|
@@ -201,10 +201,21 @@ export declare class TaskRoomApplicationService {
|
|
|
201
201
|
list: TaskListRecord;
|
|
202
202
|
tasks: TaskRecord[];
|
|
203
203
|
}>;
|
|
204
|
+
/** Run the one-time mission key migration now (service start, `task migrate-keys`). */
|
|
205
|
+
prepareMissionKeys(): Promise<void>;
|
|
206
|
+
/** One-time key migration under the list lock, honoring `tasks.default_prefix`. */
|
|
207
|
+
private ensureMissionKeys;
|
|
204
208
|
createTaskList(input: {
|
|
205
209
|
actor: TaskRoomActor;
|
|
206
210
|
name: string;
|
|
211
|
+
prefix?: string;
|
|
207
212
|
}): Promise<TaskListRecord>;
|
|
213
|
+
setTaskListPrefix(input: {
|
|
214
|
+
actor: TaskRoomActor;
|
|
215
|
+
name: string;
|
|
216
|
+
prefix: string;
|
|
217
|
+
}): Promise<TaskListRecord>;
|
|
218
|
+
suggestTaskListPrefix(name: string): Promise<string>;
|
|
208
219
|
renameTaskList(input: {
|
|
209
220
|
actor: TaskRoomActor;
|
|
210
221
|
name: string;
|
|
@@ -7,8 +7,8 @@ import { ConfigError, loadConfig } from '../config.js';
|
|
|
7
7
|
import { CoworkProtocolError, CoworkUnavailableError, createCoworkAdapter, } from '../rooms-tasks/cowork-adapter.js';
|
|
8
8
|
import { getBinPath, provisionMembers } from '../rooms-tasks/provision.js';
|
|
9
9
|
import { activateRoom, advanceSaga, createRoomRecord, getRoomRecord, listRoomRecords, setOwnerSeat, setSagaError, } from '../rooms-tasks/room-state.js';
|
|
10
|
-
import { activateTask, blockTask as persistBlockTask, createTask as persistTask, getDeletingTask, getTask as readTask, listTasks as readTasks, taskDeletionState, moveTaskToList, reviewTask as persistReviewTask, startTask as transitionTask, TaskStateError, unblockTask as persistUnblockTask, updateTaskRoom, updateTaskTemplate, updateTaskExecutionPlan, updateTaskBrief, updateTaskLayout, } from '../rooms-tasks/task-state.js';
|
|
11
|
-
import { createTaskListLocked, DEFAULT_TASK_LIST_ID, deleteTaskListRecordLocked, readTaskLists, renameTaskListLocked, resolveTaskList, TaskListError, withTaskListsLock, } from '../rooms-tasks/task-lists.js';
|
|
10
|
+
import { activateTask, blockTask as persistBlockTask, createTask as persistTask, getDeletingTask, getTask as readTask, listTasks as readTasks, taskDeletionState, migrateMissionKeysLocked, moveTaskToList, reviewTask as persistReviewTask, startTask as transitionTask, TaskStateError, unblockTask as persistUnblockTask, updateTaskRoom, updateTaskTemplate, updateTaskExecutionPlan, updateTaskBrief, updateTaskLayout, } from '../rooms-tasks/task-state.js';
|
|
11
|
+
import { createTaskListLocked, DEFAULT_TASK_LIST_ID, deleteTaskListRecordLocked, readTaskLists, renameTaskListLocked, resolveTaskList, setTaskListPrefixLocked, suggestTaskListPrefix, TaskListError, withTaskListsLock, } from '../rooms-tasks/task-lists.js';
|
|
12
12
|
import { hashTemplate, listTemplates, resolveTemplate, sealTemplateSnapshot, snapshotTemplate } from '../rooms-tasks/templates.js';
|
|
13
13
|
import { acquireLaunchSnapshotLock, releaseLaunchSnapshot } from '../rooms-tasks/launch-snapshot.js';
|
|
14
14
|
import { hashMemberOverrides, prepareExecutionPlan } from '../rooms-tasks/member-overrides.js';
|
|
@@ -100,7 +100,7 @@ export class TaskRoomApplicationService {
|
|
|
100
100
|
const task = await withTaskListsLock(() => persistTask({
|
|
101
101
|
title: request.title, brief, brief_file: request.briefFile, layout,
|
|
102
102
|
origin: request.origin, idempotency_key: request.idempotencyKey,
|
|
103
|
-
start: !request.backlog,
|
|
103
|
+
start: !request.backlog, list: request.list ?? 'default',
|
|
104
104
|
}));
|
|
105
105
|
recordFleetAuditPresentation({ kind: 'task', operation: 'create', id: task.task_id,
|
|
106
106
|
title: task.title, previousState: 'none', newState: task.state, revision: task.created_at,
|
|
@@ -200,6 +200,7 @@ export class TaskRoomApplicationService {
|
|
|
200
200
|
return this.layouts().view(task);
|
|
201
201
|
}
|
|
202
202
|
async createTask(request) {
|
|
203
|
+
await this.ensureMissionKeys();
|
|
203
204
|
if (request.layout !== undefined)
|
|
204
205
|
return this.createLayoutTask(request);
|
|
205
206
|
const cfg = (this.deps.loadConfiguration ?? loadConfig)(this.configurationPath);
|
|
@@ -229,15 +230,12 @@ export class TaskRoomApplicationService {
|
|
|
229
230
|
plan_hash: preparedPlan.planHash };
|
|
230
231
|
}
|
|
231
232
|
const ref = template && { name: template.name, version: template.version, content_hash: template.content_hash };
|
|
232
|
-
task = await withTaskListsLock(() => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
start: !request.backlog, no_room: request.noRoom, listId: list.list_id,
|
|
239
|
-
});
|
|
240
|
-
});
|
|
233
|
+
task = await withTaskListsLock(() => persistTask({
|
|
234
|
+
title: request.title, brief, brief_file: request.briefFile, template: ref,
|
|
235
|
+
execution_plan: executionPlan,
|
|
236
|
+
origin: request.origin, idempotency_key: request.idempotencyKey,
|
|
237
|
+
start: !request.backlog, no_room: request.noRoom, list: request.list ?? 'default',
|
|
238
|
+
}));
|
|
241
239
|
}
|
|
242
240
|
catch (error) {
|
|
243
241
|
unlock?.();
|
|
@@ -317,8 +315,31 @@ export class TaskRoomApplicationService {
|
|
|
317
315
|
const lists = filter?.list ? [resolveTaskList(filter.list)] : readTaskLists();
|
|
318
316
|
return lists.map(list => ({ list, tasks: tasks.filter(task => task.list_id === list.list_id) }));
|
|
319
317
|
}
|
|
318
|
+
/** Run the one-time mission key migration now (service start, `task migrate-keys`). */
|
|
319
|
+
prepareMissionKeys() { return this.ensureMissionKeys(); }
|
|
320
|
+
/** One-time key migration under the list lock, honoring `tasks.default_prefix`. */
|
|
321
|
+
ensureMissionKeys() {
|
|
322
|
+
const configured = (() => {
|
|
323
|
+
try {
|
|
324
|
+
return (this.deps.loadConfiguration ?? loadConfig)(this.configurationPath).tasks?.default_prefix;
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
return undefined;
|
|
328
|
+
}
|
|
329
|
+
})();
|
|
330
|
+
return withTaskListsLock(() => migrateMissionKeysLocked(configured));
|
|
331
|
+
}
|
|
320
332
|
async createTaskList(input) {
|
|
321
|
-
|
|
333
|
+
await this.ensureMissionKeys();
|
|
334
|
+
return withTaskListsLock(() => createTaskListLocked(input.name, input.prefix));
|
|
335
|
+
}
|
|
336
|
+
async setTaskListPrefix(input) {
|
|
337
|
+
await this.ensureMissionKeys();
|
|
338
|
+
return withTaskListsLock(() => setTaskListPrefixLocked(input.name, input.prefix));
|
|
339
|
+
}
|
|
340
|
+
async suggestTaskListPrefix(name) {
|
|
341
|
+
await this.ensureMissionKeys();
|
|
342
|
+
return suggestTaskListPrefix(name);
|
|
322
343
|
}
|
|
323
344
|
async renameTaskList(input) {
|
|
324
345
|
return withTaskListsLock(() => renameTaskListLocked(input.name, input.newName));
|
|
@@ -1125,7 +1146,9 @@ export class TaskRoomApplicationService {
|
|
|
1125
1146
|
throw new ConfigError('rooms: configuration is required before creating or querying rooms');
|
|
1126
1147
|
return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config });
|
|
1127
1148
|
})();
|
|
1128
|
-
|
|
1149
|
+
// Only tasks keyed at creation lead with the key: a room create interrupted across the
|
|
1150
|
+
// upgrade must keep the name its earlier attempt used.
|
|
1151
|
+
const roomName = task.task_id ? deriveTaskRoomName(task.title, task.task_id, task.key && !task.key_from_migration ? task.key : undefined) : task.title;
|
|
1129
1152
|
const unlockSnapshot = template ? acquireLaunchSnapshotLock() : undefined;
|
|
1130
1153
|
let launchTemplate;
|
|
1131
1154
|
let room;
|
package/dist/atomic-file.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface ReplaceOptions {
|
|
|
47
47
|
*/
|
|
48
48
|
durable?: boolean;
|
|
49
49
|
}
|
|
50
|
+
/** Make completed renames in `dir` durable; throws where the platform cannot. */
|
|
51
|
+
export declare function fsyncDirectory(dir: string): void;
|
|
50
52
|
/**
|
|
51
53
|
* Run `fn` holding a cross-process lock. A fully populated private claim directory
|
|
52
54
|
* is atomically renamed to the canonical path, so contenders never observe partial
|
package/dist/atomic-file.js
CHANGED
|
@@ -19,7 +19,8 @@ export class FileLockOwnerUnverifiableError extends Error {
|
|
|
19
19
|
this.pid = pid;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
/** Make completed renames in `dir` durable; throws where the platform cannot. */
|
|
23
|
+
export function fsyncDirectory(dir) {
|
|
23
24
|
const dirFd = openSync(dir, 'r');
|
|
24
25
|
try {
|
|
25
26
|
fsyncSync(dirFd);
|
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
3
|
-
"buildId": "
|
|
4
|
-
"commit": "
|
|
2
|
+
"version": "2.3.0",
|
|
3
|
+
"buildId": "246fc0d15b6e",
|
|
4
|
+
"commit": "ce34aa31bf25ec6d0af430270b65f013e3681900",
|
|
5
5
|
"dirty": false,
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-30T17:28:38.538Z",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"service.refresh-v1",
|
|
9
9
|
"managed-cli.codex-reasoning-effort-v1",
|
package/dist/config.d.ts
CHANGED
|
@@ -272,6 +272,12 @@ export interface FleetConfig {
|
|
|
272
272
|
agentDefinitions?: Record<string, AgentDefinition>;
|
|
273
273
|
/** Canonical inert templates keyed by stable template ID. */
|
|
274
274
|
agentTemplates?: Record<string, AgentTemplateDefinition>;
|
|
275
|
+
/**
|
|
276
|
+
* Named Role selected by each Agent Template (`role: { ref: X }`), captured
|
|
277
|
+
* before roles are flattened to `inline`. Naming provenance only: it is kept
|
|
278
|
+
* outside the definitions so launch fingerprints are unchanged.
|
|
279
|
+
*/
|
|
280
|
+
agentTemplateRoleRefs?: Record<string, string>;
|
|
275
281
|
rolePresets?: Record<string, Record<string, unknown>>;
|
|
276
282
|
brainPresets?: Record<string, Record<string, unknown>>;
|
|
277
283
|
/** Required launch-boundary resolver for effective temporary Agent definitions. */
|
package/dist/config.js
CHANGED
|
@@ -427,7 +427,7 @@ function mergeTemplateDefinition(template, overrides, file, id) {
|
|
|
427
427
|
result[key] = merge(result[key], value, key);
|
|
428
428
|
return result;
|
|
429
429
|
}
|
|
430
|
-
function composeSplitRoles(base, baseDoc, yamlMode, diagnostics, files, additionalAgent, templateSink = {}, roleSink = {}, brainSink = {}) {
|
|
430
|
+
function composeSplitRoles(base, baseDoc, yamlMode, diagnostics, files, additionalAgent, templateSink = {}, roleSink = {}, brainSink = {}, roleRefSink = {}) {
|
|
431
431
|
if (baseDoc.api_version !== V2_API_VERSION)
|
|
432
432
|
throw new ConfigError(`${base}: legacy fleet configuration is unsupported; run 'ours-fleet doctor' and rewrite it as ${V2_API_VERSION}`);
|
|
433
433
|
if ('roles' in baseDoc)
|
|
@@ -472,6 +472,8 @@ function composeSplitRoles(base, baseDoc, yamlMode, diagnostics, files, addition
|
|
|
472
472
|
validateBrainValue(templateBrain.value, templateBrain.file, templateBrain.pointer);
|
|
473
473
|
validateAgentScalars(Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'role' && key !== 'brain')), template.file, id);
|
|
474
474
|
canonicalTemplates.set(id, { file: template.file, value });
|
|
475
|
+
if (isPlainObject(value.role) && typeof value.role.ref === 'string')
|
|
476
|
+
roleRefSink[id] = value.role.ref;
|
|
475
477
|
const operational = deepSubStrict(Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'role' && key !== 'brain')), vars, template.file, `/agent_templates/${id}`);
|
|
476
478
|
templateSink[id] = {
|
|
477
479
|
role: { inline: deepSubStrict(templateRole.value, vars, templateRole.file, templateRole.pointer) },
|
|
@@ -614,6 +616,7 @@ export function loadConfig(configPath, options = {}) {
|
|
|
614
616
|
const files = [];
|
|
615
617
|
const diagnostics = [];
|
|
616
618
|
const agentTemplates = {};
|
|
619
|
+
const agentTemplateRoleRefs = {};
|
|
617
620
|
const rolePresets = {};
|
|
618
621
|
const brainPresets = {};
|
|
619
622
|
let docs = [];
|
|
@@ -634,7 +637,7 @@ export function loadConfig(configPath, options = {}) {
|
|
|
634
637
|
const dd = fleetDDir();
|
|
635
638
|
if (existsSync(dd) && readdirSync(dd).some(f => f.endsWith('.yaml') || f.endsWith('.yml')))
|
|
636
639
|
throw new ConfigError(`${dd}: legacy fleet.d configuration is unsupported; run 'ours-fleet doctor' and move agents to ${splitRootFor(base)}/agents/`);
|
|
637
|
-
docs = [{ file: base, doc: manifestDoc }, ...composeSplitRoles(base, manifestDoc, options.yamlMode ?? 'compat', diagnostics, files, options.additionalAgent, agentTemplates, rolePresets, brainPresets)];
|
|
640
|
+
docs = [{ file: base, doc: manifestDoc }, ...composeSplitRoles(base, manifestDoc, options.yamlMode ?? 'compat', diagnostics, files, options.additionalAgent, agentTemplates, rolePresets, brainPresets, agentTemplateRoleRefs)];
|
|
638
641
|
const baseDoc = manifestDoc;
|
|
639
642
|
const vars = (baseDoc.vars ?? {});
|
|
640
643
|
const defaults = (baseDoc.defaults ?? {});
|
|
@@ -822,7 +825,7 @@ export function loadConfig(configPath, options = {}) {
|
|
|
822
825
|
}
|
|
823
826
|
}
|
|
824
827
|
const result = {
|
|
825
|
-
roles, agentDefinitions, agentTemplates, rolePresets, brainPresets, vars, defaults, files, startStaggerMs, diagnostics, watchdogs,
|
|
828
|
+
roles, agentDefinitions, agentTemplates, agentTemplateRoleRefs, rolePresets, brainPresets, vars, defaults, files, startStaggerMs, diagnostics, watchdogs,
|
|
826
829
|
loops: resolvedLoops.loops,
|
|
827
830
|
rooms, roomTemplates, tasks, ownerInviteFingerprint,
|
|
828
831
|
configMode: 'split-v2',
|