@ours.network/fleet 1.0.3 → 1.0.5
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 +13 -9
- package/dist/application/errors.d.ts +1 -1
- package/dist/application/role-command-service.d.ts +29 -1
- package/dist/application/role-command-service.js +41 -2
- package/dist/application/role-creation-service.d.ts +32 -1
- package/dist/application/role-creation-service.js +56 -10
- package/dist/application/role-removal-service.d.ts +19 -0
- package/dist/application/role-removal-service.js +13 -3
- package/dist/application/session-mutations.d.ts +7 -0
- package/dist/application/session-mutations.js +8 -0
- package/dist/application/task-room-service.d.ts +262 -0
- package/dist/application/task-room-service.js +571 -0
- package/dist/atomic-file.d.ts +5 -3
- package/dist/atomic-file.js +32 -8
- package/dist/build-info.json +4 -4
- package/dist/cli.js +39 -15
- package/dist/config.d.ts +6 -3
- package/dist/config.js +0 -17
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +26 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/owner-channel/attachments.d.ts +2 -4
- package/dist/owner-channel/attachments.js +6 -39
- package/dist/owner-channel/channel.d.ts +5 -0
- package/dist/owner-channel/channel.js +159 -21
- package/dist/owner-channel/commands.d.ts +43 -1
- package/dist/owner-channel/commands.js +137 -130
- package/dist/rooms-tasks/cli.js +301 -463
- package/dist/rooms-tasks/task-lists.d.ts +19 -0
- package/dist/rooms-tasks/task-lists.js +96 -0
- package/dist/rooms-tasks/task-state.d.ts +3 -0
- package/dist/rooms-tasks/task-state.js +281 -175
- package/dist/rooms-tasks/types.d.ts +11 -1
- package/dist/runner.js +10 -33
- package/dist/session/control.d.ts +10 -1
- package/dist/session/control.js +22 -21
- package/dist/watchdog/query.d.ts +2 -0
- package/dist/watchdog/query.js +7 -3
- package/dist/web/runtime.js +2 -0
- package/dist/web/server.d.ts +2 -0
- package/dist/web/server.js +88 -3
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TaskListRecord } from './types.js';
|
|
2
|
+
export declare const DEFAULT_TASK_LIST_ID = "default";
|
|
3
|
+
export declare const TASK_LIST_NAME_MAX_CODE_POINTS = 64;
|
|
4
|
+
export declare class TaskListError extends Error {
|
|
5
|
+
readonly code: 'invalid_name' | 'duplicate_name' | 'reserved_name' | 'list_not_found' | 'default_immutable' | 'destination_required' | 'same_destination';
|
|
6
|
+
constructor(code: 'invalid_name' | 'duplicate_name' | 'reserved_name' | 'list_not_found' | 'default_immutable' | 'destination_required' | 'same_destination', message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare const taskListsPath: () => string;
|
|
9
|
+
export declare const taskListsLockPath: () => string;
|
|
10
|
+
export declare const withTaskListsLock: <T>(fn: () => T | Promise<T>) => Promise<T>;
|
|
11
|
+
export declare function normalizeTaskListName(input: string): string;
|
|
12
|
+
export declare function readTaskLists(): TaskListRecord[];
|
|
13
|
+
export declare function resolveTaskList(name: string, lists?: TaskListRecord[]): TaskListRecord;
|
|
14
|
+
/** Caller must hold withTaskListsLock. */
|
|
15
|
+
export declare function createTaskListLocked(name: string): TaskListRecord;
|
|
16
|
+
/** Caller must hold withTaskListsLock. */
|
|
17
|
+
export declare function renameTaskListLocked(currentName: string, nextName: string): TaskListRecord;
|
|
18
|
+
/** Caller must hold withTaskListsLock. */
|
|
19
|
+
export declare function deleteTaskListRecordLocked(listId: string): void;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
|
|
5
|
+
import { stateRoot } from '../paths.js';
|
|
6
|
+
export const DEFAULT_TASK_LIST_ID = 'default';
|
|
7
|
+
export const TASK_LIST_NAME_MAX_CODE_POINTS = 64;
|
|
8
|
+
const CREATED_AT = '1970-01-01T00:00:00.000Z';
|
|
9
|
+
export class TaskListError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
constructor(code, message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.name = 'TaskListError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export const taskListsPath = () => join(stateRoot(), 'task-lists.json');
|
|
18
|
+
export const taskListsLockPath = () => join(stateRoot(), 'task-lists.lock');
|
|
19
|
+
export const withTaskListsLock = (fn) => withFileLock(taskListsLockPath(), fn);
|
|
20
|
+
const defaultList = () => ({
|
|
21
|
+
list_id: DEFAULT_TASK_LIST_ID, name: 'default', built_in: true, created_at: CREATED_AT,
|
|
22
|
+
});
|
|
23
|
+
const compareNames = (a, b) => {
|
|
24
|
+
if (a.list_id === DEFAULT_TASK_LIST_ID)
|
|
25
|
+
return b.list_id === DEFAULT_TASK_LIST_ID ? 0 : -1;
|
|
26
|
+
if (b.list_id === DEFAULT_TASK_LIST_ID)
|
|
27
|
+
return 1;
|
|
28
|
+
return a.name < b.name ? -1 : a.name > b.name ? 1 : a.list_id.localeCompare(b.list_id);
|
|
29
|
+
};
|
|
30
|
+
export function normalizeTaskListName(input) {
|
|
31
|
+
if (typeof input !== 'string')
|
|
32
|
+
throw new TaskListError('invalid_name', 'list name must be a string');
|
|
33
|
+
const normalized = input.normalize('NFC');
|
|
34
|
+
if (normalized.trim() !== normalized || normalized.length === 0)
|
|
35
|
+
throw new TaskListError('invalid_name', 'list name must be non-empty with no leading or trailing whitespace');
|
|
36
|
+
if ([...normalized].length > TASK_LIST_NAME_MAX_CODE_POINTS)
|
|
37
|
+
throw new TaskListError('invalid_name', `list name must be at most ${TASK_LIST_NAME_MAX_CODE_POINTS} Unicode code points`);
|
|
38
|
+
if (/[\p{Cc}\p{Cf}\/\\]/u.test(normalized))
|
|
39
|
+
throw new TaskListError('invalid_name', 'list name contains a forbidden control, format, or path character');
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
export function readTaskLists() {
|
|
43
|
+
const path = taskListsPath();
|
|
44
|
+
if (!existsSync(path))
|
|
45
|
+
return [defaultList()];
|
|
46
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
47
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.lists))
|
|
48
|
+
throw new Error('invalid task list registry');
|
|
49
|
+
const custom = parsed.lists.filter(item => item.list_id !== DEFAULT_TASK_LIST_ID);
|
|
50
|
+
return [defaultList(), ...custom].sort(compareNames);
|
|
51
|
+
}
|
|
52
|
+
function writeTaskLists(lists) {
|
|
53
|
+
const custom = lists.filter(item => item.list_id !== DEFAULT_TASK_LIST_ID).sort(compareNames);
|
|
54
|
+
replaceFileAtomically(taskListsPath(), JSON.stringify({ version: 1, lists: custom }, null, 2) + '\n');
|
|
55
|
+
}
|
|
56
|
+
export function resolveTaskList(name, lists = readTaskLists()) {
|
|
57
|
+
const normalized = normalizeTaskListName(name);
|
|
58
|
+
const found = lists.find(item => item.name === normalized);
|
|
59
|
+
if (!found)
|
|
60
|
+
throw new TaskListError('list_not_found', `task list not found: ${normalized}`);
|
|
61
|
+
return found;
|
|
62
|
+
}
|
|
63
|
+
/** Caller must hold withTaskListsLock. */
|
|
64
|
+
export function createTaskListLocked(name) {
|
|
65
|
+
const normalized = normalizeTaskListName(name);
|
|
66
|
+
if (normalized === 'default')
|
|
67
|
+
throw new TaskListError('reserved_name', "'default' is a reserved built-in list");
|
|
68
|
+
const lists = readTaskLists();
|
|
69
|
+
if (lists.some(item => item.name === normalized))
|
|
70
|
+
throw new TaskListError('duplicate_name', `task list already exists: ${normalized}`);
|
|
71
|
+
const record = {
|
|
72
|
+
list_id: `list_${randomUUID().replace(/-/g, '')}`, name: normalized,
|
|
73
|
+
built_in: false, created_at: new Date().toISOString(),
|
|
74
|
+
};
|
|
75
|
+
writeTaskLists([...lists, record]);
|
|
76
|
+
return record;
|
|
77
|
+
}
|
|
78
|
+
/** Caller must hold withTaskListsLock. */
|
|
79
|
+
export function renameTaskListLocked(currentName, nextName) {
|
|
80
|
+
const lists = readTaskLists();
|
|
81
|
+
const current = resolveTaskList(currentName, lists);
|
|
82
|
+
if (current.built_in)
|
|
83
|
+
throw new TaskListError('default_immutable', "the 'default' list cannot be renamed");
|
|
84
|
+
const normalized = normalizeTaskListName(nextName);
|
|
85
|
+
if (normalized === 'default')
|
|
86
|
+
throw new TaskListError('reserved_name', "'default' is a reserved built-in list");
|
|
87
|
+
if (lists.some(item => item.list_id !== current.list_id && item.name === normalized))
|
|
88
|
+
throw new TaskListError('duplicate_name', `task list already exists: ${normalized}`);
|
|
89
|
+
const renamed = { ...current, name: normalized };
|
|
90
|
+
writeTaskLists(lists.map(item => item.list_id === current.list_id ? renamed : item));
|
|
91
|
+
return renamed;
|
|
92
|
+
}
|
|
93
|
+
/** Caller must hold withTaskListsLock. */
|
|
94
|
+
export function deleteTaskListRecordLocked(listId) {
|
|
95
|
+
writeTaskLists(readTaskLists().filter(item => item.list_id !== listId));
|
|
96
|
+
}
|
|
@@ -12,12 +12,15 @@ export interface CreateTaskInput {
|
|
|
12
12
|
start?: boolean;
|
|
13
13
|
no_room?: boolean;
|
|
14
14
|
room_id?: string;
|
|
15
|
+
listId?: string;
|
|
15
16
|
}
|
|
16
17
|
export declare function createTask(input: CreateTaskInput): TaskRecord;
|
|
17
18
|
export declare function getTask(id: string): TaskRecord;
|
|
18
19
|
export declare function listTasks(filter?: {
|
|
19
20
|
state?: TaskState | TaskState[];
|
|
21
|
+
listId?: string;
|
|
20
22
|
}): TaskRecord[];
|
|
23
|
+
export declare function moveTaskToList(id: string, listId: string): TaskRecord;
|
|
21
24
|
export declare function findByIdempotencyKey(key: string): TaskRecord | undefined;
|
|
22
25
|
export declare function startTask(id: string): TaskRecord;
|
|
23
26
|
export declare function activateTask(id: string): TaskRecord;
|