@ours.network/fleet 0.18.0-nightly.6 → 0.18.1
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 +81 -43
- 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.js +9 -2
- package/dist/build-info.json +5 -5
- package/dist/cli.js +37 -7
- package/dist/config.d.ts +6 -3
- package/dist/config.js +28 -14
- package/dist/creation.d.ts +14 -15
- package/dist/creation.js +19 -13
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +92 -33
- package/dist/doctor.d.ts +1 -5
- package/dist/doctor.js +11 -18
- package/dist/fleet-proxy.d.ts +5 -0
- package/dist/harness/acp-agent.js +11 -6
- package/dist/harness/claude-code.js +200 -11
- package/dist/harness/codex.d.ts +4 -1
- package/dist/harness/codex.js +70 -12
- package/dist/harness/types.d.ts +54 -4
- 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.js +1 -1
- package/dist/ops.js +1 -1
- package/dist/owner-channel/attachments.d.ts +2 -25
- package/dist/owner-channel/attachments.js +5 -61
- package/dist/owner-channel/channel.d.ts +30 -29
- package/dist/owner-channel/channel.js +291 -291
- package/dist/owner-channel/mcp.d.ts +24 -0
- package/dist/owner-channel/mcp.js +145 -0
- package/dist/owner-channel/notices.d.ts +7 -0
- package/dist/owner-channel/notices.js +9 -0
- package/dist/runner.d.ts +48 -0
- package/dist/runner.js +237 -85
- package/dist/session/acp.d.ts +104 -0
- package/dist/session/acp.js +213 -10
- package/dist/session/activity.d.ts +31 -0
- package/dist/session/activity.js +48 -0
- package/dist/session/conversation-normalizer.d.ts +6 -0
- package/dist/session/conversation-normalizer.js +153 -10
- package/dist/session/conversation-types.d.ts +23 -4
- package/dist/session/types.d.ts +35 -0
- package/dist/spawn.js +29 -17
- package/dist/supervisor/systemd.js +2 -29
- package/dist/watchdog/briefing.js +7 -0
- 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 -3
- package/dist/owner-channel/message-recovery.d.ts +0 -25
- package/dist/owner-channel/message-recovery.js +0 -114
- package/dist/owner-channel/ours-client.d.ts +0 -148
- package/dist/owner-channel/ours-client.js +0 -231
|
@@ -10,6 +10,12 @@ import { createHash } from 'node:crypto';
|
|
|
10
10
|
*/
|
|
11
11
|
/** Cap for any single normalized text payload (spec §5.3). */
|
|
12
12
|
export const MAX_TEXT_BYTES = 256 * 1024;
|
|
13
|
+
/** Cap for each retained side of an oversized snapshot-style file diff. */
|
|
14
|
+
export const MAX_DIFF_TEXT_BYTES = 64 * 1024;
|
|
15
|
+
/** Cap for attacker-controlled filesystem paths while retaining their useful basename tail. */
|
|
16
|
+
export const MAX_PATH_BYTES = 4 * 1024;
|
|
17
|
+
/** Hard cap for the complete normalized update before the durable event envelope is added. */
|
|
18
|
+
export const MAX_NORMALIZED_UPDATE_BYTES = 320 * 1024;
|
|
13
19
|
/** Cap for one adapter `_meta` namespace value. */
|
|
14
20
|
export const MAX_META_BYTES = 16 * 1024;
|
|
15
21
|
/** Cap for serialized raw tool input/output retained as structured JSON. */
|
|
@@ -27,6 +33,28 @@ function truncateUtf8(text, maxBytes) {
|
|
|
27
33
|
const buffer = Buffer.from(text).subarray(0, maxBytes);
|
|
28
34
|
return buffer.toString('utf8').replace(/�+$/u, '');
|
|
29
35
|
}
|
|
36
|
+
/** Keep a UTF-8-safe suffix. Paths and identifiers have no line semantics. */
|
|
37
|
+
function truncateUtf8Tail(text, maxBytes) {
|
|
38
|
+
const buffer = Buffer.from(text);
|
|
39
|
+
let start = Math.max(0, buffer.length - maxBytes);
|
|
40
|
+
while (start < buffer.length && (buffer[start] & 0xc0) === 0x80)
|
|
41
|
+
start++;
|
|
42
|
+
return { text: buffer.subarray(start).toString('utf8'), omittedPrefixBytes: start };
|
|
43
|
+
}
|
|
44
|
+
function boundedPath(raw) {
|
|
45
|
+
const path = asString(raw) ?? '';
|
|
46
|
+
const pathBytes = Buffer.byteLength(path);
|
|
47
|
+
if (pathBytes <= MAX_PATH_BYTES)
|
|
48
|
+
return { path };
|
|
49
|
+
const retained = truncateUtf8Tail(path, MAX_PATH_BYTES);
|
|
50
|
+
return {
|
|
51
|
+
path: retained.text,
|
|
52
|
+
pathBytes,
|
|
53
|
+
pathTruncated: true,
|
|
54
|
+
pathDigest: digest24(path),
|
|
55
|
+
pathOmittedPrefixBytes: retained.omittedPrefixBytes,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
30
58
|
function cappedText(raw, redact) {
|
|
31
59
|
const text = asString(raw) ?? '';
|
|
32
60
|
const bytes = Buffer.byteLength(text);
|
|
@@ -39,6 +67,95 @@ function cappedText(raw, redact) {
|
|
|
39
67
|
truncated: true, digest: digest24(text),
|
|
40
68
|
};
|
|
41
69
|
}
|
|
70
|
+
/** Keep the newest UTF-8 tail, aligning to a whole line whenever one fits. */
|
|
71
|
+
function cappedTextTail(text, maxBytes) {
|
|
72
|
+
const buffer = Buffer.from(text);
|
|
73
|
+
const bytes = buffer.length;
|
|
74
|
+
if (bytes <= maxBytes)
|
|
75
|
+
return { text, bytes };
|
|
76
|
+
let start = bytes - maxBytes;
|
|
77
|
+
while (start < bytes && (buffer[start] & 0xc0) === 0x80)
|
|
78
|
+
start++;
|
|
79
|
+
let startsMidLine = start > 0 && buffer[start - 1] !== 0x0a;
|
|
80
|
+
if (startsMidLine) {
|
|
81
|
+
const newline = buffer.indexOf(0x0a, start);
|
|
82
|
+
if (newline >= 0 && newline + 1 < bytes) {
|
|
83
|
+
start = newline + 1;
|
|
84
|
+
startsMidLine = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
text: buffer.subarray(start).toString('utf8'), bytes,
|
|
89
|
+
truncated: true, digest: digest24(text), omittedPrefixBytes: start,
|
|
90
|
+
...(startsMidLine ? { startsMidLine: true } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Common unchanged edges in UTF-16 indices, adjusted away from split surrogates. */
|
|
94
|
+
function commonEdges(oldText, newText) {
|
|
95
|
+
const limit = Math.min(oldText.length, newText.length);
|
|
96
|
+
let prefix = 0;
|
|
97
|
+
while (prefix < limit && oldText.charCodeAt(prefix) === newText.charCodeAt(prefix))
|
|
98
|
+
prefix++;
|
|
99
|
+
if (prefix > 0 && prefix < limit
|
|
100
|
+
&& oldText.charCodeAt(prefix) >= 0xdc00 && oldText.charCodeAt(prefix) <= 0xdfff)
|
|
101
|
+
prefix--;
|
|
102
|
+
let oldEnd = oldText.length;
|
|
103
|
+
let newEnd = newText.length;
|
|
104
|
+
while (oldEnd > prefix && newEnd > prefix
|
|
105
|
+
&& oldText.charCodeAt(oldEnd - 1) === newText.charCodeAt(newEnd - 1)) {
|
|
106
|
+
oldEnd--;
|
|
107
|
+
newEnd--;
|
|
108
|
+
}
|
|
109
|
+
// A suffix must never begin at the low half of a surrogate pair.
|
|
110
|
+
if (oldEnd < oldText.length && oldText.charCodeAt(oldEnd) >= 0xdc00
|
|
111
|
+
&& oldText.charCodeAt(oldEnd) <= 0xdfff) {
|
|
112
|
+
oldEnd++;
|
|
113
|
+
newEnd++;
|
|
114
|
+
}
|
|
115
|
+
return { prefix, suffix: oldText.length - oldEnd };
|
|
116
|
+
}
|
|
117
|
+
function normalizedDiff(item, redact) {
|
|
118
|
+
const path = boundedPath(item.path);
|
|
119
|
+
const oldText = asString(item.oldText);
|
|
120
|
+
const newText = asString(item.newText) ?? '';
|
|
121
|
+
// Preserve the established small-diff contract exactly. Redacted turns also
|
|
122
|
+
// retain their established placeholder shape and never derive private text.
|
|
123
|
+
if (redact !== undefined || oldText === undefined
|
|
124
|
+
|| (Buffer.byteLength(oldText) <= MAX_TEXT_BYTES
|
|
125
|
+
&& Buffer.byteLength(newText) <= MAX_TEXT_BYTES)) {
|
|
126
|
+
return {
|
|
127
|
+
type: 'diff', ...path,
|
|
128
|
+
newText: cappedText(newText, redact),
|
|
129
|
+
...(oldText !== undefined ? { oldText: cappedText(oldText, redact) } : {}),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// ACP adapters may describe an append by sending two complete file snapshots.
|
|
133
|
+
// Persist only the changed region: otherwise a multi-megabyte historical file
|
|
134
|
+
// contributes its prefix twice while the current append disappears past the cap.
|
|
135
|
+
const { prefix, suffix } = commonEdges(oldText, newText);
|
|
136
|
+
const oldEnd = oldText.length - suffix;
|
|
137
|
+
const newEnd = newText.length - suffix;
|
|
138
|
+
const oldDelta = oldText.slice(prefix, oldEnd);
|
|
139
|
+
const newDelta = newText.slice(prefix, newEnd);
|
|
140
|
+
const beforeBytes = Buffer.byteLength(oldText);
|
|
141
|
+
const afterBytes = Buffer.byteLength(newText);
|
|
142
|
+
const commonPrefixBytes = Buffer.byteLength(oldText.slice(0, prefix));
|
|
143
|
+
const commonSuffixBytes = Buffer.byteLength(oldText.slice(oldEnd));
|
|
144
|
+
const operation = oldDelta.length === 0 && newDelta.length === 0
|
|
145
|
+
? 'noop'
|
|
146
|
+
: oldDelta.length === 0 && prefix === oldText.length
|
|
147
|
+
? 'append'
|
|
148
|
+
: newDelta.length === 0
|
|
149
|
+
? 'delete'
|
|
150
|
+
: prefix === 0 && suffix === 0 ? 'replace' : 'edit';
|
|
151
|
+
return {
|
|
152
|
+
type: 'diff', ...path, operation, beforeBytes, afterBytes,
|
|
153
|
+
commonPrefixBytes, commonSuffixBytes, bounded: true,
|
|
154
|
+
newText: cappedTextTail(newDelta, MAX_DIFF_TEXT_BYTES),
|
|
155
|
+
...(oldDelta.length > 0
|
|
156
|
+
? { oldText: cappedTextTail(oldDelta, MAX_DIFF_TEXT_BYTES) } : {}),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
42
159
|
function normalizedText(raw, redact) {
|
|
43
160
|
const text = asString(raw) ?? '';
|
|
44
161
|
const bytes = Buffer.byteLength(text);
|
|
@@ -189,12 +306,7 @@ function normalizeToolContent(raw, redact) {
|
|
|
189
306
|
return raw.filter(isRecord).map((item) => {
|
|
190
307
|
switch (item.type) {
|
|
191
308
|
case 'diff':
|
|
192
|
-
return
|
|
193
|
-
type: 'diff',
|
|
194
|
-
path: asString(item.path) ?? '',
|
|
195
|
-
newText: cappedText(item.newText, redact),
|
|
196
|
-
...(item.oldText != null ? { oldText: cappedText(item.oldText, redact) } : {}),
|
|
197
|
-
};
|
|
309
|
+
return normalizedDiff(item, redact);
|
|
198
310
|
case 'terminal':
|
|
199
311
|
return { type: 'terminal', terminalId: asString(item.terminalId) ?? '' };
|
|
200
312
|
case 'content':
|
|
@@ -220,7 +332,7 @@ function toolUpsert(update, snapshot, options) {
|
|
|
220
332
|
payload.content = content;
|
|
221
333
|
if (Array.isArray(update.locations)) {
|
|
222
334
|
payload.locations = update.locations.filter(isRecord).map(location => ({
|
|
223
|
-
|
|
335
|
+
...boundedPath(location.path),
|
|
224
336
|
...(asFiniteNumber(location.line) !== undefined ? { line: asFiniteNumber(location.line) } : {}),
|
|
225
337
|
}));
|
|
226
338
|
}
|
|
@@ -240,18 +352,49 @@ function unsupported(update) {
|
|
|
240
352
|
}
|
|
241
353
|
const kind = isRecord(update) ? asString(update.sessionUpdate) : undefined;
|
|
242
354
|
return {
|
|
243
|
-
sessionUpdate: kind ?? 'unknown',
|
|
355
|
+
sessionUpdate: truncateUtf8(kind ?? 'unknown', 256),
|
|
244
356
|
bytes: Buffer.byteLength(serialized),
|
|
245
357
|
preview: serialized.slice(0, MAX_UNSUPPORTED_PREVIEW_CHARS),
|
|
358
|
+
...(Buffer.byteLength(serialized) > Buffer.byteLength(serialized.slice(0, MAX_UNSUPPORTED_PREVIEW_CHARS))
|
|
359
|
+
? { digest: digest24(serialized) } : {}),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function capNormalizedUpdate(result, sessionUpdate) {
|
|
363
|
+
let serialized;
|
|
364
|
+
try {
|
|
365
|
+
serialized = JSON.stringify(result);
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
return {
|
|
369
|
+
kind: 'unsupported',
|
|
370
|
+
payload: {
|
|
371
|
+
sessionUpdate: truncateUtf8(sessionUpdate, 256),
|
|
372
|
+
bytes: 0,
|
|
373
|
+
preview: '[normalized update was not serializable]',
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
const bytes = Buffer.byteLength(serialized);
|
|
378
|
+
if (bytes <= MAX_NORMALIZED_UPDATE_BYTES)
|
|
379
|
+
return result;
|
|
380
|
+
return {
|
|
381
|
+
kind: 'unsupported',
|
|
382
|
+
payload: {
|
|
383
|
+
sessionUpdate: truncateUtf8(sessionUpdate, 256),
|
|
384
|
+
bytes,
|
|
385
|
+
digest: digest24(serialized),
|
|
386
|
+
preview: `[normalized update exceeded ${MAX_NORMALIZED_UPDATE_BYTES}-byte durable-event cap]`,
|
|
387
|
+
},
|
|
246
388
|
};
|
|
247
389
|
}
|
|
248
390
|
export function normalizeSessionUpdate(update, options = {}) {
|
|
249
391
|
const redact = options.redactText;
|
|
250
392
|
const raw = update;
|
|
251
393
|
if (!isRecord(raw) || typeof raw.sessionUpdate !== 'string')
|
|
252
|
-
return { kind: 'unsupported', payload: unsupported(raw) };
|
|
394
|
+
return capNormalizedUpdate({ kind: 'unsupported', payload: unsupported(raw) }, 'unknown');
|
|
395
|
+
const sessionUpdate = raw.sessionUpdate;
|
|
253
396
|
const adapterMeta = quarantineMeta(raw._meta);
|
|
254
|
-
const withMeta = (result) => adapterMeta ? { ...result, adapterMeta } : result;
|
|
397
|
+
const withMeta = (result) => capNormalizedUpdate(adapterMeta ? { ...result, adapterMeta } : result, sessionUpdate);
|
|
255
398
|
switch (raw.sessionUpdate) {
|
|
256
399
|
case 'user_message_chunk':
|
|
257
400
|
case 'agent_message_chunk': {
|
|
@@ -48,15 +48,33 @@ export interface CappedText {
|
|
|
48
48
|
bytes: number;
|
|
49
49
|
truncated?: true;
|
|
50
50
|
digest?: string;
|
|
51
|
+
/** Bytes omitted from the front when the retained fragment is a tail. */
|
|
52
|
+
omittedPrefixBytes?: number;
|
|
53
|
+
/** The retained tail starts inside one logical line because that line alone exceeded the cap. */
|
|
54
|
+
startsMidLine?: true;
|
|
55
|
+
}
|
|
56
|
+
/** A path kept as a UTF-8-safe tail, with additive provenance only when capped. */
|
|
57
|
+
export interface BoundedPath {
|
|
58
|
+
path: string;
|
|
59
|
+
pathBytes?: number;
|
|
60
|
+
pathTruncated?: true;
|
|
61
|
+
pathDigest?: string;
|
|
62
|
+
pathOmittedPrefixBytes?: number;
|
|
51
63
|
}
|
|
52
64
|
export type NormalizedToolContent = {
|
|
53
65
|
type: 'content';
|
|
54
66
|
content: NormalizedContentBlock;
|
|
55
|
-
} | {
|
|
67
|
+
} | BoundedPath & {
|
|
56
68
|
type: 'diff';
|
|
57
|
-
path: string;
|
|
58
69
|
newText: CappedText;
|
|
59
70
|
oldText?: CappedText;
|
|
71
|
+
/** Additive provenance for oversized snapshot diffs reduced to their changed region. */
|
|
72
|
+
operation?: 'append' | 'edit' | 'delete' | 'noop' | 'replace';
|
|
73
|
+
beforeBytes?: number;
|
|
74
|
+
afterBytes?: number;
|
|
75
|
+
commonPrefixBytes?: number;
|
|
76
|
+
commonSuffixBytes?: number;
|
|
77
|
+
bounded?: true;
|
|
60
78
|
}
|
|
61
79
|
/** A tool-owned display terminal reference — never a PTY attachment. */
|
|
62
80
|
| {
|
|
@@ -105,8 +123,7 @@ export interface ToolUpsertPayload {
|
|
|
105
123
|
kind?: string;
|
|
106
124
|
status?: string;
|
|
107
125
|
content?: NormalizedToolContent[];
|
|
108
|
-
locations?: Array<{
|
|
109
|
-
path: string;
|
|
126
|
+
locations?: Array<BoundedPath & {
|
|
110
127
|
line?: number;
|
|
111
128
|
}>;
|
|
112
129
|
rawInput?: BoundedJson;
|
|
@@ -140,6 +157,8 @@ export interface UnsupportedPayload {
|
|
|
140
157
|
/** The wire discriminant (or 'unknown' when even that was absent). */
|
|
141
158
|
sessionUpdate: string;
|
|
142
159
|
bytes: number;
|
|
160
|
+
/** Digest of the omitted original/normalized representation when it was bounded. */
|
|
161
|
+
digest?: string;
|
|
143
162
|
/** Sanitized JSON preview, capped; enough to diagnose, never to exhaust. */
|
|
144
163
|
preview?: string;
|
|
145
164
|
}
|
package/dist/session/types.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { SessionBackendId } from '../config.js';
|
|
2
2
|
import type { ConversationEventV1, ConversationSnapshot, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* TURN OCCUPANCY, and nothing else: `idle` means no fleet-tracked turn is in
|
|
5
|
+
* flight, which is exactly the question `arbiter.tryScheduled` asks before it
|
|
6
|
+
* admits a prompt. It is NOT a claim that the agent is doing nothing — a wake
|
|
7
|
+
* delivered through the `_session/steering` extension answers `startedNewTurn`
|
|
8
|
+
* and runs a whole turn that fleet never gets a `session/prompt` response for
|
|
9
|
+
* (ACP has no turn-end session update), so `readiness` stays `idle` for its
|
|
10
|
+
* entire duration. Anything reporting activity or liveness to a human must
|
|
11
|
+
* corroborate with `SessionSnapshot.activity` instead of reading `idle` here as
|
|
12
|
+
* "not working".
|
|
13
|
+
*/
|
|
3
14
|
export type SessionReadiness = 'starting' | 'idle' | 'running' | 'awaiting_permission' | 'failed';
|
|
4
15
|
export type TurnOutcome = 'completed' | 'refused' | 'cancelled' | 'failed' | 'inconclusive';
|
|
5
16
|
export type TurnCancellationSource = 'owner' | 'local-console' | 'fleet-monitor' | 'scheduled-loop' | 'shutdown';
|
|
@@ -99,6 +110,15 @@ export declare function interruptOutcome(result: InterruptResult): InterruptOutc
|
|
|
99
110
|
* stop here: the session has the prompt, and waiting for the turn to finish is
|
|
100
111
|
* a different question with a different, much longer, timescale.
|
|
101
112
|
*/
|
|
113
|
+
/**
|
|
114
|
+
* What actually happened to an admitted prompt, so a caller reporting to a
|
|
115
|
+
* human can be accurate instead of repeating what it asked for.
|
|
116
|
+
*
|
|
117
|
+
* `interrupted` is only ever returned when a turn was really cancelled for this
|
|
118
|
+
* prompt. `deferred` says the session is busy with work this prompt could not
|
|
119
|
+
* safely pre-empt — the prompt is admitted and will run, just not yet.
|
|
120
|
+
*/
|
|
121
|
+
export type PromptDelivery = 'started' | 'queued' | 'interrupted' | 'deferred';
|
|
102
122
|
export interface QueuedPrompt {
|
|
103
123
|
promptId: string;
|
|
104
124
|
/** Turns already queued ahead of this one. 0 means it starts immediately. */
|
|
@@ -106,6 +126,8 @@ export interface QueuedPrompt {
|
|
|
106
126
|
origin?: PromptOrigin;
|
|
107
127
|
/** The turn's terminal result. Never rejects. */
|
|
108
128
|
completion: Promise<TurnResult>;
|
|
129
|
+
/** Observed admission outcome. Absent on backends that do not report it. */
|
|
130
|
+
delivery?: PromptDelivery;
|
|
109
131
|
}
|
|
110
132
|
/**
|
|
111
133
|
* How a session's process ended.
|
|
@@ -170,6 +192,19 @@ export interface SessionSnapshot {
|
|
|
170
192
|
/** Exact harness-native approval/permission mode used by this runner. */
|
|
171
193
|
nativeMode: string;
|
|
172
194
|
};
|
|
195
|
+
/**
|
|
196
|
+
* Observed agent activity, independent of turn occupancy: the evidence a
|
|
197
|
+
* human-facing surface needs before calling a role idle. Absent on backends
|
|
198
|
+
* that cannot observe the agent at all (tmux), which is itself honest — no
|
|
199
|
+
* evidence is not evidence of inactivity.
|
|
200
|
+
*/
|
|
201
|
+
activity?: SessionActivity;
|
|
202
|
+
}
|
|
203
|
+
export interface SessionActivity {
|
|
204
|
+
/** ACP tool calls currently reserved (lifecycle open or permission pending). */
|
|
205
|
+
activeToolCalls: number;
|
|
206
|
+
/** When the agent last sent ANY session update, replay excluded. */
|
|
207
|
+
lastUpdateAt?: string;
|
|
173
208
|
}
|
|
174
209
|
export type SessionEventKind = 'state' | 'agent_text' | 'thought' | 'tool_call' | 'tool_update' | 'permission' | 'monitor_delivery' | 'turn_stop' | 'error';
|
|
175
210
|
/** What a settled permission request resolved to. */
|
package/dist/spawn.js
CHANGED
|
@@ -5,6 +5,7 @@ import { parse, stringify } from 'yaml';
|
|
|
5
5
|
import { agentDir, fleetDDir } from './paths.js';
|
|
6
6
|
import { validateIsolationConfig } from './isolation/policy.js';
|
|
7
7
|
import { loadConfig, resolveAuthProxy, resolveModelChain, resolveMonitorConfig, resolveOwnerChannelConfig, resolvePermissions, resolveRoleModel, resolveWorklogPolicy, validateMonitorConfig, } from './config.js';
|
|
8
|
+
import { resolveRoleModelEnv } from './model-env.js';
|
|
8
9
|
import { applyRole, up } from './ops.js';
|
|
9
10
|
import { START_STAGGER_FILE } from './runner.js';
|
|
10
11
|
import { buildProvenance, daemonIdentityProvisioner, ensureIdentity, provenanceOf, withCreationTransaction, writeProvenance, writeRoleFile, } from './creation.js';
|
|
@@ -191,7 +192,17 @@ export function spawnDryRun(o) {
|
|
|
191
192
|
const harness = raw.harness ?? cfg.defaults.harness ?? 'claude-code';
|
|
192
193
|
const defaultHarness = cfg.defaults.harness ?? 'claude-code';
|
|
193
194
|
const inheritsModelDefaults = harness === defaultHarness && raw.model !== null;
|
|
194
|
-
const
|
|
195
|
+
const authProxy = resolveAuthProxy(cfg.defaults.auth_proxy, raw.auth_proxy);
|
|
196
|
+
// One resolution for the environment and the model it pins (src/model-env.ts).
|
|
197
|
+
const modelEnv = resolveRoleModelEnv({
|
|
198
|
+
harness,
|
|
199
|
+
model: resolveRoleModel(raw.model, raw.harness, cfg.defaults),
|
|
200
|
+
modelWasExplicit: raw.model !== undefined,
|
|
201
|
+
defaultsEnv: (cfg.defaults.env ?? {}),
|
|
202
|
+
roleEnv: raw.env,
|
|
203
|
+
...(authProxy ? { authProxyBaseUrl: authProxy.base_url } : {}),
|
|
204
|
+
});
|
|
205
|
+
const model = modelEnv.model;
|
|
195
206
|
const session = raw.session ?? cfg.defaults.session ?? 'tmux';
|
|
196
207
|
const resolvedRole = {
|
|
197
208
|
...raw,
|
|
@@ -212,19 +223,13 @@ export function spawnDryRun(o) {
|
|
|
212
223
|
monitor: resolveMonitorConfig(cfg.defaults.monitor, raw.monitor),
|
|
213
224
|
owner_channel: resolveOwnerChannelConfig(cfg.defaults.owner_channel, raw.owner_channel, session),
|
|
214
225
|
worklog: resolveWorklogPolicy(cfg.defaults.worklog, raw.worklog),
|
|
215
|
-
auth_proxy:
|
|
216
|
-
};
|
|
217
|
-
resolvedRole.env = {
|
|
218
|
-
...(cfg.defaults.env ?? {}),
|
|
219
|
-
...(raw.env ?? {}),
|
|
220
|
-
...(resolvedRole.auth_proxy
|
|
221
|
-
? { ANTHROPIC_BASE_URL: resolvedRole.auth_proxy.base_url }
|
|
222
|
-
: {}),
|
|
226
|
+
auth_proxy: authProxy,
|
|
223
227
|
};
|
|
228
|
+
resolvedRole.env = modelEnv.env;
|
|
224
229
|
const adapter = getAdapter(resolvedRole.harness);
|
|
225
230
|
if (resolvedRole.auth_proxy && resolvedRole.harness !== 'claude-code')
|
|
226
231
|
throw new Error('auth_proxy is supported only by claude-code');
|
|
227
|
-
const optionProblems = adapter.validateOptions(resolvedRole.harness_options);
|
|
232
|
+
const optionProblems = adapter.validateOptions(resolvedRole.harness_options, resolvedRole);
|
|
228
233
|
if (optionProblems.length)
|
|
229
234
|
throw new Error(optionProblems.map(problem => `${problem.path}: ${problem.message}`).join('; '));
|
|
230
235
|
return {
|
|
@@ -403,7 +408,18 @@ async function spawnTempInner(o, binPath, launch, tx, guarantee, onStage) {
|
|
|
403
408
|
};
|
|
404
409
|
const harness = o.harness ?? defaultHarness ?? 'claude-code';
|
|
405
410
|
const inheritsModelDefaults = harness === (defaultHarness ?? 'claude-code') && o.model !== null;
|
|
406
|
-
const
|
|
411
|
+
const tempAuthProxy = resolveAuthProxy(cfg.defaults.auth_proxy, fromOpts.auth_proxy);
|
|
412
|
+
// An explicitly requested --model must reach the child, not just the banner
|
|
413
|
+
// (src/model-env.ts).
|
|
414
|
+
const modelEnv = resolveRoleModelEnv({
|
|
415
|
+
harness,
|
|
416
|
+
model: resolveRoleModel(o.model, o.harness, cfg.defaults),
|
|
417
|
+
modelWasExplicit: o.model !== undefined,
|
|
418
|
+
defaultsEnv: (cfg.defaults.env ?? {}),
|
|
419
|
+
roleEnv: fromOpts.env,
|
|
420
|
+
...(tempAuthProxy ? { authProxyBaseUrl: tempAuthProxy.base_url } : {}),
|
|
421
|
+
});
|
|
422
|
+
const model = modelEnv.model;
|
|
407
423
|
const session = o.session ?? cfg.defaults.session ?? 'tmux';
|
|
408
424
|
const role = {
|
|
409
425
|
...fromOpts, // includes `isolation` when --isolation-file was given
|
|
@@ -422,14 +438,10 @@ async function spawnTempInner(o, binPath, launch, tx, guarantee, onStage) {
|
|
|
422
438
|
monitor: resolveMonitorConfig(cfg.defaults.monitor, fromOpts.monitor),
|
|
423
439
|
owner_channel: resolveOwnerChannelConfig(cfg.defaults.owner_channel, fromOpts.owner_channel, session),
|
|
424
440
|
worklog: resolveWorklogPolicy(cfg.defaults.worklog, fromOpts.worklog),
|
|
425
|
-
auth_proxy:
|
|
441
|
+
auth_proxy: tempAuthProxy,
|
|
426
442
|
sourceFile: '(temp)',
|
|
427
443
|
};
|
|
428
|
-
role.env =
|
|
429
|
-
...(cfg.defaults.env ?? {}),
|
|
430
|
-
...(fromOpts.env ?? {}),
|
|
431
|
-
...(role.auth_proxy ? { ANTHROPIC_BASE_URL: role.auth_proxy.base_url } : {}),
|
|
432
|
-
};
|
|
444
|
+
role.env = modelEnv.env;
|
|
433
445
|
if (role.auth_proxy && role.harness !== 'claude-code')
|
|
434
446
|
throw new Error('auth_proxy is supported only by claude-code');
|
|
435
447
|
onStage?.('writing_role');
|
|
@@ -64,38 +64,11 @@ export function makeSystemdBackend(exec = realExec) {
|
|
|
64
64
|
const unitDir = join(home(), '.config', 'systemd', 'user');
|
|
65
65
|
// Lingering user units often start before a login shell imports its PATH.
|
|
66
66
|
// Pin the Node runtime and persist the install-time PATH so the runner and
|
|
67
|
-
//
|
|
67
|
+
// children such as `ours-mcp proxy` resolve the same tools after reboot.
|
|
68
68
|
const servicePath = [...new Set([
|
|
69
69
|
dirname(process.execPath),
|
|
70
70
|
...(process.env.PATH ?? '').split(delimiter),
|
|
71
71
|
].filter(Boolean))].join(delimiter);
|
|
72
|
-
// Same reason as PATH, for the other thing a lingering unit cannot inherit:
|
|
73
|
-
// WHICH ours daemon this fleet was set up against.
|
|
74
|
-
//
|
|
75
|
-
// ours-fleet resolves its daemon from OURS_CONFIG / OURS_PORT / OURS_STATE_DIR
|
|
76
|
-
// and otherwise falls back to ~/.ours and port 3050 (src/monitor.ts). A host
|
|
77
|
-
// set up against a non-default daemon — the installer's multi-daemon profiles
|
|
78
|
-
// do exactly this — passes that selection to `ours-fleet init` in the
|
|
79
|
-
// environment, and it died there: nothing persisted it, so every runner
|
|
80
|
-
// systemd started at boot resolved the default daemon again, and on a host
|
|
81
|
-
// where only the non-default daemon exists that is a daemon that is not there.
|
|
82
|
-
//
|
|
83
|
-
// ONLY OURS_CONFIG is baked, deliberately. It names which daemon, and leaves
|
|
84
|
-
// that daemon's own config file authoritative for port and state directory, so
|
|
85
|
-
// a later edit to it still wins. Baking OURS_PORT/OURS_STATE_DIR would freeze
|
|
86
|
-
// those into a unit file that outranks the config for ever after — the failure
|
|
87
|
-
// mode @ours.network/cli avoids for the same reason (packages/cli/src/
|
|
88
|
-
// service.ts: "The port is deliberately NOT baked").
|
|
89
|
-
//
|
|
90
|
-
// Absent from init's environment ⇒ no line, and the unit is byte-for-byte what
|
|
91
|
-
// it has always been. This teaches fleet nothing about installer profiles; it
|
|
92
|
-
// persists the selection fleet was initialised with.
|
|
93
|
-
const unitEnv = ['PATH=' + servicePath];
|
|
94
|
-
if (process.env.OURS_CONFIG)
|
|
95
|
-
unitEnv.push('OURS_CONFIG=' + process.env.OURS_CONFIG);
|
|
96
|
-
const environmentLines = unitEnv
|
|
97
|
-
.map(value => `Environment="${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/%/g, '%%')}"`)
|
|
98
|
-
.join('\n');
|
|
99
72
|
mkdirSync(unitDir, { recursive: true });
|
|
100
73
|
writeFileSync(join(unitDir, UNIT_TEMPLATE), `[Unit]
|
|
101
74
|
Description=ours-fleet agent %i
|
|
@@ -103,7 +76,7 @@ After=default.target
|
|
|
103
76
|
|
|
104
77
|
[Service]
|
|
105
78
|
Type=simple
|
|
106
|
-
|
|
79
|
+
Environment="PATH=${servicePath.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/%/g, '%%')}"
|
|
107
80
|
ExecStart=${unitArg(process.execPath)} ${unitArg(binPath)} _run %i
|
|
108
81
|
# The RUNNER owns the child-session restart loop, with a counted, backed-off
|
|
109
82
|
# circuit breaker (3.2). systemd must only recover the runner PROCESS crashing —
|
|
@@ -80,6 +80,13 @@ export function generateWatchdogBriefing(opts) {
|
|
|
80
80
|
L.push('- `healthy` — alive, on-briefing, recent progress.');
|
|
81
81
|
L.push('- `idle` — alive, nothing assigned or nothing to do. Not an anomaly.');
|
|
82
82
|
L.push('- `stale` = no worklog append and no console progress for ≥ 3 intervals.');
|
|
83
|
+
L.push('');
|
|
84
|
+
L.push('`session.readiness` from `ours-fleet status` is TURN OCCUPANCY, not activity: a mail');
|
|
85
|
+
L.push('wake delivered by ACP steering runs an entire turn while readiness stays `idle`. Never');
|
|
86
|
+
L.push('report `idle` or `stale` from `readiness=idle` alone — corroborate with the');
|
|
87
|
+
L.push('`activity:` line of the same `status` output (`active` means the agent is working),');
|
|
88
|
+
L.push('the worklog, or `ours-fleet peek`. `activity: unobservable` is missing evidence, not');
|
|
89
|
+
L.push('an idle agent.');
|
|
83
90
|
L.push('- `blocked` = waiting on a permission/prompt/modal longer than one interval.');
|
|
84
91
|
L.push('- `off_briefing` — activity contradicts the briefing (wrong repo, out-of-scope work,');
|
|
85
92
|
L.push(' ignored routine).');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as le,a as Ee,j as re}from"./index-
|
|
1
|
+
import{r as le,a as Ee,j as re}from"./index-BCBK78hw.js";var ge={exports:{}},Se;function ke(){return Se||(Se=1,(function(se,ne){(function(Q,X){se.exports=X()})(globalThis,(()=>(()=>{var Q={4567:function(B,r,o){var l=this&&this.__decorate||function(e,i,a,v){var f,g=arguments.length,c=g<3?i:v===null?v=Object.getOwnPropertyDescriptor(i,a):v;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")c=Reflect.decorate(e,i,a,v);else for(var m=e.length-1;m>=0;m--)(f=e[m])&&(c=(g<3?f(c):g>3?f(i,a,c):f(i,a))||c);return g>3&&c&&Object.defineProperty(i,a,c),c},_=this&&this.__param||function(e,i){return function(a,v){i(a,v,e)}};Object.defineProperty(r,"__esModule",{value:!0}),r.AccessibilityManager=void 0;const n=o(9042),d=o(9924),u=o(844),p=o(4725),h=o(2585),t=o(3656);let s=r.AccessibilityManager=class extends u.Disposable{constructor(e,i,a,v){super(),this._terminal=e,this._coreBrowserService=a,this._renderService=v,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let f=0;f<this._terminal.rows;f++)this._rowElements[f]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[f]);if(this._topBoundaryFocusListener=f=>this._handleBoundaryFocus(f,0),this._bottomBoundaryFocusListener=f=>this._handleBoundaryFocus(f,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new d.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((f=>this._handleResize(f.rows)))),this.register(this._terminal.onRender((f=>this._refreshRows(f.start,f.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((f=>this._handleChar(f)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(`
|
|
2
2
|
`)))),this.register(this._terminal.onA11yTab((f=>this._handleTab(f)))),this.register(this._terminal.onKey((f=>this._handleKey(f.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,t.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,u.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let i=0;i<e;i++)this._handleChar(" ")}_handleChar(e){this._liveRegionLineCount<21&&(this._charsToConsume.length>0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,e===`
|
|
3
3
|
`&&(this._liveRegionLineCount++,this._liveRegionLineCount===21&&(this._liveRegion.textContent+=n.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),new RegExp("\\p{Control}","u").test(e)||this._charsToConsume.push(e)}_refreshRows(e,i){this._liveRegionDebouncer.refresh(e,i,this._terminal.rows)}_renderRows(e,i){const a=this._terminal.buffer,v=a.lines.length.toString();for(let f=e;f<=i;f++){const g=a.lines.get(a.ydisp+f),c=[],m=g?.translateToString(!0,void 0,void 0,c)||"",E=(a.ydisp+f+1).toString(),k=this._rowElements[f];k&&(m.length===0?(k.innerText=" ",this._rowColumns.set(k,[0,1])):(k.textContent=m,this._rowColumns.set(k,c)),k.setAttribute("aria-posinset",E),k.setAttribute("aria-setsize",v))}this._announceCharacters()}_announceCharacters(){this._charsToAnnounce.length!==0&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,i){const a=e.target,v=this._rowElements[i===0?1:this._rowElements.length-2];if(a.getAttribute("aria-posinset")===(i===0?"1":`${this._terminal.buffer.lines.length}`)||e.relatedTarget!==v)return;let f,g;if(i===0?(f=a,g=this._rowElements.pop(),this._rowContainer.removeChild(g)):(f=this._rowElements.shift(),g=a,this._rowContainer.removeChild(f)),f.removeEventListener("focus",this._topBoundaryFocusListener),g.removeEventListener("focus",this._bottomBoundaryFocusListener),i===0){const c=this._createAccessibilityTreeNode();this._rowElements.unshift(c),this._rowContainer.insertAdjacentElement("afterbegin",c)}else{const c=this._createAccessibilityTreeNode();this._rowElements.push(c),this._rowContainer.appendChild(c)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(i===0?-1:1),this._rowElements[i===0?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleSelectionChange(){if(this._rowElements.length===0)return;const e=document.getSelection();if(!e)return;if(e.isCollapsed)return void(this._rowContainer.contains(e.anchorNode)&&this._terminal.clearSelection());if(!e.anchorNode||!e.focusNode)return void console.error("anchorNode and/or focusNode are null");let i={node:e.anchorNode,offset:e.anchorOffset},a={node:e.focusNode,offset:e.focusOffset};if((i.node.compareDocumentPosition(a.node)&Node.DOCUMENT_POSITION_PRECEDING||i.node===a.node&&i.offset>a.offset)&&([i,a]=[a,i]),i.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(i={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(i.node))return;const v=this._rowElements.slice(-1)[0];if(a.node.compareDocumentPosition(v)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(a={node:v,offset:v.textContent?.length??0}),!this._rowContainer.contains(a.node))return;const f=({node:m,offset:E})=>{const k=m instanceof Text?m.parentNode:m;let D=parseInt(k?.getAttribute("aria-posinset"),10)-1;if(isNaN(D))return console.warn("row is invalid. Race condition?"),null;const b=this._rowColumns.get(k);if(!b)return console.warn("columns is null. Race condition?"),null;let x=E<b.length?b[E]:b.slice(-1)[0]+1;return x>=this._terminal.cols&&(++D,x=0),{row:D,column:x}},g=f(i),c=f(a);if(g&&c){if(g.row>c.row||g.row===c.row&&g.column>=c.column)throw new Error("invalid range");this._terminal.select(g.column,g.row,(c.row-g.row)*this._terminal.cols-g.column+c.column)}}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let i=this._rowContainer.children.length;i<this._terminal.rows;i++)this._rowElements[i]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[i]);for(;this._rowElements.length>e;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const e=this._coreBrowserService.mainDocument.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e<this._terminal.rows;e++)this._refreshRowDimensions(this._rowElements[e])}}_refreshRowDimensions(e){e.style.height=`${this._renderService.dimensions.css.cell.height}px`}};r.AccessibilityManager=s=l([_(1,h.IInstantiationService),_(2,p.ICoreBrowserService),_(3,p.IRenderService)],s)},3614:(B,r)=>{function o(d){return d.replace(/\r?\n/g,"\r")}function l(d,u){return u?"\x1B[200~"+d+"\x1B[201~":d}function _(d,u,p,h){d=l(d=o(d),p.decPrivateModes.bracketedPasteMode&&h.rawOptions.ignoreBracketedPasteMode!==!0),p.triggerDataEvent(d,!0),u.value=""}function n(d,u,p){const h=p.getBoundingClientRect(),t=d.clientX-h.left-10,s=d.clientY-h.top-10;u.style.width="20px",u.style.height="20px",u.style.left=`${t}px`,u.style.top=`${s}px`,u.style.zIndex="1000",u.focus()}Object.defineProperty(r,"__esModule",{value:!0}),r.rightClickHandler=r.moveTextAreaUnderMouseCursor=r.paste=r.handlePasteEvent=r.copyHandler=r.bracketTextForPaste=r.prepareTextForTerminal=void 0,r.prepareTextForTerminal=o,r.bracketTextForPaste=l,r.copyHandler=function(d,u){d.clipboardData&&d.clipboardData.setData("text/plain",u.selectionText),d.preventDefault()},r.handlePasteEvent=function(d,u,p,h){d.stopPropagation(),d.clipboardData&&_(d.clipboardData.getData("text/plain"),u,p,h)},r.paste=_,r.moveTextAreaUnderMouseCursor=n,r.rightClickHandler=function(d,u,p,h,t){n(d,u,p),t&&h.rightClickSelect(d),u.value=h.selectionText,u.select()}},7239:(B,r,o)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.ColorContrastCache=void 0;const l=o(1505);r.ColorContrastCache=class{constructor(){this._color=new l.TwoKeyMap,this._css=new l.TwoKeyMap}setCss(_,n,d){this._css.set(_,n,d)}getCss(_,n){return this._css.get(_,n)}setColor(_,n,d){this._color.set(_,n,d)}getColor(_,n){return this._color.get(_,n)}clear(){this._color.clear(),this._css.clear()}}},3656:(B,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.addDisposableDomListener=void 0,r.addDisposableDomListener=function(o,l,_,n){o.addEventListener(l,_,n);let d=!1;return{dispose:()=>{d||(d=!0,o.removeEventListener(l,_,n))}}}},3551:function(B,r,o){var l=this&&this.__decorate||function(s,e,i,a){var v,f=arguments.length,g=f<3?e:a===null?a=Object.getOwnPropertyDescriptor(e,i):a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")g=Reflect.decorate(s,e,i,a);else for(var c=s.length-1;c>=0;c--)(v=s[c])&&(g=(f<3?v(g):f>3?v(e,i,g):v(e,i))||g);return f>3&&g&&Object.defineProperty(e,i,g),g},_=this&&this.__param||function(s,e){return function(i,a){e(i,a,s)}};Object.defineProperty(r,"__esModule",{value:!0}),r.Linkifier=void 0;const n=o(3656),d=o(8460),u=o(844),p=o(2585),h=o(4725);let t=r.Linkifier=class extends u.Disposable{get currentLink(){return this._currentLink}constructor(s,e,i,a,v){super(),this._element=s,this._mouseService=e,this._renderService=i,this._bufferService=a,this._linkProviderService=v,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new d.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new d.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,u.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,u.toDisposable)((()=>{this._lastMouseEvent=void 0,this._activeProviderReplies?.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,n.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,n.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(s){this._lastMouseEvent=s;const e=this._positionFromMouseEvent(s,this._element,this._mouseService);if(!e)return;this._isMouseOut=!1;const i=s.composedPath();for(let a=0;a<i.length;a++){const v=i[a];if(v.classList.contains("xterm"))break;if(v.classList.contains("xterm-hover"))return}this._lastBufferCell&&e.x===this._lastBufferCell.x&&e.y===this._lastBufferCell.y||(this._handleHover(e),this._lastBufferCell=e)}_handleHover(s){if(this._activeLine!==s.y||this._wasResized)return this._clearCurrentLink(),this._askForLink(s,!1),void(this._wasResized=!1);this._currentLink&&this._linkAtPosition(this._currentLink.link,s)||(this._clearCurrentLink(),this._askForLink(s,!0))}_askForLink(s,e){this._activeProviderReplies&&e||(this._activeProviderReplies?.forEach((a=>{a?.forEach((v=>{v.link.dispose&&v.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=s.y);let i=!1;for(const[a,v]of this._linkProviderService.linkProviders.entries())e?this._activeProviderReplies?.get(a)&&(i=this._checkLinkProviderResult(a,s,i)):v.provideLinks(s.y,(f=>{if(this._isMouseOut)return;const g=f?.map((c=>({link:c})));this._activeProviderReplies?.set(a,g),i=this._checkLinkProviderResult(a,s,i),this._activeProviderReplies?.size===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(s.y,this._activeProviderReplies)}))}_removeIntersectingLinks(s,e){const i=new Set;for(let a=0;a<e.size;a++){const v=e.get(a);if(v)for(let f=0;f<v.length;f++){const g=v[f],c=g.link.range.start.y<s?0:g.link.range.start.x,m=g.link.range.end.y>s?this._bufferService.cols:g.link.range.end.x;for(let E=c;E<=m;E++){if(i.has(E)){v.splice(f--,1);break}i.add(E)}}}}_checkLinkProviderResult(s,e,i){if(!this._activeProviderReplies)return i;const a=this._activeProviderReplies.get(s);let v=!1;for(let f=0;f<s;f++)this._activeProviderReplies.has(f)&&!this._activeProviderReplies.get(f)||(v=!0);if(!v&&a){const f=a.find((g=>this._linkAtPosition(g.link,e)));f&&(i=!0,this._handleNewLink(f))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!i)for(let f=0;f<this._activeProviderReplies.size;f++){const g=this._activeProviderReplies.get(f)?.find((c=>this._linkAtPosition(c.link,e)));if(g){i=!0,this._handleNewLink(g);break}}return i}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(s){if(!this._currentLink)return;const e=this._positionFromMouseEvent(s,this._element,this._mouseService);e&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,e)&&this._currentLink.link.activate(s,this._currentLink.link.text)}_clearCurrentLink(s,e){this._currentLink&&this._lastMouseEvent&&(!s||!e||this._currentLink.link.range.start.y>=s&&this._currentLink.link.range.end.y<=e)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,u.disposeArray)(this._linkCacheDisposables))}_handleNewLink(s){if(!this._lastMouseEvent)return;const e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._linkAtPosition(s.link,e)&&(this._currentLink=s,this._currentLink.state={decorations:{underline:s.link.decorations===void 0||s.link.decorations.underline,pointerCursor:s.link.decorations===void 0||s.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,s.link,this._lastMouseEvent),s.link.decorations={},Object.defineProperties(s.link.decorations,{pointerCursor:{get:()=>this._currentLink?.state?.decorations.pointerCursor,set:i=>{this._currentLink?.state&&this._currentLink.state.decorations.pointerCursor!==i&&(this._currentLink.state.decorations.pointerCursor=i,this._currentLink.state.isHovered&&this._element.classList.toggle("xterm-cursor-pointer",i))}},underline:{get:()=>this._currentLink?.state?.decorations.underline,set:i=>{this._currentLink?.state&&this._currentLink?.state?.decorations.underline!==i&&(this._currentLink.state.decorations.underline=i,this._currentLink.state.isHovered&&this._fireUnderlineEvent(s.link,i))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((i=>{if(!this._currentLink)return;const a=i.start===0?0:i.start+1+this._bufferService.buffer.ydisp,v=this._bufferService.buffer.ydisp+1+i.end;if(this._currentLink.link.range.start.y>=a&&this._currentLink.link.range.end.y<=v&&(this._clearCurrentLink(a,v),this._lastMouseEvent)){const f=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);f&&this._askForLink(f,!1)}}))))}_linkHover(s,e,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(e,!0),this._currentLink.state.decorations.pointerCursor&&s.classList.add("xterm-cursor-pointer")),e.hover&&e.hover(i,e.text)}_fireUnderlineEvent(s,e){const i=s.range,a=this._bufferService.buffer.ydisp,v=this._createLinkUnderlineEvent(i.start.x-1,i.start.y-a-1,i.end.x,i.end.y-a-1,void 0);(e?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(v)}_linkLeave(s,e,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(e,!1),this._currentLink.state.decorations.pointerCursor&&s.classList.remove("xterm-cursor-pointer")),e.leave&&e.leave(i,e.text)}_linkAtPosition(s,e){const i=s.range.start.y*this._bufferService.cols+s.range.start.x,a=s.range.end.y*this._bufferService.cols+s.range.end.x,v=e.y*this._bufferService.cols+e.x;return i<=v&&v<=a}_positionFromMouseEvent(s,e,i){const a=i.getCoords(s,e,this._bufferService.cols,this._bufferService.rows);if(a)return{x:a[0],y:a[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(s,e,i,a,v){return{x1:s,y1:e,x2:i,y2:a,cols:this._bufferService.cols,fg:v}}};r.Linkifier=t=l([_(1,h.IMouseService),_(2,h.IRenderService),_(3,p.IBufferService),_(4,h.ILinkProviderService)],t)},9042:(B,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.tooMuchOutput=r.promptLabel=void 0,r.promptLabel="Terminal input",r.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(B,r,o){var l=this&&this.__decorate||function(h,t,s,e){var i,a=arguments.length,v=a<3?t:e===null?e=Object.getOwnPropertyDescriptor(t,s):e;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")v=Reflect.decorate(h,t,s,e);else for(var f=h.length-1;f>=0;f--)(i=h[f])&&(v=(a<3?i(v):a>3?i(t,s,v):i(t,s))||v);return a>3&&v&&Object.defineProperty(t,s,v),v},_=this&&this.__param||function(h,t){return function(s,e){t(s,e,h)}};Object.defineProperty(r,"__esModule",{value:!0}),r.OscLinkProvider=void 0;const n=o(511),d=o(2585);let u=r.OscLinkProvider=class{constructor(h,t,s){this._bufferService=h,this._optionsService=t,this._oscLinkService=s}provideLinks(h,t){const s=this._bufferService.buffer.lines.get(h-1);if(!s)return void t(void 0);const e=[],i=this._optionsService.rawOptions.linkHandler,a=new n.CellData,v=s.getTrimmedLength();let f=-1,g=-1,c=!1;for(let m=0;m<v;m++)if(g!==-1||s.hasContent(m)){if(s.loadCell(m,a),a.hasExtendedAttrs()&&a.extended.urlId){if(g===-1){g=m,f=a.extended.urlId;continue}c=a.extended.urlId!==f}else g!==-1&&(c=!0);if(c||g!==-1&&m===v-1){const E=this._oscLinkService.getLinkData(f)?.uri;if(E){const k={start:{x:g+1,y:h},end:{x:m+(c||m!==v-1?0:1),y:h}};let D=!1;if(!i?.allowNonHttpProtocols)try{const b=new URL(E);["http:","https:"].includes(b.protocol)||(D=!0)}catch{D=!0}D||e.push({text:E,range:k,activate:(b,x)=>i?i.activate(b,x,k):p(0,x),hover:(b,x)=>i?.hover?.(b,x,k),leave:(b,x)=>i?.leave?.(b,x,k)})}c=!1,a.hasExtendedAttrs()&&a.extended.urlId?(g=m,f=a.extended.urlId):(g=-1,f=-1)}}t(e)}};function p(h,t){if(confirm(`Do you want to navigate to ${t}?
|
|
4
4
|
|