@ours.network/fleet 0.10.4 → 0.11.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/dist/application/fleet-query-service.d.ts +11 -0
- package/dist/application/fleet-query-service.js +9 -1
- package/dist/cli.js +202 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.js +3 -1
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +32 -0
- package/dist/duration.d.ts +5 -0
- package/dist/duration.js +20 -0
- package/dist/harness/codex.js +16 -1
- package/dist/isolation/policy.js +5 -0
- package/dist/isolation/runtime.d.ts +16 -0
- package/dist/isolation/runtime.js +136 -0
- package/dist/isolation/types.d.ts +2 -0
- package/dist/ops.d.ts +16 -0
- package/dist/ops.js +112 -3
- package/dist/paths.d.ts +1 -0
- package/dist/paths.js +1 -0
- package/dist/resolved-plan.js +8 -0
- package/dist/runner.js +11 -5
- package/dist/watchdog/alerts.d.ts +34 -0
- package/dist/watchdog/alerts.js +78 -0
- package/dist/watchdog/briefing.d.ts +65 -0
- package/dist/watchdog/briefing.js +181 -0
- package/dist/watchdog/config.d.ts +53 -0
- package/dist/watchdog/config.js +120 -0
- package/dist/watchdog/query.d.ts +78 -0
- package/dist/watchdog/query.js +124 -0
- package/dist/watchdog/report.d.ts +53 -0
- package/dist/watchdog/report.js +126 -0
- package/dist/watchdog/run.d.ts +63 -0
- package/dist/watchdog/run.js +345 -0
- package/dist/watchdog/scheduler.d.ts +105 -0
- package/dist/watchdog/scheduler.js +244 -0
- package/dist/watchdog/service.d.ts +46 -0
- package/dist/watchdog/service.js +179 -0
- package/dist/watchdog/store.d.ts +85 -0
- package/dist/watchdog/store.js +226 -0
- package/dist/web/runtime.js +46 -2
- package/dist/web/server.d.ts +2 -0
- package/dist/web/server.js +18 -0
- package/dist/web-app/assets/{TerminalView-DcImdrI1.js → TerminalView-BvcIkuIF.js} +1 -1
- package/dist/web-app/assets/index-B-jtLAkp.css +1 -0
- package/dist/web-app/assets/index-CUN7ksTw.js +9 -0
- package/dist/web-app/index.html +2 -2
- package/package.json +1 -1
- package/dist/web-app/assets/index-BokQN1Ao.js +0 -9
- package/dist/web-app/assets/index-lAXzaOZM.css +0 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { watchdogsRoot } from '../paths.js';
|
|
4
|
+
// store.ts imports config.ts (ROLE_NAME_RE) but not the reverse — config.ts's
|
|
5
|
+
// import graph (config-yaml, isolation/policy, harness/registry, watchdog/config)
|
|
6
|
+
// never reaches back into watchdog/store.ts, so this does not create a cycle.
|
|
7
|
+
import { ROLE_NAME_RE } from '../config.js';
|
|
8
|
+
const RUN_ID_RE = /^\d{8}T\d{6}Z$/;
|
|
9
|
+
const REPORT_FILE_RE = /^\d{8}T\d{6}Z\.json$/;
|
|
10
|
+
/**
|
|
11
|
+
* A lock directory briefly exists before acquireRunLock can rename its
|
|
12
|
+
* prewritten owner.json into it. Missing/corrupt owner metadata is therefore
|
|
13
|
+
* reclaimable only after this grace period, never while that acquisition
|
|
14
|
+
* window may still be in progress.
|
|
15
|
+
*/
|
|
16
|
+
export const RUN_LOCK_OWNER_GRACE_MS = 10_000;
|
|
17
|
+
/**
|
|
18
|
+
* mkdirSync's `mode` is masked by the process umask and ignored outright when
|
|
19
|
+
* the directory already exists, so an explicit chmod after mkdir is the only
|
|
20
|
+
* way to guarantee 0700 regardless of umask or prior state.
|
|
21
|
+
*/
|
|
22
|
+
function ensureDir(dir) {
|
|
23
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
24
|
+
chmodSync(dir, 0o700);
|
|
25
|
+
return dir;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Choke point every other helper in this module goes through to reach a
|
|
29
|
+
* watchdog's on-disk state. Validates `name` BEFORE any join/mkdir (defense
|
|
30
|
+
* in depth, finding #1): a caller that forgets its own ROLE_NAME_RE guard
|
|
31
|
+
* (as the CLI's `watchdogKnown` once did) must not be able to turn an
|
|
32
|
+
* unvalidated `name` into `join(watchdogsRoot(), '../../victim')` and mkdir
|
|
33
|
+
* an arbitrary path on disk.
|
|
34
|
+
*/
|
|
35
|
+
export function watchdogDir(name) {
|
|
36
|
+
if (!ROLE_NAME_RE.test(name))
|
|
37
|
+
throw new Error(`invalid watchdog name '${name}'`);
|
|
38
|
+
return ensureDir(join(watchdogsRoot(), name));
|
|
39
|
+
}
|
|
40
|
+
export function reportsDir(name) {
|
|
41
|
+
return ensureDir(join(watchdogDir(name), 'reports'));
|
|
42
|
+
}
|
|
43
|
+
function runLockPath(name) {
|
|
44
|
+
return join(watchdogDir(name), '.run-lock');
|
|
45
|
+
}
|
|
46
|
+
function runLockOwnerPath(name) {
|
|
47
|
+
return join(runLockPath(name), 'owner.json');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* mkdir-as-mutex: atomic across processes, unlike a lock file (open+O_EXCL
|
|
51
|
+
* would work too, but a directory needs no cleanup of file contents and
|
|
52
|
+
* can't be partially written). EEXIST means another run holds it.
|
|
53
|
+
*
|
|
54
|
+
* Stamps `owner.json` with our pid (finding #2): ownership metadata is what
|
|
55
|
+
* lets a later `reclaimStaleRunLock` tell a lock abandoned by a dead process
|
|
56
|
+
* apart from one genuinely held by a live run. A naive "mkdir, then
|
|
57
|
+
* writeFileSync(owner.json)" leaves an unnecessarily wide window —
|
|
58
|
+
* between the mkdir succeeding and the write landing — where the lock dir
|
|
59
|
+
* exists but owner.json doesn't yet. A `reclaimStaleRunLock` call from
|
|
60
|
+
* another process landing in exactly that window would see a lock with no
|
|
61
|
+
* (or corrupt) owner metadata and treat a genuinely live lock as a legacy
|
|
62
|
+
* one, reclaiming it out from under us. Do all slow work (building the JSON,
|
|
63
|
+
* writing it, chmod) to a per-pid temp file BEFORE mkdir, then publish it with
|
|
64
|
+
* one rename. There is still an unavoidable interval between those two
|
|
65
|
+
* syscalls; reclaimStaleRunLock protects it by treating a fresh ownerless lock
|
|
66
|
+
* as held for RUN_LOCK_OWNER_GRACE_MS. The temp file is unique per-pid (this
|
|
67
|
+
* function is synchronous, so there's no same-process concurrent-call hazard
|
|
68
|
+
* either) and is cleaned up if mkdir loses the race.
|
|
69
|
+
*/
|
|
70
|
+
export function acquireRunLock(name) {
|
|
71
|
+
const dir = watchdogDir(name);
|
|
72
|
+
const owner = { pid: process.pid, at: new Date().toISOString() };
|
|
73
|
+
const tempOwnerPath = join(dir, `.owner.${process.pid}.tmp`);
|
|
74
|
+
writeFileSync(tempOwnerPath, JSON.stringify(owner), { mode: 0o600 });
|
|
75
|
+
chmodSync(tempOwnerPath, 0o600);
|
|
76
|
+
try {
|
|
77
|
+
mkdirSync(runLockPath(name));
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
try {
|
|
81
|
+
unlinkSync(tempOwnerPath);
|
|
82
|
+
}
|
|
83
|
+
catch { /* best effort cleanup */ }
|
|
84
|
+
if (e.code === 'EEXIST')
|
|
85
|
+
return false;
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
renameSync(tempOwnerPath, runLockOwnerPath(name));
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Release-tolerant of absence: a lock already gone (or never acquired) is not
|
|
93
|
+
* an error. Recursive because the lock dir now holds `owner.json` alongside
|
|
94
|
+
* the mkdir mutex itself (finding #2) — a plain rmdir would fail ENOTEMPTY.
|
|
95
|
+
*/
|
|
96
|
+
export function releaseRunLock(name) {
|
|
97
|
+
try {
|
|
98
|
+
rmSync(runLockPath(name), { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
if (e.code === 'ENOENT')
|
|
102
|
+
return;
|
|
103
|
+
throw e;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Reads a run lock's owner metadata; missing or corrupt yields undefined. */
|
|
107
|
+
export function readRunLockOwner(name) {
|
|
108
|
+
try {
|
|
109
|
+
const raw = JSON.parse(readFileSync(runLockOwnerPath(name), 'utf8'));
|
|
110
|
+
if (!Number.isInteger(raw.pid) || raw.pid <= 0 || typeof raw.at !== 'string')
|
|
111
|
+
return undefined;
|
|
112
|
+
return { pid: raw.pid, at: raw.at };
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** True iff `pid` names a live process. EPERM means the process exists but we can't signal it — still alive. */
|
|
119
|
+
function pidAlive(pid) {
|
|
120
|
+
try {
|
|
121
|
+
process.kill(pid, 0);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
return e.code === 'EPERM';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Owner-mandated (finding #2): only a DEMONSTRABLY stale run lock may be
|
|
130
|
+
* reclaimed — a lock is stale iff it isn't held at all, its owner metadata
|
|
131
|
+
* names a dead pid, or its owner metadata is missing/corrupt AND the lock dir
|
|
132
|
+
* is older than RUN_LOCK_OWNER_GRACE_MS. The age gate closes the interprocess
|
|
133
|
+
* interval between acquireRunLock's mkdir and owner.json rename: a concurrent
|
|
134
|
+
* scheduler sees a fresh ownerless lock as held, not stale. A live owner (a
|
|
135
|
+
* foreground `watchdog-run`, another scheduler instance, an in-progress run)
|
|
136
|
+
* is left strictly alone: reclaiming it would let two runs share the same temp
|
|
137
|
+
* dir.
|
|
138
|
+
* Returns true when the lock is (now) not held — whether because it was
|
|
139
|
+
* already absent or because a stale lock was just removed; false when a live
|
|
140
|
+
* lock was found and deliberately left in place.
|
|
141
|
+
*/
|
|
142
|
+
export function reclaimStaleRunLock(name) {
|
|
143
|
+
const path = runLockPath(name);
|
|
144
|
+
if (!existsSync(path))
|
|
145
|
+
return true;
|
|
146
|
+
const owner = readRunLockOwner(name);
|
|
147
|
+
if (owner !== undefined && pidAlive(owner.pid))
|
|
148
|
+
return false;
|
|
149
|
+
if (owner === undefined) {
|
|
150
|
+
try {
|
|
151
|
+
if (Date.now() - statSync(path).mtimeMs < RUN_LOCK_OWNER_GRACE_MS)
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
// The holder may have released between existsSync and statSync.
|
|
156
|
+
if (e.code === 'ENOENT')
|
|
157
|
+
return true;
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
releaseRunLock(name);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
/** Lexical-chronological UTC run id, e.g. '20260731T115000Z'. */
|
|
165
|
+
export function formatRunId(d) {
|
|
166
|
+
return d.toISOString().replace(/\.\d{3}Z$/, 'Z').replace(/[-:]/g, '');
|
|
167
|
+
}
|
|
168
|
+
const CORRUPT_SUMMARY = { checked: 0, healthy: 0, idle: 0, anomalies: 0 };
|
|
169
|
+
function reportPath(name, runId) {
|
|
170
|
+
return join(reportsDir(name), `${runId}.json`);
|
|
171
|
+
}
|
|
172
|
+
/** Newest-first run ids currently on disk, derived from filenames alone. */
|
|
173
|
+
function runIdsDesc(name) {
|
|
174
|
+
return readdirSync(reportsDir(name))
|
|
175
|
+
.filter(f => REPORT_FILE_RE.test(f))
|
|
176
|
+
.sort()
|
|
177
|
+
.reverse()
|
|
178
|
+
.map(f => f.slice(0, -'.json'.length));
|
|
179
|
+
}
|
|
180
|
+
export function writeReport(name, report) {
|
|
181
|
+
const path = reportPath(name, report.run_id);
|
|
182
|
+
writeFileSync(path, JSON.stringify(report, null, 2) + '\n', { mode: 0o600 });
|
|
183
|
+
chmodSync(path, 0o600);
|
|
184
|
+
return path;
|
|
185
|
+
}
|
|
186
|
+
/** Newest-first run listing; a corrupt report file yields a synthetic 'error' entry rather than throwing. */
|
|
187
|
+
export function listRuns(name) {
|
|
188
|
+
return runIdsDesc(name).map((runId) => {
|
|
189
|
+
try {
|
|
190
|
+
const report = JSON.parse(readFileSync(reportPath(name, runId), 'utf8'));
|
|
191
|
+
return {
|
|
192
|
+
runId, status: report.status, startedAt: report.started_at, finishedAt: report.finished_at,
|
|
193
|
+
summary: report.summary, error: report.error,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return { runId, status: 'error', startedAt: '', finishedAt: '', summary: CORRUPT_SUMMARY, error: 'unreadable report file' };
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/** Reads one run's full report. Rejects non-conforming runIds (path-traversal guard) and corrupt files by returning undefined. */
|
|
202
|
+
export function readReport(name, runId) {
|
|
203
|
+
if (!RUN_ID_RE.test(runId))
|
|
204
|
+
return undefined;
|
|
205
|
+
try {
|
|
206
|
+
return JSON.parse(readFileSync(reportPath(name, runId), 'utf8'));
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
export function latestReport(name) {
|
|
213
|
+
const [newest] = runIdsDesc(name);
|
|
214
|
+
return newest === undefined ? undefined : readReport(name, newest);
|
|
215
|
+
}
|
|
216
|
+
/** Deletes all but the `keep` newest reports (oldest first); returns the number pruned. */
|
|
217
|
+
export function pruneReports(name, keep) {
|
|
218
|
+
const stale = runIdsDesc(name).slice(keep);
|
|
219
|
+
for (const runId of stale) {
|
|
220
|
+
try {
|
|
221
|
+
unlinkSync(reportPath(name, runId));
|
|
222
|
+
}
|
|
223
|
+
catch { /* best effort */ }
|
|
224
|
+
}
|
|
225
|
+
return stale.length;
|
|
226
|
+
}
|
package/dist/web/runtime.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { existsSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
+
import { loadConfig } from '../config.js';
|
|
4
5
|
import { RoleRepository } from '../application/role-repository.js';
|
|
5
6
|
import { FleetQueryService } from '../application/fleet-query-service.js';
|
|
6
7
|
import { AcpRoleSessionAdapter, TmuxRoleSessionAdapter } from '../application/session-control.js';
|
|
@@ -21,6 +22,24 @@ import { acquireWebServerLock } from './lock.js';
|
|
|
21
22
|
import { TrustedDeviceStore } from './device-store.js';
|
|
22
23
|
import { WebAuth } from './auth.js';
|
|
23
24
|
import { startWebControlServer } from './control.js';
|
|
25
|
+
import { buildWatchdogFindings, cachedWatchdogFindingsProvider, WatchdogQueryService } from '../watchdog/query.js';
|
|
26
|
+
import { latestReport } from '../watchdog/store.js';
|
|
27
|
+
const CONFIG_CACHE_TTL_MS = 5_000;
|
|
28
|
+
/**
|
|
29
|
+
* loadConfig re-parses YAML from disk on every call; the watchdog list/reports
|
|
30
|
+
* routes get polled by the console UI, so cache the resolved config for a
|
|
31
|
+
* short TTL rather than re-parsing per request. Runtime-only concern (not the
|
|
32
|
+
* scheduler's), so a plain Date.now() clock is fine.
|
|
33
|
+
*/
|
|
34
|
+
function cachedConfigProvider(configPath) {
|
|
35
|
+
let cached;
|
|
36
|
+
return () => {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
if (!cached || now - cached.at >= CONFIG_CACHE_TTL_MS)
|
|
39
|
+
cached = { at: now, cfg: loadConfig(configPath) };
|
|
40
|
+
return cached.cfg;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
24
43
|
export async function startWebConsole(options) {
|
|
25
44
|
const requestedPort = options.port ?? 49_271;
|
|
26
45
|
if (!Number.isInteger(requestedPort) || requestedPort < 0 || requestedPort > 65_535)
|
|
@@ -51,11 +70,35 @@ export async function startWebConsole(options) {
|
|
|
51
70
|
const audit = new AuditSink();
|
|
52
71
|
const terminals = new TerminalBridgeManager({ repository, audit, tmux });
|
|
53
72
|
const terminalAvailable = await terminals.available();
|
|
73
|
+
const watchdogConfigProvider = cachedConfigProvider(options.configPath);
|
|
74
|
+
const log = options.log ?? (() => { });
|
|
75
|
+
let loggedWatchdogFindingsError = false;
|
|
76
|
+
// Needs-attention integration (Task 19): worst per-role watchdog finding,
|
|
77
|
+
// rebuilt from stored reports. A store hiccup (corrupt state, unreadable
|
|
78
|
+
// report) must never break the fleet list, so it degrades to an empty map
|
|
79
|
+
// and logs once rather than repeating on every poll. status() calls this
|
|
80
|
+
// once per role, so list()'s O(roles) sweep would otherwise cost
|
|
81
|
+
// O(roles x watchdogs) disk reads every 1-3s of console polling —
|
|
82
|
+
// cachedWatchdogFindingsProvider memoizes the whole build behind the same
|
|
83
|
+
// TTL as the config cache above.
|
|
84
|
+
const watchdogFindings = cachedWatchdogFindingsProvider(() => {
|
|
85
|
+
try {
|
|
86
|
+
return buildWatchdogFindings(watchdogConfigProvider(), latestReport);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (!loggedWatchdogFindingsError) {
|
|
90
|
+
loggedWatchdogFindingsError = true;
|
|
91
|
+
log(`watchdog findings unavailable: ${error.message}`);
|
|
92
|
+
}
|
|
93
|
+
return new Map();
|
|
94
|
+
}
|
|
95
|
+
}, CONFIG_CACHE_TTL_MS);
|
|
54
96
|
const query = new FleetQueryService({
|
|
55
97
|
repository, supervisor: backend, tmux,
|
|
56
98
|
capabilityContext: { terminalPtyAvailable: terminalAvailable },
|
|
99
|
+
watchdogFindings,
|
|
57
100
|
});
|
|
58
|
-
const ops = { backend, binPath: options.binPath, log
|
|
101
|
+
const ops = { backend, binPath: options.binPath, log };
|
|
59
102
|
const creation = new RoleCreationService({
|
|
60
103
|
configPath: options.configPath, ops, binPath: options.binPath,
|
|
61
104
|
allowedCwdRoots: [realpathSync(home()), realpathSync(process.cwd())],
|
|
@@ -84,10 +127,11 @@ export async function startWebConsole(options) {
|
|
|
84
127
|
},
|
|
85
128
|
});
|
|
86
129
|
const logs = new StructuredLogService(backend, realExec);
|
|
130
|
+
const watchdogs = new WatchdogQueryService(watchdogConfigProvider);
|
|
87
131
|
let server;
|
|
88
132
|
try {
|
|
89
133
|
server = await buildWebServer({
|
|
90
|
-
query, repository, logs, commands, creation, audit, events,
|
|
134
|
+
query, repository, logs, commands, creation, audit, events, watchdogs,
|
|
91
135
|
terminalUpgrade: terminalAvailable
|
|
92
136
|
? async (socket, _request, roleId, _ticket, hello) => terminals.connect(socket, roleId, hello)
|
|
93
137
|
: undefined,
|
package/dist/web/server.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { RoleSessionControl } from '../application/session-control.js';
|
|
|
6
6
|
import type { StructuredLogService } from '../application/log-service.js';
|
|
7
7
|
import type { RoleCommandService } from '../application/role-command-service.js';
|
|
8
8
|
import type { RoleCreationService } from '../application/role-creation-service.js';
|
|
9
|
+
import type { WatchdogQueryService } from '../watchdog/query.js';
|
|
9
10
|
import { AuditSink } from './audit.js';
|
|
10
11
|
import { WebAuth } from './auth.js';
|
|
11
12
|
import { FleetEventBus } from './events.js';
|
|
@@ -18,6 +19,7 @@ export interface WebServices {
|
|
|
18
19
|
creation: RoleCreationService;
|
|
19
20
|
audit?: AuditSink;
|
|
20
21
|
events?: FleetEventBus;
|
|
22
|
+
watchdogs?: WatchdogQueryService;
|
|
21
23
|
terminalUpgrade?: (socket: WebSocket, request: FastifyRequest, roleId: string, ticket: string, hello: Record<string, unknown>) => Promise<void>;
|
|
22
24
|
}
|
|
23
25
|
export interface WebServer {
|
package/dist/web/server.js
CHANGED
|
@@ -186,6 +186,24 @@ export async function buildWebServer(services, boundary, options = {}) {
|
|
|
186
186
|
auth.authenticate(request);
|
|
187
187
|
return { records: audit.list() };
|
|
188
188
|
});
|
|
189
|
+
app.get('/api/v1/watchdogs', async (request) => {
|
|
190
|
+
auth.authenticate(request);
|
|
191
|
+
if (!services.watchdogs)
|
|
192
|
+
throw new FleetError('capability_unavailable', 'watchdogs are unavailable');
|
|
193
|
+
return services.watchdogs.list();
|
|
194
|
+
});
|
|
195
|
+
app.get('/api/v1/watchdogs/:name/reports', async (request) => {
|
|
196
|
+
auth.authenticate(request);
|
|
197
|
+
if (!services.watchdogs)
|
|
198
|
+
throw new FleetError('capability_unavailable', 'watchdogs are unavailable');
|
|
199
|
+
return services.watchdogs.reports(request.params.name, request.query.limit ? Number(request.query.limit) : undefined);
|
|
200
|
+
});
|
|
201
|
+
app.get('/api/v1/watchdogs/:name/reports/:runId', async (request) => {
|
|
202
|
+
auth.authenticate(request);
|
|
203
|
+
if (!services.watchdogs)
|
|
204
|
+
throw new FleetError('capability_unavailable', 'watchdogs are unavailable');
|
|
205
|
+
return services.watchdogs.report(request.params.name, request.params.runId);
|
|
206
|
+
});
|
|
189
207
|
app.get('/api/v1/events', { websocket: true }, (socket, request) => {
|
|
190
208
|
requireSubprotocol(request, 'ours-fleet-events.v1');
|
|
191
209
|
authorizeSocket(socket, request, async (hello) => {
|
|
@@ -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-CUN7ksTw.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
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#e9eef0;background:#080b0c;font-synthesis:none;--panel: #111617;--line: #222a2c;--muted: #849093;--mint: #7ce7b0;--amber: #f0c66c;--red: #ff827c}*{box-sizing:border-box}body{margin:0;min-width:900px;min-height:100vh;background:radial-gradient(circle at 70% -20%,#183027 0,transparent 35%),#080b0c}button,input,select,textarea{font:inherit}button{color:inherit}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--mint);outline-offset:2px}.auth-screen{display:grid;place-content:center;text-align:center;min-height:100vh;color:var(--muted)}.auth-screen h1{color:#fff;margin-bottom:0}.brand-wordmark{color:var(--mint);font-size:21px;font-weight:820;letter-spacing:-.02em}.auth-screen .brand-wordmark{justify-self:center;font-size:32px}.shell{display:grid;grid-template-columns:224px 1fr;min-height:100vh}aside{position:fixed;inset:0 auto 0 0;width:224px;display:flex;flex-direction:column;padding:24px 14px;border-right:1px solid #1d2425;background:#080b0ceb;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.brand{display:flex;gap:12px;align-items:center;padding:0 8px 30px}.brand div{display:flex;flex-direction:column}.brand small{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:1.4px}nav{display:grid;gap:5px}nav button{display:grid;grid-template-columns:24px 1fr auto;gap:8px;align-items:center;width:100%;border:0;border-radius:8px;padding:10px 12px;text-align:left;color:#98a3a5;background:transparent;text-transform:capitalize;cursor:pointer}nav button:hover,nav button.active{color:#fff;background:#151b1c}nav button.active{box-shadow:inset 2px 0 var(--mint)}nav b{background:#422f22;color:var(--amber);border-radius:10px;font-size:11px;padding:2px 7px}.sidebar-foot{margin-top:auto;display:grid;grid-template-columns:12px 1fr;align-items:center;padding:12px;color:var(--muted);font-size:12px;text-transform:capitalize}.sidebar-foot i{width:7px;height:7px;border-radius:50%;background:var(--amber)}.sidebar-foot i.live{background:var(--mint);box-shadow:0 0 9px var(--mint)}.sidebar-foot small{grid-column:2;opacity:.6;margin-top:3px}.main{grid-column:2;min-width:0}header{display:flex;justify-content:space-between;align-items:flex-end;height:124px;padding:25px 36px 23px;border-bottom:1px solid var(--line);background:#080b0c8c}h1,h2,h3,p{margin-top:0}header h1{margin:4px 0 0;font-size:29px;letter-spacing:-.8px}.eyebrow{color:var(--mint);text-transform:uppercase;font-size:10px;letter-spacing:1.8px;font-weight:700}.header-actions,.actions{display:flex;gap:9px}button.primary,button.secondary,.actions button,.terminal-toolbar button{border-radius:7px;padding:9px 13px;cursor:pointer}button.primary{border:1px solid #83e9b5;color:#07130d;background:var(--mint);font-weight:700}button.primary:disabled{opacity:.4;cursor:default}button.secondary,.actions button,.terminal-toolbar button{border:1px solid #30393b;background:#141a1b}button.secondary:hover,.actions button:hover{border-color:#526064}.content,.workspace{padding:28px 36px 60px}.toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;color:var(--muted);font-size:12px}.toolbar input{width:340px;padding:10px 13px;color:#fff;background:#101516;border:1px solid var(--line);border-radius:8px}.toolbar>div{display:flex;align-items:center;gap:10px}.toolbar button{padding:7px 10px}.role-row.inactive{opacity:.72}.role-row.active{background:#141a1b;border-left:2px solid var(--mint)}.watchdog-detail-layout{display:grid;gap:18px}.watchdog-report-head{display:flex;align-items:center;gap:12px}.watchdog-report-head h2{flex:1}.watchdog-roles{display:grid;gap:10px;margin-top:12px}.watchdog-role{border:1px solid var(--line);border-radius:8px;padding:12px 14px;background:#0d1213}.watchdog-role-head{display:flex;align-items:center;gap:10px}.watchdog-role-head strong{text-transform:capitalize}.watchdog-role-detail,.watchdog-role-note{margin:8px 0 0;font-size:12px;color:var(--muted)}.watchdog-role-note{color:var(--amber)}.watchdog-role details{margin-top:8px;font-size:12px}.watchdog-role summary{cursor:pointer;color:var(--muted)}.watchdog-role details ul{margin:8px 0 0;padding-left:18px;color:#c9d1d3}.watchdog-role details li{margin-bottom:4px}.status-guide{display:flex;flex-wrap:wrap;gap:7px;align-items:center;margin-bottom:15px;color:var(--muted);font-size:11px}.status-guide>span,.status-chip{display:inline-flex;align-items:center;gap:5px;border:1px solid #30393b;border-radius:12px;padding:3px 7px;white-space:nowrap}.status-guide b{color:#fff;font-size:11px}.status-guide small{flex-basis:100%;color:var(--muted)}.status-guide .ready,.status-chip.ready{border-color:#315e4a}.status-guide .busy,.status-chip.busy{border-color:#315478}.status-guide .attention,.status-chip.attention,.status-chip.unknown{border-color:#66552f}.status-guide .offline,.status-chip.offline{border-color:#693b38}.role-table{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#0e1213cc}.role-row{display:grid;grid-template-columns:minmax(260px,1.55fr) repeat(4,minmax(125px,1fr));width:100%;align-items:center;gap:15px;padding:14px 18px;border:0;border-bottom:1px solid var(--line);background:transparent;text-align:left;cursor:pointer}button.role-row:hover{background:#141a1b}.role-row.heading{padding-block:10px;color:#6f7b7e;font-size:10px;letter-spacing:1px;text-transform:uppercase;cursor:default}.role-row:last-child{border-bottom:0}.role-row>span{min-width:0;display:flex;flex-direction:column;gap:3px}.role-row strong{font-size:13px;text-transform:capitalize;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.role-row small{color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.role-name{position:relative;display:grid!important;grid-template-columns:auto 1fr auto;align-items:center}.role-name .mission-summary{display:-webkit-box;max-height:2.5em;line-height:1.25;overflow:hidden;overflow-wrap:anywhere;white-space:normal;-webkit-box-orient:vertical;-webkit-line-clamp:2}.status-chip{color:#c9d1d3;font-size:10px;padding:3px 6px}.status-chip i{width:6px;height:6px;border-radius:50%;background:#667174}.status-chip.ready i{background:var(--mint)}.status-chip.busy i{background:#71b7ff}.status-chip.attention i,.status-chip.unknown i{background:var(--amber)}.status-chip.offline i{background:var(--red)}.state.ready,.hero-state.ready i{background:var(--mint);box-shadow:0 0 7px #69dba0}.state.busy,.hero-state.busy i{background:#71b7ff}.state.attention,.state.unknown,.hero-state.attention i,.hero-state.unknown i{background:var(--amber)}.state.offline,.hero-state.offline i{background:var(--red)}.role-name em{color:#7f8a8d;font-size:10px;font-style:normal;border:1px solid #2e3739;border-radius:10px;padding:3px 6px}.role-pills{display:flex;flex-direction:column;align-items:flex-end;gap:4px}.empty{padding:60px;text-align:center;color:var(--muted)}.banner{margin:16px 36px 0;border:1px solid;border-radius:8px;padding:10px 13px;font-size:13px}.banner.error,.error{border-color:#5c302f;background:#271616;color:#ffaaa5}.banner.warning,.warning{border-color:#5a4726;background:#241e12;color:#f1ce83}.banner.info{border-color:#28463b;background:#10231c;color:#9be4bf}.workspace>.banner{margin-inline:0}.back{border:0;background:none;color:var(--muted);padding:0 0 18px;cursor:pointer}.workspace-summary{display:flex;align-items:center;gap:9px;color:var(--muted);font-size:12px}.workspace-summary>span{border:1px solid var(--line);border-radius:12px;padding:4px 8px}.workspace-summary small{margin-left:auto}.hero-state{display:flex;gap:7px;align-items:center;color:#fff;text-transform:capitalize}.hero-state i{width:7px;height:7px;border-radius:50%;background:#788}.tabs{display:flex;gap:22px;margin:26px 0 22px;border-bottom:1px solid var(--line)}.tabs button{border:0;border-bottom:2px solid transparent;padding:10px 2px;background:none;color:var(--muted);text-transform:capitalize;cursor:pointer}.tabs button.active{color:#fff;border-bottom-color:var(--mint)}.tabs button:disabled{opacity:.35;cursor:not-allowed}.dashboard-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.panel{border:1px solid var(--line);border-radius:10px;background:#101516db;padding:18px}.panel h2{font-size:15px;letter-spacing:-.2px}.panel.wide{grid-column:1 / -1}.evidence>div:first-child{display:flex;justify-content:space-between}.evidence>div:first-child strong{color:var(--mint);text-transform:capitalize;font-size:12px}dl{margin:0}dl div{display:grid;grid-template-columns:120px 1fr;gap:15px;padding:7px 0;border-top:1px solid #1d2426;font-size:12px}dt{color:var(--muted)}dd{margin:0;word-break:break-word}.danger{color:#ff9e99!important;border-color:#613432!important}.activity-layout{display:grid;grid-template-columns:1fr 290px;gap:14px;align-items:start}.activity{display:grid;gap:9px}.activity-filter{display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--muted);font-size:11px}.activity-filter button{padding:6px 9px}.event{border-left:2px solid #334044;padding:10px 13px;background:#0d1213}.event.agent_text{border-color:var(--mint)}.event.error,.event.permission{border-color:var(--amber)}.event p{margin:5px 0 0;white-space:pre-wrap}.event small,.muted{color:var(--muted)}.composer{position:sticky;top:16px;display:grid;gap:9px}textarea{min-height:84px;resize:vertical}.composer textarea,fieldset input,fieldset select,fieldset textarea{width:100%;color:#fff;border:1px solid #303a3c;border-radius:6px;background:#0d1112;padding:9px 10px}.composer small{color:var(--muted);line-height:1.45}pre{max-width:100%;overflow:auto;white-space:pre-wrap;word-break:break-word;font:12px/1.55 SFMono-Regular,Consolas,monospace;color:#cbd5d7}.log-panel>pre{margin:0;padding:5px 8px;border-bottom:1px solid #1b2224}.audit-list div{display:grid;grid-template-columns:180px 1fr 120px;padding:10px 0;border-top:1px solid var(--line);font-size:12px}.audit-list time{color:var(--muted)}.modal-backdrop{position:fixed;z-index:10;inset:0;display:grid;place-items:center;padding:30px;background:#000000b8;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.modal{width:min(900px,95vw);max-height:92vh;overflow:auto;border:1px solid #354043;border-radius:13px;background:#0d1112;box-shadow:0 30px 100px #000}.modal-head{position:sticky;z-index:2;top:0;display:flex;justify-content:space-between;align-items:flex-start;padding:22px 26px 18px;border-bottom:1px solid var(--line);background:#0d1112f5}.modal-head h2{margin:4px 0 0}.icon{border:0;background:none;color:var(--muted);font-size:25px;cursor:pointer}.wizard,.progress{padding:22px 26px}fieldset{border:0;border-bottom:1px solid var(--line);padding:0 0 20px;margin:0 0 20px}legend{margin-bottom:13px;color:var(--mint);text-transform:uppercase;font-size:10px;letter-spacing:1.5px;font-weight:700}.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:13px}.form-grid.three{grid-template-columns:repeat(3,1fr)}.wake-sources{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px 14px}.wake-sources>small{grid-column:1 / -1;color:var(--muted)}.wake-sources label{display:flex;flex-direction:row;align-items:center;gap:7px;color:#c7d0d1;font-size:11px;text-transform:none;letter-spacing:0}.form-grid label{display:grid;gap:6px;color:#b7c0c2;font-size:12px}.form-grid label small{color:var(--muted)}.form-grid .wide{grid-column:1 / -1}.risk{display:flex;align-items:center;gap:8px;margin-top:14px;color:var(--amber);font-size:12px}.review{border:1px solid #2f493f;border-radius:8px;background:#101b17;padding:15px}.review dl{display:grid;grid-template-columns:1fr 1fr;gap:0 20px}.modal-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:20px}.stage{display:flex;gap:12px;min-height:54px;position:relative}.stage:after{position:absolute;left:5px;top:14px;bottom:0;width:1px;background:#34413d;content:""}.stage:last-child:after{display:none}.stage i{z-index:1;width:11px;height:11px;margin-top:2px;border-radius:50%;background:var(--mint);box-shadow:0 0 0 4px #173026}.stage span{display:flex;flex-direction:column;text-transform:capitalize}.stage small{color:var(--muted);margin-top:3px}.terminal-panel{padding:0;overflow:hidden}.terminal-toolbar{display:flex;align-items:center;gap:12px;min-height:48px;padding:8px 12px;border-bottom:1px solid var(--line);color:var(--muted);font-size:11px}.terminal-toolbar button{margin-left:auto;padding-block:6px}.terminal-mode{text-transform:uppercase;letter-spacing:1px;color:var(--amber)}.terminal-mode.controlling{color:var(--mint)}.terminal-host{height:calc(100vh - 310px);min-height:360px;padding:8px;background:#050707}@media(max-width:1050px){.role-row{grid-template-columns:1.5fr repeat(3,1fr)}.role-row>span:nth-child(4){display:none}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}
|