@ours.network/fleet 1.0.5 → 1.1.0-nightly.10
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 +122 -133
- package/dist/agent-recovery-gate.d.ts +17 -0
- package/dist/agent-recovery-gate.js +135 -0
- package/dist/application/capabilities.d.ts +0 -1
- package/dist/application/capabilities.js +3 -13
- package/dist/application/fleet-query-service.d.ts +0 -3
- package/dist/application/fleet-query-service.js +14 -25
- package/dist/application/role-creation-service.d.ts +5 -24
- package/dist/application/role-creation-service.js +27 -67
- package/dist/application/role-removal-service.js +6 -3
- package/dist/application/role-repository.d.ts +1 -2
- package/dist/application/role-repository.js +7 -7
- package/dist/application/session-control.d.ts +0 -12
- package/dist/application/session-control.js +0 -42
- package/dist/application/session-mutations.d.ts +5 -5
- package/dist/application/task-room-service.d.ts +1 -1
- package/dist/application/task-room-service.js +154 -16
- package/dist/application/types.d.ts +1 -8
- package/dist/briefing.js +12 -11
- package/dist/build-info.json +5 -5
- package/dist/cli.js +143 -63
- package/dist/config-yaml.d.ts +1 -1
- package/dist/config.d.ts +66 -6
- package/dist/config.js +398 -43
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +2 -2
- 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 +103 -127
- package/dist/doctor.js +18 -11
- package/dist/fleet-command-audit.d.ts +160 -0
- package/dist/fleet-command-audit.js +433 -0
- package/dist/fleet-proxy.d.ts +3 -1
- package/dist/fleet-proxy.js +30 -8
- package/dist/generated-agent-source.d.ts +9 -0
- package/dist/generated-agent-source.js +53 -0
- package/dist/harness/acp-session-transport.d.ts +8 -0
- package/dist/harness/acp-session-transport.js +3 -0
- package/dist/harness/agent-session.d.ts +51 -0
- package/dist/harness/agent-session.js +1 -0
- package/dist/harness/claude-code-session.d.ts +24 -0
- package/dist/harness/claude-code-session.js +36 -0
- package/dist/harness/claude-code.d.ts +2 -1
- package/dist/harness/claude-code.js +41 -81
- package/dist/harness/codex-session.d.ts +24 -0
- package/dist/harness/codex-session.js +36 -0
- package/dist/harness/codex.d.ts +2 -1
- package/dist/harness/codex.js +55 -45
- package/dist/harness/registry.js +4 -0
- package/dist/harness/types.d.ts +6 -38
- package/dist/index.d.ts +4 -6
- package/dist/index.js +2 -4
- package/dist/init-guidance.d.ts +1 -0
- package/dist/init-guidance.js +6 -0
- package/dist/isolation/resources.d.ts +3 -7
- package/dist/isolation/resources.js +3 -7
- package/dist/model-env.d.ts +4 -6
- package/dist/model-env.js +5 -8
- package/dist/monitor.d.ts +1 -24
- package/dist/monitor.js +5 -140
- package/dist/ops.js +4 -2
- package/dist/owner-channel/channel.d.ts +58 -2
- package/dist/owner-channel/channel.js +269 -29
- package/dist/owner-channel/commands.d.ts +2 -0
- package/dist/owner-channel/commands.js +31 -13
- package/dist/owner-channel/state.d.ts +2 -0
- package/dist/owner-channel/state.js +8 -2
- package/dist/preset-bootstrap.d.ts +10 -0
- package/dist/preset-bootstrap.js +85 -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.d.ts +3 -2
- package/dist/resolved-plan.js +21 -5
- package/dist/rooms-tasks/cli.js +225 -40
- package/dist/rooms-tasks/config.js +24 -13
- package/dist/rooms-tasks/external-worker.d.ts +1 -0
- package/dist/rooms-tasks/external-worker.js +14 -9
- package/dist/rooms-tasks/provision.js +98 -36
- package/dist/rooms-tasks/templates.d.ts +0 -1
- package/dist/rooms-tasks/templates.js +9 -76
- package/dist/rooms-tasks/types.d.ts +10 -16
- package/dist/rooms-tasks/types.js +1 -4
- package/dist/runner.d.ts +13 -16
- package/dist/runner.js +110 -122
- package/dist/sensitive-config.d.ts +2 -0
- package/dist/sensitive-config.js +4 -0
- package/dist/session/acp.d.ts +7 -2
- package/dist/session/acp.js +29 -6
- package/dist/session/activity.d.ts +2 -3
- package/dist/session/activity.js +2 -3
- package/dist/session/arbiter.d.ts +4 -4
- package/dist/session/control.d.ts +17 -4
- package/dist/session/control.js +35 -0
- package/dist/session/types.d.ts +11 -5
- package/dist/spawn.d.ts +8 -33
- package/dist/spawn.js +53 -213
- package/dist/supervisor/none.d.ts +1 -1
- package/dist/supervisor/none.js +2 -2
- package/dist/temp-lifecycle.d.ts +1 -1
- package/dist/tmux.d.ts +1 -14
- package/dist/tmux.js +1 -51
- package/dist/watchdog/config.d.ts +10 -7
- package/dist/watchdog/config.js +30 -18
- package/dist/watchdog/run.js +12 -36
- package/dist/web/auth.d.ts +1 -1
- package/dist/web/fleet-config-service.d.ts +11 -8
- package/dist/web/fleet-config-service.js +384 -183
- package/dist/web/runtime.js +4 -15
- package/dist/web/server.d.ts +1 -3
- package/dist/web/server.js +3 -14
- package/dist/web/topology-promote.js +26 -19
- package/dist/web/topology.js +2 -2
- package/dist/web/yaml-document-edit.js +2 -0
- package/dist/web-app/assets/index-59GF-gsZ.css +1 -0
- package/dist/web-app/assets/index-BbTc5KtZ.js +10 -0
- package/dist/web-app/index.html +2 -2
- package/examples/fleet/agents/Alice.yaml +11 -0
- package/examples/fleet/agents/FleetCoordinator.yaml +7 -0
- package/examples/fleet/brains/claude-default.yaml +5 -0
- package/examples/fleet/roles/coordinator.yaml +5 -0
- package/examples/fleet/roles/developer.yaml +3 -0
- package/examples/fleet.yaml +74 -0
- package/package.json +5 -8
- package/presets/fleet/agents/Agent.yaml +3 -0
- package/presets/fleet/agents/Architect.yaml +3 -0
- package/presets/fleet/agents/Critic.yaml +3 -0
- package/presets/fleet/agents/Developer.yaml +3 -0
- package/presets/fleet/agents/Secretary.yaml +3 -0
- package/presets/fleet/agents/Tester.yaml +3 -0
- package/presets/fleet/brains/claude-default.yaml +5 -0
- package/presets/fleet/roles/Agent.yaml +6 -0
- package/presets/fleet/roles/Architect.yaml +6 -0
- package/presets/fleet/roles/Critic.yaml +6 -0
- package/presets/fleet/roles/Developer.yaml +6 -0
- package/presets/fleet/roles/Secretary.yaml +6 -0
- package/presets/fleet/roles/Tester.yaml +6 -0
- package/presets/fleet/room_templates/pair.yaml +11 -0
- package/presets/fleet/room_templates/single.yaml +8 -0
- package/presets/fleet/room_templates/team.yaml +12 -0
- package/presets/fleet.yaml +7 -0
- package/presets/manifest.json +5 -0
- package/dist/session/tmux.d.ts +0 -28
- package/dist/session/tmux.js +0 -80
- package/dist/web/terminal/bridge.d.ts +0 -27
- package/dist/web/terminal/bridge.js +0 -317
- package/dist/web-app/assets/TerminalView-C_G1ID2P.js +0 -9
- package/dist/web-app/assets/index-BCBK78hw.js +0 -10
- package/dist/web-app/assets/index-DuC-xnX4.css +0 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { FleetReportService, ReportRegistry } from './service.js';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
export const TASK_REPORT_MAX_RECORDS = 200;
|
|
4
|
+
export const TASK_REPORT_MAX_TEXT = 2_000;
|
|
5
|
+
const TASK_REPORT_BRIEF_PREVIEW = 240;
|
|
6
|
+
const STATUS_LABEL = {
|
|
7
|
+
backlog: 'Backlog', provisioning: 'Provisioning', active: 'Active', review: 'Review',
|
|
8
|
+
done: 'Done', cancelled: 'Cancelled', failed: 'Failed',
|
|
9
|
+
};
|
|
10
|
+
const STATUS_TONE = {
|
|
11
|
+
backlog: 'neutral', provisioning: 'warning', active: 'good', review: 'warning',
|
|
12
|
+
done: 'good', cancelled: 'neutral', failed: 'bad',
|
|
13
|
+
};
|
|
14
|
+
const bounded = (value, limit = TASK_REPORT_MAX_TEXT) => {
|
|
15
|
+
if (value === undefined)
|
|
16
|
+
return null;
|
|
17
|
+
const points = [...value];
|
|
18
|
+
return points.length <= limit ? value
|
|
19
|
+
: `${points.slice(0, Math.max(0, limit - 34)).join('')}… [truncated from ${points.length} chars]`;
|
|
20
|
+
};
|
|
21
|
+
const briefPreview = (value) => {
|
|
22
|
+
const first = value?.split(/\r?\n/u).map(line => line.trim()).find(Boolean);
|
|
23
|
+
return bounded(first, TASK_REPORT_BRIEF_PREVIEW) ?? 'No brief supplied.';
|
|
24
|
+
};
|
|
25
|
+
const field = (label, value, tone, multiline = false) => ({
|
|
26
|
+
label, value, ...(tone ? { tone } : {}), ...(multiline ? { multiline: true } : {}),
|
|
27
|
+
});
|
|
28
|
+
const allowlistList = (list) => ({
|
|
29
|
+
list_id: list.list_id, name: bounded(list.name) ?? 'Unnamed list', built_in: list.built_in,
|
|
30
|
+
});
|
|
31
|
+
const allowlistTask = (task) => ({
|
|
32
|
+
task_id: task.task_id, list_id: task.list_id, list_name: bounded(task.list_name) ?? 'default',
|
|
33
|
+
title: bounded(task.title) ?? 'Untitled task', ...(task.brief === undefined ? {} : { brief: bounded(task.brief) ?? '' }),
|
|
34
|
+
state: task.state, ...(task.blocked ? { blocked: { reason: bounded(task.blocked.reason) ?? 'Blocked' } } : {}),
|
|
35
|
+
...(task.room_id ? { room_id: bounded(task.room_id) ?? undefined } : {}),
|
|
36
|
+
...(task.template ? { template: { name: bounded(task.template.name) ?? 'Unknown', version: task.template.version } } : {}),
|
|
37
|
+
member_roles: task.member_roles.map(member => ({ name: bounded(member.name) ?? 'Unknown', slot: bounded(member.slot) ?? 'Unknown', cowork_role: bounded(member.cowork_role) ?? 'Unknown' })),
|
|
38
|
+
origin: { type: task.origin.type }, created_at: task.created_at,
|
|
39
|
+
...(task.started_at ? { started_at: task.started_at } : {}), ...(task.ended_at ? { ended_at: task.ended_at } : {}),
|
|
40
|
+
...(task.outcome ? { outcome: { summary: bounded(task.outcome.summary) ?? undefined } } : {}),
|
|
41
|
+
});
|
|
42
|
+
function safeTask(task) {
|
|
43
|
+
const status = STATUS_LABEL[task.state];
|
|
44
|
+
const title = bounded(task.title) ?? 'Untitled task';
|
|
45
|
+
const brief = briefPreview(task.brief);
|
|
46
|
+
const groups = [
|
|
47
|
+
{ title: '1. Identity and lifecycle', values: [
|
|
48
|
+
field('Task ID', task.task_id), field('Title', title),
|
|
49
|
+
field('Lifecycle status', status, STATUS_TONE[task.state]), field('List', task.list_name),
|
|
50
|
+
field('Blocked indicator', task.blocked ? bounded(task.blocked.reason) : 'No — unblocked', task.blocked ? 'warning' : undefined),
|
|
51
|
+
] },
|
|
52
|
+
{ title: '2. Task content', values: [
|
|
53
|
+
field('Brief', brief, undefined, true),
|
|
54
|
+
field('Detailed description', bounded(task.brief), undefined, true),
|
|
55
|
+
] },
|
|
56
|
+
{ title: '3. Work context', values: [
|
|
57
|
+
field('Room', task.room_id ?? null),
|
|
58
|
+
field('Template', task.template ? `${task.template.name}@${task.template.version}` : null),
|
|
59
|
+
field('Members and roles', task.member_roles.length
|
|
60
|
+
? bounded(task.member_roles.map(member => `${member.name} — ${member.slot} — ${member.cowork_role}`).join('\n')) : null, undefined, true),
|
|
61
|
+
field('Origin', task.origin.type),
|
|
62
|
+
] },
|
|
63
|
+
{ title: '4. Timeline and outcome', values: [
|
|
64
|
+
field('Created', task.created_at), field('Started', task.started_at ?? null), field('Ended', task.ended_at ?? null),
|
|
65
|
+
field('Terminal outcome', bounded(task.outcome?.summary), undefined, true),
|
|
66
|
+
] },
|
|
67
|
+
];
|
|
68
|
+
return {
|
|
69
|
+
id: task.task_id, title, brief, status,
|
|
70
|
+
...(task.blocked ? { blocked: bounded(task.blocked.reason) ?? 'Blocked' } : {}), updated: task.ended_at ?? task.started_at ?? task.created_at,
|
|
71
|
+
groups,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function presentTasksReport(input) {
|
|
75
|
+
const maxRecords = input.maxRecords ?? TASK_REPORT_MAX_RECORDS;
|
|
76
|
+
const includedLists = input.selectedList
|
|
77
|
+
? input.lists.filter(list => list.name === input.selectedList) : input.lists;
|
|
78
|
+
let remaining = maxRecords;
|
|
79
|
+
const panels = includedLists.map(list => {
|
|
80
|
+
const all = input.tasks.filter(task => task.list_id === list.list_id);
|
|
81
|
+
const total = input.totalsByList?.[list.list_id] ?? all.length;
|
|
82
|
+
const shown = all.slice(0, remaining);
|
|
83
|
+
remaining -= shown.length;
|
|
84
|
+
return {
|
|
85
|
+
id: list.list_id, name: list.name, total, shown: shown.length,
|
|
86
|
+
description: shown.length === total ? `All ${total} tasks are included in source order.`
|
|
87
|
+
: `${shown.length} of ${total} tasks are included by the report bound; source order is preserved.`,
|
|
88
|
+
tasks: shown.map(safeTask),
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
const defaultList = includedLists.find(list => list.name === input.selectedList)?.list_id
|
|
92
|
+
?? includedLists.find(list => list.built_in)?.list_id ?? includedLists[0]?.list_id ?? 'default';
|
|
93
|
+
const section = {
|
|
94
|
+
kind: 'task-navigator', id: 'task-lists', title: 'Fleet task lists',
|
|
95
|
+
description: 'One read-only task report shared by task and list commands.',
|
|
96
|
+
lists: panels.map(panel => ({ id: panel.id, name: panel.name, count: panel.total,
|
|
97
|
+
blocked: panel.tasks.filter(task => task.blocked).length })), defaultList, panels,
|
|
98
|
+
};
|
|
99
|
+
return {
|
|
100
|
+
schemaVersion: 1, reportKind: 'tasks', title: 'Fleet task lists',
|
|
101
|
+
description: section.description, generatedAt: input.generatedAt,
|
|
102
|
+
source: input.source ?? { name: 'ours-fleet', version: '1' },
|
|
103
|
+
filters: { ...(input.selectedList ? { list: input.selectedList } : {}), ...(input.state ? { state: input.state } : {}) },
|
|
104
|
+
observedAt: input.observedAt ? { tasks: input.observedAt } : {}, unavailable: [], sections: [section],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export function buildTasksReport(input) {
|
|
108
|
+
return presentTasksReport({ ...input, lists: input.lists.map(allowlistList), tasks: input.tasks.map(allowlistTask) });
|
|
109
|
+
}
|
|
110
|
+
export async function createTasksReport(input) {
|
|
111
|
+
const request = {
|
|
112
|
+
kind: 'tasks', viewer: input.viewer,
|
|
113
|
+
...(input.state ? { state: input.state } : {}),
|
|
114
|
+
...(input.selectedList ? { list: input.selectedList } : {}),
|
|
115
|
+
};
|
|
116
|
+
const registry = new ReportRegistry().register({
|
|
117
|
+
kind: 'tasks', maxRecords: TASK_REPORT_MAX_RECORDS,
|
|
118
|
+
validate: (candidate) => candidate.kind === 'tasks',
|
|
119
|
+
resourceId: () => undefined,
|
|
120
|
+
present: (candidate, snapshot, generatedAt) => presentTasksReport({
|
|
121
|
+
...snapshot.data, generatedAt, observedAt: snapshot.observedAt.tasks, source: input.source,
|
|
122
|
+
selectedList: candidate.list, state: candidate.state,
|
|
123
|
+
maxRecords: TASK_REPORT_MAX_RECORDS,
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
const provider = {
|
|
127
|
+
surface: input.viewer.surface,
|
|
128
|
+
collect: async (_request, limits) => {
|
|
129
|
+
const data = await input.collect(limits);
|
|
130
|
+
const observedAt = new Date().toISOString();
|
|
131
|
+
const total = data.tasks.length;
|
|
132
|
+
const tasks = data.tasks.slice(0, limits.maxRecords).map(allowlistTask);
|
|
133
|
+
const totalsByList = data.tasks.reduce((totals, task) => {
|
|
134
|
+
totals[task.list_id] = (totals[task.list_id] ?? 0) + 1;
|
|
135
|
+
return totals;
|
|
136
|
+
}, {});
|
|
137
|
+
return { data: { lists: data.lists.map(allowlistList), tasks, totalsByList }, observedAt: { tasks: observedAt }, unavailable: [], stale: [],
|
|
138
|
+
bounds: { shown: tasks.length, total, truncated: total > tasks.length } };
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
return new FleetReportService(registry, input.maxBytes)
|
|
142
|
+
.create(request, { provider, generatedAt: input.generatedAt ?? new Date().toISOString() });
|
|
143
|
+
}
|
|
144
|
+
export async function createTaskReport(input) {
|
|
145
|
+
const request = { kind: 'task', viewer: input.viewer, taskId: input.taskId };
|
|
146
|
+
const resourceSlug = input.taskId.toLowerCase().replace(/[^a-z0-9_-]+/gu, '-').replace(/^-+|-+$/gu, '').slice(0, 68) || 'task';
|
|
147
|
+
const resourceName = `${resourceSlug}-${createHash('sha256').update(input.taskId).digest('hex').slice(0, 10)}`;
|
|
148
|
+
const registry = new ReportRegistry().register({
|
|
149
|
+
kind: 'task', maxRecords: 1,
|
|
150
|
+
validate: (candidate) => candidate.kind === 'task'
|
|
151
|
+
&& typeof candidate.taskId === 'string' && candidate.taskId.length > 0 && candidate.taskId.length <= 200,
|
|
152
|
+
resourceId: () => resourceName,
|
|
153
|
+
present: (candidate, snapshot, generatedAt) => {
|
|
154
|
+
const task = snapshot.data;
|
|
155
|
+
const model = presentTasksReport({
|
|
156
|
+
lists: [{ list_id: task.list_id, name: task.list_name, built_in: task.list_id === 'default' }],
|
|
157
|
+
tasks: [task], generatedAt, observedAt: snapshot.observedAt.tasks, source: input.source,
|
|
158
|
+
selectedList: task.list_name, maxRecords: 1,
|
|
159
|
+
});
|
|
160
|
+
return { ...model, reportKind: 'task', title: `Task — ${task.title}`,
|
|
161
|
+
description: `Focused read-only task report for ${candidate.taskId}.`, filters: { task: candidate.taskId } };
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
const provider = {
|
|
165
|
+
surface: input.viewer.surface,
|
|
166
|
+
collect: async () => {
|
|
167
|
+
const collected = await input.collect();
|
|
168
|
+
if (collected.task_id !== input.taskId)
|
|
169
|
+
throw new Error('authorized task provider returned a mismatched resource');
|
|
170
|
+
const task = allowlistTask(collected);
|
|
171
|
+
return { data: task, observedAt: { tasks: new Date().toISOString() }, unavailable: [], stale: [],
|
|
172
|
+
bounds: { shown: 1, total: 1, truncated: false } };
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
return new FleetReportService(registry, input.maxBytes)
|
|
176
|
+
.create(request, { provider, generatedAt: input.generatedAt ?? new Date().toISOString() });
|
|
177
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
export declare const REPORT_KINDS: readonly ["overview", "tasks", "task-lists", "task", "rooms", "room", "room-members", "agents", "agent-status", "templates", "template", "template-validation", "loops", "loop-status", "loop-validation", "watchdog", "watchdog-runs", "version", "config", "doctor", "manual"];
|
|
2
|
+
export type ReportKind = typeof REPORT_KINDS[number];
|
|
3
|
+
export type ReportTone = 'neutral' | 'good' | 'warning' | 'bad' | 'unknown';
|
|
4
|
+
export interface ReportValue {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string | number | boolean | null;
|
|
7
|
+
tone?: ReportTone;
|
|
8
|
+
/** Internal artifact link only; the renderer derives the fragment. */
|
|
9
|
+
target?: {
|
|
10
|
+
section: string;
|
|
11
|
+
id?: string;
|
|
12
|
+
};
|
|
13
|
+
multiline?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export type ReportViewer = {
|
|
16
|
+
surface: 'cli';
|
|
17
|
+
authority: 'local-owner';
|
|
18
|
+
} | {
|
|
19
|
+
surface: 'rest';
|
|
20
|
+
sessionId: string;
|
|
21
|
+
roomCids: string[];
|
|
22
|
+
} | {
|
|
23
|
+
surface: 'messenger';
|
|
24
|
+
authenticatedCid: string;
|
|
25
|
+
roomCids: string[];
|
|
26
|
+
};
|
|
27
|
+
export type ReportRequest = {
|
|
28
|
+
kind: 'overview';
|
|
29
|
+
viewer: ReportViewer;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'tasks';
|
|
32
|
+
viewer: ReportViewer;
|
|
33
|
+
state?: string;
|
|
34
|
+
list?: string;
|
|
35
|
+
groupByList?: boolean;
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'task-lists';
|
|
38
|
+
viewer: ReportViewer;
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'task';
|
|
41
|
+
viewer: ReportViewer;
|
|
42
|
+
taskId: string;
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'rooms';
|
|
45
|
+
viewer: ReportViewer;
|
|
46
|
+
state?: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: 'room';
|
|
49
|
+
viewer: ReportViewer;
|
|
50
|
+
roomId: string;
|
|
51
|
+
} | {
|
|
52
|
+
kind: 'room-members';
|
|
53
|
+
viewer: ReportViewer;
|
|
54
|
+
roomId: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'agents';
|
|
57
|
+
viewer: ReportViewer;
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'agent-status';
|
|
60
|
+
viewer: ReportViewer;
|
|
61
|
+
role: string;
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'templates' | 'template-validation';
|
|
64
|
+
viewer: ReportViewer;
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'template';
|
|
67
|
+
viewer: ReportViewer;
|
|
68
|
+
name: string;
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'loops' | 'loop-validation';
|
|
71
|
+
viewer: ReportViewer;
|
|
72
|
+
role?: string;
|
|
73
|
+
} | {
|
|
74
|
+
kind: 'loop-status';
|
|
75
|
+
viewer: ReportViewer;
|
|
76
|
+
role?: string;
|
|
77
|
+
loop?: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: 'watchdog';
|
|
80
|
+
viewer: ReportViewer;
|
|
81
|
+
watchdog: string;
|
|
82
|
+
runId?: string;
|
|
83
|
+
} | {
|
|
84
|
+
kind: 'watchdog-runs';
|
|
85
|
+
viewer: ReportViewer;
|
|
86
|
+
watchdog: string;
|
|
87
|
+
} | {
|
|
88
|
+
kind: 'version' | 'config' | 'doctor' | 'manual';
|
|
89
|
+
viewer: ReportViewer;
|
|
90
|
+
};
|
|
91
|
+
export interface ReportTable {
|
|
92
|
+
kind: 'table';
|
|
93
|
+
id: string;
|
|
94
|
+
title: string;
|
|
95
|
+
description?: string;
|
|
96
|
+
columns: string[];
|
|
97
|
+
rows: Array<{
|
|
98
|
+
id?: string;
|
|
99
|
+
cells: ReportValue[];
|
|
100
|
+
}>;
|
|
101
|
+
empty?: string;
|
|
102
|
+
truncated?: {
|
|
103
|
+
shown: number;
|
|
104
|
+
total: number;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export interface ReportDetails {
|
|
108
|
+
kind: 'details';
|
|
109
|
+
id: string;
|
|
110
|
+
title: string;
|
|
111
|
+
description?: string;
|
|
112
|
+
values: ReportValue[];
|
|
113
|
+
paragraphs?: string[];
|
|
114
|
+
}
|
|
115
|
+
export interface ReportNotice {
|
|
116
|
+
kind: 'notice';
|
|
117
|
+
id: string;
|
|
118
|
+
title: string;
|
|
119
|
+
tone: ReportTone;
|
|
120
|
+
text: string;
|
|
121
|
+
}
|
|
122
|
+
export interface ReportCards {
|
|
123
|
+
kind: 'cards';
|
|
124
|
+
id: string;
|
|
125
|
+
title: string;
|
|
126
|
+
description?: string;
|
|
127
|
+
items: Array<{
|
|
128
|
+
id: string;
|
|
129
|
+
title: string;
|
|
130
|
+
subtitle?: string;
|
|
131
|
+
tone?: ReportTone;
|
|
132
|
+
values: ReportValue[];
|
|
133
|
+
paragraphs?: string[];
|
|
134
|
+
open?: boolean;
|
|
135
|
+
}>;
|
|
136
|
+
empty?: string;
|
|
137
|
+
truncated?: {
|
|
138
|
+
shown: number;
|
|
139
|
+
total: number;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export interface ReportRecords {
|
|
143
|
+
kind: 'records';
|
|
144
|
+
id: string;
|
|
145
|
+
title: string;
|
|
146
|
+
description?: string;
|
|
147
|
+
items: Array<{
|
|
148
|
+
id: string;
|
|
149
|
+
title: string;
|
|
150
|
+
subtitle: string;
|
|
151
|
+
tone?: ReportTone;
|
|
152
|
+
open?: boolean;
|
|
153
|
+
groups: Array<{
|
|
154
|
+
title: string;
|
|
155
|
+
values: ReportValue[];
|
|
156
|
+
}>;
|
|
157
|
+
}>;
|
|
158
|
+
empty?: string;
|
|
159
|
+
truncated?: {
|
|
160
|
+
shown: number;
|
|
161
|
+
total: number;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export interface ReportListBoard {
|
|
165
|
+
kind: 'list-board';
|
|
166
|
+
id: string;
|
|
167
|
+
title: string;
|
|
168
|
+
description?: string;
|
|
169
|
+
items: Array<{
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
builtIn: boolean;
|
|
173
|
+
createdAt: string | null;
|
|
174
|
+
counts: {
|
|
175
|
+
total: number;
|
|
176
|
+
active: number;
|
|
177
|
+
blocked: number;
|
|
178
|
+
terminal: number;
|
|
179
|
+
};
|
|
180
|
+
taskTarget: {
|
|
181
|
+
section: string;
|
|
182
|
+
};
|
|
183
|
+
recent: ReportValue[];
|
|
184
|
+
recentTotal: number;
|
|
185
|
+
}>;
|
|
186
|
+
truncated?: {
|
|
187
|
+
shown: number;
|
|
188
|
+
total: number;
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
export interface ReportInbox {
|
|
192
|
+
kind: 'inbox';
|
|
193
|
+
id: string;
|
|
194
|
+
title: string;
|
|
195
|
+
description: string;
|
|
196
|
+
lists: Array<{
|
|
197
|
+
id: string;
|
|
198
|
+
name: string;
|
|
199
|
+
count: number;
|
|
200
|
+
blocked: number;
|
|
201
|
+
selected: boolean;
|
|
202
|
+
}>;
|
|
203
|
+
selected: {
|
|
204
|
+
name: string;
|
|
205
|
+
total: number;
|
|
206
|
+
shown: number;
|
|
207
|
+
};
|
|
208
|
+
attention: Array<{
|
|
209
|
+
id: string;
|
|
210
|
+
title: string;
|
|
211
|
+
brief: string;
|
|
212
|
+
status: string;
|
|
213
|
+
blocker: string;
|
|
214
|
+
updated: string;
|
|
215
|
+
groups: Array<{
|
|
216
|
+
title: string;
|
|
217
|
+
values: ReportValue[];
|
|
218
|
+
}>;
|
|
219
|
+
}>;
|
|
220
|
+
active: Array<{
|
|
221
|
+
id: string;
|
|
222
|
+
title: string;
|
|
223
|
+
brief: string;
|
|
224
|
+
status: string;
|
|
225
|
+
updated: string;
|
|
226
|
+
groups: Array<{
|
|
227
|
+
title: string;
|
|
228
|
+
values: ReportValue[];
|
|
229
|
+
}>;
|
|
230
|
+
}>;
|
|
231
|
+
terminal: Array<{
|
|
232
|
+
id: string;
|
|
233
|
+
title: string;
|
|
234
|
+
brief: string;
|
|
235
|
+
status: string;
|
|
236
|
+
updated: string;
|
|
237
|
+
outcome: string;
|
|
238
|
+
}>;
|
|
239
|
+
}
|
|
240
|
+
export interface ReportTaskNavigator {
|
|
241
|
+
kind: 'task-navigator';
|
|
242
|
+
id: string;
|
|
243
|
+
title: string;
|
|
244
|
+
description: string;
|
|
245
|
+
lists: Array<{
|
|
246
|
+
id: string;
|
|
247
|
+
name: string;
|
|
248
|
+
count: number;
|
|
249
|
+
blocked: number;
|
|
250
|
+
}>;
|
|
251
|
+
defaultList: string;
|
|
252
|
+
panels: Array<{
|
|
253
|
+
id: string;
|
|
254
|
+
name: string;
|
|
255
|
+
total: number;
|
|
256
|
+
shown: number;
|
|
257
|
+
description: string;
|
|
258
|
+
tasks: Array<{
|
|
259
|
+
id: string;
|
|
260
|
+
title: string;
|
|
261
|
+
brief: string;
|
|
262
|
+
status: string;
|
|
263
|
+
blocked?: string;
|
|
264
|
+
updated: string;
|
|
265
|
+
groups: Array<{
|
|
266
|
+
title: string;
|
|
267
|
+
values: ReportValue[];
|
|
268
|
+
}>;
|
|
269
|
+
}>;
|
|
270
|
+
}>;
|
|
271
|
+
}
|
|
272
|
+
export type ReportSection = ReportTable | ReportDetails | ReportNotice | ReportCards | ReportRecords | ReportListBoard | ReportInbox | ReportTaskNavigator;
|
|
273
|
+
export interface ReportViewModel {
|
|
274
|
+
schemaVersion: 1;
|
|
275
|
+
reportKind: ReportKind;
|
|
276
|
+
title: string;
|
|
277
|
+
description?: string;
|
|
278
|
+
generatedAt: string;
|
|
279
|
+
source: {
|
|
280
|
+
name: string;
|
|
281
|
+
version: string;
|
|
282
|
+
buildId?: string;
|
|
283
|
+
};
|
|
284
|
+
filters?: Record<string, string>;
|
|
285
|
+
observedAt?: Record<string, string>;
|
|
286
|
+
summary?: ReportValue[];
|
|
287
|
+
sections: ReportSection[];
|
|
288
|
+
unavailable?: string[];
|
|
289
|
+
}
|
|
290
|
+
export interface ReportArtifactMetadata {
|
|
291
|
+
schemaVersion: 1;
|
|
292
|
+
reportKind: ReportKind;
|
|
293
|
+
filename: string;
|
|
294
|
+
mediaType: 'text/html; charset=utf-8';
|
|
295
|
+
byteSize: number;
|
|
296
|
+
source: {
|
|
297
|
+
name: string;
|
|
298
|
+
version: string;
|
|
299
|
+
buildId?: string;
|
|
300
|
+
};
|
|
301
|
+
generatedAt: string;
|
|
302
|
+
filters: Record<string, string>;
|
|
303
|
+
truncated: boolean;
|
|
304
|
+
unavailable: string[];
|
|
305
|
+
observedAt: Record<string, string>;
|
|
306
|
+
truncation: Array<{
|
|
307
|
+
section: string;
|
|
308
|
+
shown: number;
|
|
309
|
+
total: number;
|
|
310
|
+
}>;
|
|
311
|
+
}
|
|
312
|
+
export interface ReportArtifact {
|
|
313
|
+
metadata: ReportArtifactMetadata;
|
|
314
|
+
html: string;
|
|
315
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const REPORT_KINDS = [
|
|
2
|
+
'overview', 'tasks', 'task-lists', 'task', 'rooms', 'room', 'room-members',
|
|
3
|
+
'agents', 'agent-status', 'templates', 'template', 'template-validation',
|
|
4
|
+
'loops', 'loop-status', 'loop-validation', 'watchdog', 'watchdog-runs',
|
|
5
|
+
'version', 'config', 'doctor', 'manual',
|
|
6
|
+
];
|
package/dist/resolved-plan.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FleetConfig, ResolvedRole } from './config.js';
|
|
2
|
-
export declare const RESOLVED_PLAN_SCHEMA_VERSION =
|
|
2
|
+
export declare const RESOLVED_PLAN_SCHEMA_VERSION = 2;
|
|
3
|
+
export declare const redactSensitive: (value: unknown, key?: string) => unknown;
|
|
3
4
|
/** Stable, secret-safe machine contract consumed by config JSON and spawn dry-run. */
|
|
4
5
|
export declare function resolvedPlan(cfg: FleetConfig): Record<string, unknown>;
|
|
5
|
-
export declare function resolvedRolePlan(role: ResolvedRole): Record<string, unknown>;
|
|
6
|
+
export declare function resolvedRolePlan(role: ResolvedRole, manifestDir?: string): Record<string, unknown>;
|
package/dist/resolved-plan.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { analyzeRolePermissions } from './permissions.js';
|
|
2
|
-
|
|
2
|
+
import { dirname, relative } from 'node:path';
|
|
3
|
+
import { isSensitiveConfigKey } from './sensitive-config.js';
|
|
4
|
+
export const RESOLVED_PLAN_SCHEMA_VERSION = 2;
|
|
3
5
|
const sortedObject = (value) => Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)));
|
|
4
|
-
const redactSensitive = (value, key = '') => {
|
|
5
|
-
if (
|
|
6
|
+
export const redactSensitive = (value, key = '') => {
|
|
7
|
+
if (isSensitiveConfigKey(key))
|
|
6
8
|
return '<redacted>';
|
|
7
9
|
if (Array.isArray(value))
|
|
8
10
|
return value.map(item => redactSensitive(item));
|
|
@@ -14,12 +16,17 @@ const redactSensitive = (value, key = '') => {
|
|
|
14
16
|
};
|
|
15
17
|
/** Stable, secret-safe machine contract consumed by config JSON and spawn dry-run. */
|
|
16
18
|
export function resolvedPlan(cfg) {
|
|
19
|
+
const manifestDir = dirname(cfg.files[0] ?? '.');
|
|
17
20
|
return {
|
|
18
21
|
schemaVersion: RESOLVED_PLAN_SCHEMA_VERSION,
|
|
22
|
+
configMode: cfg.configMode ?? 'split-v2',
|
|
19
23
|
sourceFiles: [...cfg.files],
|
|
24
|
+
sourceDocuments: (cfg.sourceDocuments ?? []).map(document => ({
|
|
25
|
+
...document, path: relative(manifestDir, document.path) || document.path,
|
|
26
|
+
})),
|
|
20
27
|
startStaggerMs: cfg.startStaggerMs,
|
|
21
28
|
diagnostics: cfg.diagnostics.map(diagnostic => ({ ...diagnostic })),
|
|
22
|
-
roles: cfg.roles.map(resolvedRolePlan),
|
|
29
|
+
roles: cfg.roles.map(role => resolvedRolePlan(role, manifestDir)),
|
|
23
30
|
loops: cfg.loops.map(loop => sortedObject({
|
|
24
31
|
name: loop.name, selectors: [...loop.selectors], roles: [...loop.roleNames],
|
|
25
32
|
intervalMs: loop.intervalMs, initialDelayMs: loop.initialDelayMs, jitterMs: loop.jitterMs,
|
|
@@ -36,16 +43,25 @@ export function resolvedPlan(cfg) {
|
|
|
36
43
|
})),
|
|
37
44
|
};
|
|
38
45
|
}
|
|
39
|
-
export function resolvedRolePlan(role) {
|
|
46
|
+
export function resolvedRolePlan(role, manifestDir = dirname(role.sourceFile)) {
|
|
40
47
|
const analysis = analyzeRolePermissions(role);
|
|
41
48
|
return {
|
|
42
49
|
name: role.name,
|
|
43
50
|
sourceFile: role.sourceFile,
|
|
51
|
+
references: Object.values(role.provenance ?? {}).flatMap(item => item.viaReference ? [item.viaReference] : [])
|
|
52
|
+
.filter((item, index, all) => all.findIndex(other => JSON.stringify(other) === JSON.stringify(item)) === index)
|
|
53
|
+
.sort((a, b) => a.kind.localeCompare(b.kind) || a.id.localeCompare(b.id)
|
|
54
|
+
|| a.sourcePointer.localeCompare(b.sourcePointer)),
|
|
55
|
+
provenance: sortedObject(Object.fromEntries(Object.entries(role.provenance ?? {}).map(([field, item]) => [
|
|
56
|
+
field, { ...item, sourceFile: item.sourceKind === 'built-in'
|
|
57
|
+
? item.sourceFile : relative(manifestDir, item.sourceFile) || item.sourceFile },
|
|
58
|
+
]))),
|
|
44
59
|
identity: role.identity,
|
|
45
60
|
harness: role.harness,
|
|
46
61
|
session: role.session,
|
|
47
62
|
sessionOptions: role.session_options ?? null,
|
|
48
63
|
model: role.model ?? null,
|
|
64
|
+
effort: role.effort ?? null,
|
|
49
65
|
modelChain: role.model_chain ?? null,
|
|
50
66
|
cwd: role.cwd ?? null,
|
|
51
67
|
coordinator: role.coordinator ?? null,
|