@ours.network/fleet 0.19.0-nightly.13 → 0.19.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 +66 -11
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +12 -0
- package/dist/application/role-creation-service.js +3 -1
- package/dist/application/types.d.ts +11 -0
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +11 -4
- package/dist/build-info.json +4 -4
- package/dist/cli.js +41 -11
- package/dist/config.d.ts +10 -7
- package/dist/config.js +32 -18
- package/dist/creation.d.ts +1 -1
- package/dist/docs.d.ts +2 -2
- package/dist/docs.js +96 -24
- package/dist/doctor.js +10 -10
- package/dist/duration.js +1 -1
- package/dist/fleet-proxy.d.ts +5 -0
- package/dist/harness/acp-agent.js +11 -6
- package/dist/harness/claude-code.js +199 -8
- package/dist/harness/codex.d.ts +4 -1
- package/dist/harness/codex.js +70 -13
- package/dist/harness/types.d.ts +55 -6
- package/dist/isolation/bubblewrap.d.ts +4 -4
- package/dist/isolation/bubblewrap.js +4 -4
- package/dist/isolation/policy.d.ts +1 -1
- package/dist/isolation/policy.js +2 -2
- package/dist/isolation/registry.d.ts +3 -3
- package/dist/isolation/registry.js +5 -5
- package/dist/isolation/resources.d.ts +1 -1
- package/dist/isolation/resources.js +1 -1
- package/dist/isolation/types.d.ts +3 -3
- package/dist/loops/manager.d.ts +30 -1
- package/dist/loops/manager.js +69 -6
- package/dist/loops/state.d.ts +18 -0
- package/dist/loops/state.js +4 -0
- package/dist/model-env.d.ts +71 -0
- package/dist/model-env.js +106 -0
- package/dist/monitor.d.ts +2 -2
- package/dist/monitor.js +4 -4
- package/dist/ops.d.ts +2 -2
- package/dist/ops.js +9 -9
- package/dist/owner-channel/channel.d.ts +10 -0
- package/dist/owner-channel/channel.js +65 -26
- package/dist/owner-channel/commands.js +198 -87
- package/dist/owner-channel/notices.d.ts +7 -0
- package/dist/owner-channel/notices.js +9 -0
- package/dist/rooms-tasks/cli.js +453 -192
- package/dist/rooms-tasks/markdown.d.ts +49 -0
- package/dist/rooms-tasks/markdown.js +206 -0
- package/dist/rooms-tasks/provision.js +1 -1
- package/dist/runner.d.ts +48 -0
- package/dist/runner.js +252 -100
- package/dist/session/acp.d.ts +106 -2
- package/dist/session/acp.js +217 -14
- package/dist/session/activity.d.ts +31 -0
- package/dist/session/activity.js +48 -0
- package/dist/session/control.d.ts +1 -1
- package/dist/session/conversation-normalizer.d.ts +7 -1
- package/dist/session/conversation-normalizer.js +154 -11
- package/dist/session/conversation-store.js +1 -1
- package/dist/session/conversation-types.d.ts +25 -6
- package/dist/session/types.d.ts +35 -0
- package/dist/spawn.d.ts +1 -1
- package/dist/spawn.js +38 -26
- package/dist/supervisor/launchd.d.ts +2 -2
- package/dist/supervisor/launchd.js +4 -4
- package/dist/supervisor/systemd.js +4 -4
- package/dist/supervisor/types.d.ts +1 -1
- package/dist/watchdog/alerts.d.ts +2 -2
- package/dist/watchdog/alerts.js +2 -2
- package/dist/watchdog/briefing.d.ts +5 -5
- package/dist/watchdog/briefing.js +13 -6
- package/dist/watchdog/config.js +1 -1
- package/dist/watchdog/query.d.ts +2 -2
- package/dist/watchdog/query.js +2 -2
- package/dist/watchdog/report.js +2 -2
- package/dist/watchdog/run.d.ts +2 -2
- package/dist/watchdog/run.js +6 -6
- package/dist/watchdog/scheduler.d.ts +7 -7
- package/dist/watchdog/scheduler.js +10 -10
- package/dist/watchdog/service.d.ts +4 -4
- package/dist/watchdog/service.js +5 -6
- package/dist/watchdog/store.d.ts +4 -4
- package/dist/watchdog/store.js +4 -4
- package/dist/web/runtime.js +1 -1
- package/dist/web/server.js +1 -1
- package/dist/web/topology-promote.js +1 -1
- package/dist/web-app/assets/{TerminalView-BAVk1Bot.js → TerminalView-C_G1ID2P.js} +1 -1
- package/dist/web-app/assets/{index-C3S-xFRU.js → index-BCBK78hw.js} +5 -5
- package/dist/web-app/index.html +1 -1
- package/dist/worklog.d.ts +7 -1
- package/dist/worklog.js +191 -39
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RoomOrchestrationState, TaskState } from './types.js';
|
|
2
|
+
export declare const MARKDOWN_MAX_CODE_POINTS = 3500;
|
|
3
|
+
export declare const MARKDOWN_MAX_BYTES = 12000;
|
|
4
|
+
export interface StatusPresentation {
|
|
5
|
+
icon: string;
|
|
6
|
+
word: string;
|
|
7
|
+
}
|
|
8
|
+
export type MarkdownField = {
|
|
9
|
+
label: string;
|
|
10
|
+
value: unknown;
|
|
11
|
+
kind?: 'prose' | 'code' | 'markdown';
|
|
12
|
+
multiline?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type MarkdownSection = {
|
|
15
|
+
heading?: string;
|
|
16
|
+
items?: unknown[];
|
|
17
|
+
markdownItems?: string[];
|
|
18
|
+
prose?: unknown;
|
|
19
|
+
};
|
|
20
|
+
export declare function withinMarkdownBounds(value: string): boolean;
|
|
21
|
+
/** Escaped single-line prose suitable for a field or list item. */
|
|
22
|
+
export declare function markdownProse(value: unknown): string;
|
|
23
|
+
/** Escaped heading text. Newlines and heading/list syntax cannot escape the heading. */
|
|
24
|
+
export declare function markdownHeading(value: unknown): string;
|
|
25
|
+
/** Escaped multiline prose. Intended line breaks remain line breaks. */
|
|
26
|
+
export declare function markdownMultiline(value: unknown): string;
|
|
27
|
+
/** CommonMark code span with a delimiter longer than every run in the value. */
|
|
28
|
+
export declare function markdownCode(value: unknown): string;
|
|
29
|
+
export declare function taskStatus(value: TaskState | string): string;
|
|
30
|
+
export declare function roomStatus(value: RoomOrchestrationState | string): string;
|
|
31
|
+
export declare function renderMarkdownResult(input: {
|
|
32
|
+
icon: string;
|
|
33
|
+
title: string;
|
|
34
|
+
fields?: MarkdownField[];
|
|
35
|
+
sections?: MarkdownSection[];
|
|
36
|
+
}): string;
|
|
37
|
+
export declare function renderMarkdownList(input: {
|
|
38
|
+
icon: string;
|
|
39
|
+
title: string;
|
|
40
|
+
empty: string;
|
|
41
|
+
records: string[];
|
|
42
|
+
}): string;
|
|
43
|
+
export type FailureKind = 'usage' | 'not_found' | 'conflict' | 'state' | 'pending' | 'unexpected';
|
|
44
|
+
export declare function renderMarkdownFailure(input: {
|
|
45
|
+
kind: FailureKind;
|
|
46
|
+
subject: string;
|
|
47
|
+
detail?: unknown;
|
|
48
|
+
action: string;
|
|
49
|
+
}): string;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
export const MARKDOWN_MAX_CODE_POINTS = 3_500;
|
|
3
|
+
export const MARKDOWN_MAX_BYTES = 12_000;
|
|
4
|
+
const FIELD_MAX_CODE_POINTS = 900;
|
|
5
|
+
const FIELD_MAX_BYTES = 3_000;
|
|
6
|
+
const ID_MAX_CODE_POINTS = 160;
|
|
7
|
+
const ID_MAX_BYTES = 640;
|
|
8
|
+
const TRUNCATED = '_… output truncated._';
|
|
9
|
+
const SPOOFING_CONTROLS = /[\u200b-\u200f\u202a-\u202e\u2060-\u206f\ufeff]/g;
|
|
10
|
+
const SINGLE_LINE_CONTROLS = /[\u0000-\u001f\u007f-\u009f]/g;
|
|
11
|
+
const MULTILINE_CONTROLS = /[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/g;
|
|
12
|
+
const PROSE_PUNCTUATION = /([\\`*_[\]<>])/g;
|
|
13
|
+
const HEADING_PUNCTUATION = /([\\`*_[\]<>#])/g;
|
|
14
|
+
const TASK_STATUS = {
|
|
15
|
+
backlog: { icon: '⏸️', word: 'Backlog' },
|
|
16
|
+
provisioning: { icon: '⏳', word: 'Provisioning' },
|
|
17
|
+
active: { icon: '🟢', word: 'Active' },
|
|
18
|
+
review: { icon: '🟡', word: 'Review' },
|
|
19
|
+
done: { icon: '✅', word: 'Done' },
|
|
20
|
+
cancelled: { icon: '🚫', word: 'Cancelled' },
|
|
21
|
+
failed: { icon: '❌', word: 'Failed' },
|
|
22
|
+
};
|
|
23
|
+
const ROOM_STATUS = {
|
|
24
|
+
provisioning: { icon: '⏳', word: 'Provisioning' },
|
|
25
|
+
active: { icon: '🟢', word: 'Active' },
|
|
26
|
+
closing: { icon: '⏳', word: 'Closing' },
|
|
27
|
+
closed: { icon: '🔒', word: 'Closed' },
|
|
28
|
+
};
|
|
29
|
+
const codePoints = (value) => Array.from(value).length;
|
|
30
|
+
const bytes = (value) => Buffer.byteLength(value, 'utf8');
|
|
31
|
+
export function withinMarkdownBounds(value) {
|
|
32
|
+
return codePoints(value) <= MARKDOWN_MAX_CODE_POINTS && bytes(value) <= MARKDOWN_MAX_BYTES;
|
|
33
|
+
}
|
|
34
|
+
function normalize(value, multiline) {
|
|
35
|
+
let text = String(value ?? '').replace(/\r\n?/g, '\n').replace(SPOOFING_CONTROLS, '�');
|
|
36
|
+
if (multiline)
|
|
37
|
+
text = text.replace(MULTILINE_CONTROLS, '�');
|
|
38
|
+
else
|
|
39
|
+
text = text.replace(SINGLE_LINE_CONTROLS, ' ').replace(/\n+/g, ' ');
|
|
40
|
+
return text;
|
|
41
|
+
}
|
|
42
|
+
function boundPlain(value, maxPoints, maxBytes) {
|
|
43
|
+
if (codePoints(value) <= maxPoints && bytes(value) <= maxBytes)
|
|
44
|
+
return value;
|
|
45
|
+
const suffix = '…';
|
|
46
|
+
let out = '';
|
|
47
|
+
for (const point of value) {
|
|
48
|
+
const next = out + point + suffix;
|
|
49
|
+
if (codePoints(next) > maxPoints || bytes(next) > maxBytes)
|
|
50
|
+
break;
|
|
51
|
+
out += point;
|
|
52
|
+
}
|
|
53
|
+
return out.replace(/\s+$/u, '') + suffix;
|
|
54
|
+
}
|
|
55
|
+
/** Escaped single-line prose suitable for a field or list item. */
|
|
56
|
+
export function markdownProse(value) {
|
|
57
|
+
return boundPlain(normalize(value, false).trim(), FIELD_MAX_CODE_POINTS, FIELD_MAX_BYTES)
|
|
58
|
+
.replace(PROSE_PUNCTUATION, '\\$1');
|
|
59
|
+
}
|
|
60
|
+
/** Escaped heading text. Newlines and heading/list syntax cannot escape the heading. */
|
|
61
|
+
export function markdownHeading(value) {
|
|
62
|
+
return boundPlain(normalize(value, false).trim(), 160, 640)
|
|
63
|
+
.replace(HEADING_PUNCTUATION, '\\$1');
|
|
64
|
+
}
|
|
65
|
+
/** Escaped multiline prose. Intended line breaks remain line breaks. */
|
|
66
|
+
export function markdownMultiline(value) {
|
|
67
|
+
const bounded = boundPlain(normalize(value, true).trim(), FIELD_MAX_CODE_POINTS, FIELD_MAX_BYTES);
|
|
68
|
+
return bounded.split('\n').map(line => {
|
|
69
|
+
const escaped = line.replace(PROSE_PUNCTUATION, '\\$1');
|
|
70
|
+
// A multiline value is commonly nested inside a block quote. Escape every
|
|
71
|
+
// still-active line-leading block marker so user text cannot create nested
|
|
72
|
+
// headings, lists, quotes, thematic breaks, or tilde fences.
|
|
73
|
+
return escaped
|
|
74
|
+
.replace(/^([ \t]*)(#{1,6}|[-+>])(?=[ \t]|$)/u, '$1\\$2')
|
|
75
|
+
.replace(/^([ \t]*)(\d{1,9})([.)])(?=[ \t]|$)/u, '$1$2\\$3')
|
|
76
|
+
.replace(/^([ \t]*)(-{3,})(?=[ \t]*$)/u, '$1\\$2')
|
|
77
|
+
.replace(/^([ \t]*)(~{3,})/u, '$1\\$2');
|
|
78
|
+
}).join('\n');
|
|
79
|
+
}
|
|
80
|
+
/** CommonMark code span with a delimiter longer than every run in the value. */
|
|
81
|
+
export function markdownCode(value) {
|
|
82
|
+
const normalized = normalize(value, false);
|
|
83
|
+
const text = boundPlain(normalized || '—', ID_MAX_CODE_POINTS, ID_MAX_BYTES);
|
|
84
|
+
const longest = Math.max(0, ...[...text.matchAll(/`+/g)].map(match => match[0].length));
|
|
85
|
+
const fence = '`'.repeat(longest + 1);
|
|
86
|
+
const pad = /^`|`$/.test(text) || (/^ | $/.test(text) && !/^ +$/.test(text));
|
|
87
|
+
return `${fence}${pad ? ' ' : ''}${text}${pad ? ' ' : ''}${fence}`;
|
|
88
|
+
}
|
|
89
|
+
export function taskStatus(value) {
|
|
90
|
+
const status = TASK_STATUS[value];
|
|
91
|
+
return status ? `${status.icon} ${status.word}` : `⚪ Unknown (${markdownProse(value)})`;
|
|
92
|
+
}
|
|
93
|
+
export function roomStatus(value) {
|
|
94
|
+
const status = ROOM_STATUS[value];
|
|
95
|
+
return status ? `${status.icon} ${status.word}` : `⚪ Unknown (${markdownProse(value)})`;
|
|
96
|
+
}
|
|
97
|
+
function addBlock(blocks, block) {
|
|
98
|
+
const candidate = [...blocks, block, TRUNCATED].join('\n\n');
|
|
99
|
+
if (!withinMarkdownBounds(candidate))
|
|
100
|
+
return false;
|
|
101
|
+
blocks.push(block);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function finalize(blocks, truncated) {
|
|
105
|
+
if (truncated)
|
|
106
|
+
blocks.push(TRUNCATED);
|
|
107
|
+
const output = blocks.join('\n\n');
|
|
108
|
+
if (!withinMarkdownBounds(output))
|
|
109
|
+
throw new Error('Markdown result exceeded its transport bounds');
|
|
110
|
+
return output;
|
|
111
|
+
}
|
|
112
|
+
export function renderMarkdownResult(input) {
|
|
113
|
+
const blocks = [`## ${input.icon} ${markdownHeading(input.title)}`];
|
|
114
|
+
let truncated = false;
|
|
115
|
+
for (const field of input.fields ?? []) {
|
|
116
|
+
const label = markdownHeading(field.label);
|
|
117
|
+
const value = field.kind === 'code' ? markdownCode(field.value)
|
|
118
|
+
: field.kind === 'markdown' ? String(field.value)
|
|
119
|
+
: field.multiline ? markdownMultiline(field.value) : markdownProse(field.value);
|
|
120
|
+
const rendered = field.multiline
|
|
121
|
+
? `**${label}:**\n\n${value.split('\n').map(line => `> ${line}`).join('\n')}`
|
|
122
|
+
: `- **${label}:** ${value || '—'}`;
|
|
123
|
+
if (!addBlock(blocks, rendered)) {
|
|
124
|
+
truncated = true;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!truncated)
|
|
129
|
+
for (const section of input.sections ?? []) {
|
|
130
|
+
const lines = [];
|
|
131
|
+
if (section.heading)
|
|
132
|
+
lines.push(`### ${markdownHeading(section.heading)}`);
|
|
133
|
+
if (section.prose !== undefined)
|
|
134
|
+
lines.push(markdownMultiline(section.prose));
|
|
135
|
+
const items = [
|
|
136
|
+
...(section.items ?? []).map(markdownProse),
|
|
137
|
+
...(section.markdownItems ?? []),
|
|
138
|
+
];
|
|
139
|
+
let admitted = 0;
|
|
140
|
+
for (const item of items) {
|
|
141
|
+
const next = [...lines, `- ${item}`];
|
|
142
|
+
const remaining = items.length - admitted - 1;
|
|
143
|
+
const omission = remaining
|
|
144
|
+
? `- _${remaining} more ${remaining === 1 ? 'result' : 'results'} omitted\\._` : undefined;
|
|
145
|
+
const candidate = [...blocks, [...next, ...(omission ? [omission] : [])].join('\n'), TRUNCATED]
|
|
146
|
+
.join('\n\n');
|
|
147
|
+
if (!withinMarkdownBounds(candidate))
|
|
148
|
+
break;
|
|
149
|
+
lines.push(`- ${item}`);
|
|
150
|
+
admitted++;
|
|
151
|
+
}
|
|
152
|
+
if (admitted < items.length) {
|
|
153
|
+
const omitted = items.length - admitted;
|
|
154
|
+
lines.push(`- _${omitted} more ${omitted === 1 ? 'result' : 'results'} omitted\\._`);
|
|
155
|
+
}
|
|
156
|
+
if (!addBlock(blocks, lines.join('\n'))) {
|
|
157
|
+
truncated = true;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return finalize(blocks, truncated);
|
|
162
|
+
}
|
|
163
|
+
export function renderMarkdownList(input) {
|
|
164
|
+
const blocks = [`## ${input.icon} ${markdownHeading(input.title)}`];
|
|
165
|
+
if (!input.records.length)
|
|
166
|
+
return finalize([...blocks, markdownProse(input.empty)], false);
|
|
167
|
+
let admitted = 0;
|
|
168
|
+
for (const record of input.records) {
|
|
169
|
+
const remaining = input.records.length - admitted - 1;
|
|
170
|
+
const rendered = `- ${record}`;
|
|
171
|
+
const omission = remaining
|
|
172
|
+
? `- _${remaining} more ${remaining === 1 ? 'result' : 'results'} omitted\\._` : '';
|
|
173
|
+
const candidate = [...blocks, rendered, ...(omission ? [omission] : [])].join('\n\n');
|
|
174
|
+
if (!withinMarkdownBounds(candidate))
|
|
175
|
+
break;
|
|
176
|
+
blocks.push(rendered);
|
|
177
|
+
admitted++;
|
|
178
|
+
}
|
|
179
|
+
if (admitted < input.records.length) {
|
|
180
|
+
const omitted = input.records.length - admitted;
|
|
181
|
+
const notice = `- _${omitted} more ${omitted === 1 ? 'result' : 'results'} omitted\\._`;
|
|
182
|
+
if (!addBlock(blocks, notice))
|
|
183
|
+
return finalize(blocks, true);
|
|
184
|
+
}
|
|
185
|
+
return finalize(blocks, false);
|
|
186
|
+
}
|
|
187
|
+
export function renderMarkdownFailure(input) {
|
|
188
|
+
const titles = {
|
|
189
|
+
usage: 'Invalid command',
|
|
190
|
+
not_found: 'Not found',
|
|
191
|
+
conflict: 'Conflict',
|
|
192
|
+
state: 'Action not allowed',
|
|
193
|
+
pending: 'Action still pending',
|
|
194
|
+
unexpected: 'Command failed',
|
|
195
|
+
};
|
|
196
|
+
return renderMarkdownResult({
|
|
197
|
+
icon: input.kind === 'pending' ? '⏳' : '⚠️',
|
|
198
|
+
title: titles[input.kind],
|
|
199
|
+
fields: [
|
|
200
|
+
{ label: 'Command', value: input.subject, kind: 'code' },
|
|
201
|
+
...(input.detail !== undefined && input.kind !== 'unexpected'
|
|
202
|
+
? [{ label: 'Reason', value: input.detail }] : []),
|
|
203
|
+
],
|
|
204
|
+
sections: [{ heading: 'Next step', items: [input.action] }],
|
|
205
|
+
});
|
|
206
|
+
}
|
|
@@ -245,7 +245,7 @@ export async function provisionMembers(input) {
|
|
|
245
245
|
updateMemberSeats(roomId, seats);
|
|
246
246
|
}
|
|
247
247
|
else {
|
|
248
|
-
//
|
|
248
|
+
// create_members saga phase
|
|
249
249
|
advanceSaga(roomId, 'create_members', 3);
|
|
250
250
|
try {
|
|
251
251
|
for (const planned of plan) {
|
package/dist/runner.d.ts
CHANGED
|
@@ -35,6 +35,15 @@ export interface RunnerDeps {
|
|
|
35
35
|
}
|
|
36
36
|
/** Environment injected only into the managed harness process. */
|
|
37
37
|
export declare function managedFleetProxyEnv(role: ResolvedRole, stateDir: string): Record<string, string>;
|
|
38
|
+
/**
|
|
39
|
+
* The environment a managed harness child actually receives, checked at the one
|
|
40
|
+
* point where it is composed. `role.env` deliberately wins over harness prep,
|
|
41
|
+
* which is exactly how a stale fleet-wide model pin used to outrank the model
|
|
42
|
+
* the role was spawned with — so the model pin is verified here rather than
|
|
43
|
+
* trusted, and a disagreement stops the launch instead of being reported as a
|
|
44
|
+
* success (see src/model-env.ts).
|
|
45
|
+
*/
|
|
46
|
+
export declare function harnessChildEnv(role: ResolvedRole, launchEnv: Record<string, string> | undefined, stateDir: string): Record<string, string>;
|
|
38
47
|
/**
|
|
39
48
|
* Record who owns wake delivery for this run. Returning true means a fleet
|
|
40
49
|
* monitor is taking ownership back from a native harness and must start at the
|
|
@@ -61,6 +70,23 @@ export declare function readExitRecord(path: string): ExitRecord | null;
|
|
|
61
70
|
export declare const RESTART_LEDGER_FILE = ".restart-ledger.json";
|
|
62
71
|
/** Consecutive immediate failures tolerated before the agent is held down. */
|
|
63
72
|
export declare const RESTART_FAIL_THRESHOLD = 5;
|
|
73
|
+
/**
|
|
74
|
+
* How the previous supervisor process ended.
|
|
75
|
+
*
|
|
76
|
+
* `abrupt` is the case the ledger used to miss entirely: an OOM-kill or any
|
|
77
|
+
* other external signal takes the supervisor down before it can write anything,
|
|
78
|
+
* the service manager restarts the unit, and every durable indicator still
|
|
79
|
+
* describes the run that died. A health check reading them reported "no
|
|
80
|
+
* restarts" for a role that had died and come back.
|
|
81
|
+
*/
|
|
82
|
+
export interface TerminationRecord {
|
|
83
|
+
class: 'clean' | 'abrupt' | 'unknown';
|
|
84
|
+
detail: string;
|
|
85
|
+
/** When the SURVIVING process observed it, not when it happened. */
|
|
86
|
+
observedAt: string;
|
|
87
|
+
/** Start time of the run that ended, when it was recorded. */
|
|
88
|
+
runStartedAt?: string;
|
|
89
|
+
}
|
|
64
90
|
export interface RestartLedger {
|
|
65
91
|
version: 1;
|
|
66
92
|
consecutiveImmediateFailures: number;
|
|
@@ -72,7 +98,29 @@ export interface RestartLedger {
|
|
|
72
98
|
updatedAt: string;
|
|
73
99
|
/** When the circuit opened, for the held-down status line. */
|
|
74
100
|
openedAt?: string;
|
|
101
|
+
/** How the previous supervisor process ended, including abnormal exits. */
|
|
102
|
+
lastTermination?: TerminationRecord;
|
|
103
|
+
/** Supervisor processes that died without closing their run marker. */
|
|
104
|
+
abruptTerminations?: number;
|
|
105
|
+
/** Start of the supervisor run that owns this state directory now. */
|
|
106
|
+
supervisorStartedAt?: string;
|
|
75
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Carried across a supervisor process's life so its successor can tell an
|
|
110
|
+
* orderly exit from a kill. Present on disk == "a supervisor believed it was
|
|
111
|
+
* running"; the next start finding one that is not its own is proof the
|
|
112
|
+
* previous process died without getting to write anything.
|
|
113
|
+
*/
|
|
114
|
+
export declare const RUN_MARKER_FILE = ".supervisor-run.json";
|
|
115
|
+
/**
|
|
116
|
+
* Claim this state directory for the current supervisor process and report how
|
|
117
|
+
* the previous one ended. Runs BEFORE the first attempt, which is the whole
|
|
118
|
+
* point: after an abrupt kill nothing else writes until an attempt finishes,
|
|
119
|
+
* and an attempt can take minutes.
|
|
120
|
+
*/
|
|
121
|
+
export declare function claimSupervisorRun(dir: string, startedAt: string, pid?: number): TerminationRecord;
|
|
122
|
+
/** Orderly exit: the successor must not read this run as a kill. */
|
|
123
|
+
export declare function releaseSupervisorRun(dir: string): void;
|
|
76
124
|
/** Bounded exponential backoff for the nth consecutive immediate failure. */
|
|
77
125
|
export declare function backoffFor(consecutiveFailures: number): number;
|
|
78
126
|
/** Read a role's restart ledger; a missing or corrupt one starts clean. */
|