@ariobarin/glossa 0.2.3-beta.1 → 0.2.4
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/app.js +1658 -529
- package/package.json +6 -2
package/dist/app.js
CHANGED
|
@@ -39741,9 +39741,9 @@ function parseInvocation(args) {
|
|
|
39741
39741
|
// src/device-format.ts
|
|
39742
39742
|
function deviceStatus(device) {
|
|
39743
39743
|
if (device.revokedAt) return "revoked";
|
|
39744
|
-
if (device.activeWorkers === null) return "
|
|
39744
|
+
if (device.activeWorkers === null) return "workspace count unavailable";
|
|
39745
39745
|
if (device.activeWorkers === 0) return "offline";
|
|
39746
|
-
return `${device.activeWorkers} active ${device.activeWorkers === 1 ? "
|
|
39746
|
+
return `${device.activeWorkers} active ${device.activeWorkers === 1 ? "workspace" : "workspaces"}`;
|
|
39747
39747
|
}
|
|
39748
39748
|
function formatRelativeTime(iso, now = Date.now()) {
|
|
39749
39749
|
if (!iso) return "never";
|
|
@@ -43019,14 +43019,14 @@ function getSgrFragments(code) {
|
|
|
43019
43019
|
return fragments;
|
|
43020
43020
|
}
|
|
43021
43021
|
function parseCsiCode(string4, index) {
|
|
43022
|
-
const
|
|
43022
|
+
const escapeCodePoint3 = string4.codePointAt(index);
|
|
43023
43023
|
let sequenceStartIndex;
|
|
43024
|
-
if (
|
|
43024
|
+
if (escapeCodePoint3 === ESCAPE_CODE_POINT) {
|
|
43025
43025
|
if (string4[index + 1] !== ANSI_CSI2) {
|
|
43026
43026
|
return;
|
|
43027
43027
|
}
|
|
43028
43028
|
sequenceStartIndex = index + 2;
|
|
43029
|
-
} else if (
|
|
43029
|
+
} else if (escapeCodePoint3 === C1_CSI_CODE_POINT) {
|
|
43030
43030
|
sequenceStartIndex = index + 1;
|
|
43031
43031
|
} else {
|
|
43032
43032
|
return;
|
|
@@ -49276,61 +49276,24 @@ async function announceConnectHint(store2, log) {
|
|
|
49276
49276
|
return true;
|
|
49277
49277
|
}
|
|
49278
49278
|
|
|
49279
|
-
// src/
|
|
49280
|
-
import
|
|
49281
|
-
|
|
49282
|
-
function parseDeviceCredential(value) {
|
|
49283
|
-
let parsed;
|
|
49284
|
-
try {
|
|
49285
|
-
parsed = JSON.parse(value);
|
|
49286
|
-
} catch {
|
|
49287
|
-
throw new Error("Stored Glossa device credentials are invalid.");
|
|
49288
|
-
}
|
|
49289
|
-
let relayOriginValid = false;
|
|
49290
|
-
if (typeof parsed.relayOrigin === "string") {
|
|
49291
|
-
try {
|
|
49292
|
-
relayOriginValid = new URL(parsed.relayOrigin).origin === parsed.relayOrigin;
|
|
49293
|
-
} catch {
|
|
49294
|
-
relayOriginValid = false;
|
|
49295
|
-
}
|
|
49296
|
-
}
|
|
49297
|
-
if (!relayOriginValid || typeof parsed.deviceId !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
|
49298
|
-
parsed.deviceId
|
|
49299
|
-
) || typeof parsed.deviceName !== "string" || parsed.deviceName.length === 0 || parsed.accountSubject !== void 0 && (typeof parsed.accountSubject !== "string" || parsed.accountSubject.length === 0) || typeof parsed.token !== "string" || !parsed.token.startsWith(`gld_${parsed.deviceId}_`)) {
|
|
49300
|
-
throw new Error("Stored Glossa device credentials are invalid.");
|
|
49301
|
-
}
|
|
49302
|
-
return parsed;
|
|
49303
|
-
}
|
|
49304
|
-
var store = new SecureStore({
|
|
49305
|
-
account: "device",
|
|
49306
|
-
file: path3.join(configDirectory(), "device.json"),
|
|
49307
|
-
warning: FILE_DEVICE_WARNING,
|
|
49308
|
-
parse: parseDeviceCredential
|
|
49309
|
-
});
|
|
49310
|
-
async function loadDeviceCredential() {
|
|
49311
|
-
return (await store.load())?.value ?? null;
|
|
49312
|
-
}
|
|
49313
|
-
async function saveDeviceCredential(credential) {
|
|
49314
|
-
await store.save(credential);
|
|
49315
|
-
}
|
|
49316
|
-
async function deleteDeviceCredential() {
|
|
49317
|
-
await store.delete();
|
|
49318
|
-
}
|
|
49279
|
+
// src/update-state.ts
|
|
49280
|
+
import { chmod as chmod2, mkdir as mkdir5, readFile as readFile4, rename, rm as rm4, writeFile as writeFile5 } from "node:fs/promises";
|
|
49281
|
+
import path5 from "node:path";
|
|
49319
49282
|
|
|
49320
|
-
// src/
|
|
49283
|
+
// src/process-lease.ts
|
|
49321
49284
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
49322
49285
|
import { mkdir as mkdir4, readFile as readFile3, rm as rm3, stat, writeFile as writeFile4 } from "node:fs/promises";
|
|
49323
|
-
import
|
|
49286
|
+
import path4 from "node:path";
|
|
49324
49287
|
import { setTimeout as delay } from "node:timers/promises";
|
|
49325
49288
|
|
|
49326
49289
|
// src/update-lock.ts
|
|
49327
49290
|
import { randomUUID } from "node:crypto";
|
|
49328
49291
|
import { mkdir as mkdir3, readdir, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
49329
|
-
import
|
|
49292
|
+
import path3 from "node:path";
|
|
49330
49293
|
var UPDATE_SUFFIX = ".update";
|
|
49331
49294
|
var SESSION_SUFFIX = ".session";
|
|
49332
49295
|
function updateRuntimeDirectory() {
|
|
49333
|
-
return
|
|
49296
|
+
return path3.join(configDirectory(), "runtime");
|
|
49334
49297
|
}
|
|
49335
49298
|
function processIsAlive(pid) {
|
|
49336
49299
|
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
@@ -49360,7 +49323,7 @@ async function activeLeaseFiles(directory, suffix) {
|
|
|
49360
49323
|
for (const entry of entries) {
|
|
49361
49324
|
if (!entry.isFile() || !entry.name.endsWith(suffix)) continue;
|
|
49362
49325
|
const pid = leasePid(entry.name, suffix);
|
|
49363
|
-
const file2 =
|
|
49326
|
+
const file2 = path3.join(directory, entry.name);
|
|
49364
49327
|
if (pid !== null && processIsAlive(pid)) active.push(file2);
|
|
49365
49328
|
else await rm2(file2, { force: true });
|
|
49366
49329
|
}
|
|
@@ -49374,7 +49337,7 @@ async function activeSessionFiles(directory) {
|
|
|
49374
49337
|
}
|
|
49375
49338
|
async function createUpdateLock(directory) {
|
|
49376
49339
|
await mkdir3(directory, { recursive: true, mode: 448 });
|
|
49377
|
-
const lockFile =
|
|
49340
|
+
const lockFile = path3.join(
|
|
49378
49341
|
directory,
|
|
49379
49342
|
`${process.pid}-${randomUUID()}${UPDATE_SUFFIX}`
|
|
49380
49343
|
);
|
|
@@ -49412,7 +49375,7 @@ async function withWorkspaceLease(action, directory = updateRuntimeDirectory())
|
|
|
49412
49375
|
if (await updateLockIsActive(directory)) {
|
|
49413
49376
|
throw new Error("Glossa is updating. Run this workspace again after the update finishes.");
|
|
49414
49377
|
}
|
|
49415
|
-
const leaseFile =
|
|
49378
|
+
const leaseFile = path3.join(
|
|
49416
49379
|
directory,
|
|
49417
49380
|
`${process.pid}-${randomUUID()}${SESSION_SUFFIX}`
|
|
49418
49381
|
);
|
|
@@ -49432,17 +49395,9 @@ async function withWorkspaceLease(action, directory = updateRuntimeDirectory())
|
|
|
49432
49395
|
}
|
|
49433
49396
|
}
|
|
49434
49397
|
|
|
49435
|
-
// src/
|
|
49436
|
-
|
|
49437
|
-
|
|
49438
|
-
var DEVICE_PAIRING_LOCK_POLL_MS = 100;
|
|
49439
|
-
var DEVICE_PAIRING_LOCK_MAX_AGE_MS = 6 * 6e4;
|
|
49440
|
-
var DEVICE_PAIRING_GUARD_MAX_AGE_MS = 3e4;
|
|
49441
|
-
function lockPath(directory) {
|
|
49442
|
-
return path5.join(directory, DEVICE_PAIRING_LOCK);
|
|
49443
|
-
}
|
|
49444
|
-
function guardPath(directory) {
|
|
49445
|
-
return path5.join(directory, DEVICE_PAIRING_LOCK_GUARD);
|
|
49398
|
+
// src/process-lease.ts
|
|
49399
|
+
function guardName(lockName) {
|
|
49400
|
+
return `${lockName}.guard`;
|
|
49446
49401
|
}
|
|
49447
49402
|
function newOwner() {
|
|
49448
49403
|
return {
|
|
@@ -49477,8 +49432,8 @@ async function lockIsStale(file2, maxAgeMs) {
|
|
|
49477
49432
|
const ageMs = Date.now() - Date.parse(owner.startedAt);
|
|
49478
49433
|
return ageMs > maxAgeMs || !processIsAlive(owner.pid);
|
|
49479
49434
|
}
|
|
49480
|
-
async function acquireGuard(directory, signal) {
|
|
49481
|
-
const file2 =
|
|
49435
|
+
async function acquireGuard(directory, options, signal) {
|
|
49436
|
+
const file2 = path4.join(directory, guardName(options.lockName));
|
|
49482
49437
|
for (; ; ) {
|
|
49483
49438
|
signal?.throwIfAborted();
|
|
49484
49439
|
const owner = newOwner();
|
|
@@ -49493,32 +49448,28 @@ async function acquireGuard(directory, signal) {
|
|
|
49493
49448
|
} catch (error46) {
|
|
49494
49449
|
if (error46.code !== "EEXIST") throw error46;
|
|
49495
49450
|
}
|
|
49496
|
-
if (await lockIsStale(file2,
|
|
49451
|
+
if (await lockIsStale(file2, options.guardMaxAgeMs)) {
|
|
49497
49452
|
await rm3(file2, { force: true });
|
|
49498
49453
|
continue;
|
|
49499
49454
|
}
|
|
49500
|
-
await delay(
|
|
49501
|
-
DEVICE_PAIRING_LOCK_POLL_MS,
|
|
49502
|
-
void 0,
|
|
49503
|
-
signal ? { signal } : void 0
|
|
49504
|
-
);
|
|
49455
|
+
await delay(options.pollMs, void 0, signal ? { signal } : void 0);
|
|
49505
49456
|
}
|
|
49506
49457
|
}
|
|
49507
49458
|
async function removeOwnedLock(file2, token) {
|
|
49508
49459
|
const owner = await readOwner(file2);
|
|
49509
49460
|
if (owner?.token === token) await rm3(file2, { force: true });
|
|
49510
49461
|
}
|
|
49511
|
-
async function withGuard(directory, action, signal) {
|
|
49512
|
-
const guard = await acquireGuard(directory, signal);
|
|
49462
|
+
async function withGuard(directory, options, action, signal) {
|
|
49463
|
+
const guard = await acquireGuard(directory, options, signal);
|
|
49513
49464
|
try {
|
|
49514
49465
|
return await action();
|
|
49515
49466
|
} finally {
|
|
49516
49467
|
await removeOwnedLock(guard.file, guard.token);
|
|
49517
49468
|
}
|
|
49518
49469
|
}
|
|
49519
|
-
async function
|
|
49470
|
+
async function acquireProcessLease(directory, options, signal) {
|
|
49520
49471
|
await mkdir4(directory, { recursive: true, mode: 448 });
|
|
49521
|
-
const file2 =
|
|
49472
|
+
const file2 = path4.join(directory, options.lockName);
|
|
49522
49473
|
for (; ; ) {
|
|
49523
49474
|
signal?.throwIfAborted();
|
|
49524
49475
|
const owner = newOwner();
|
|
@@ -49535,30 +49486,189 @@ async function acquireDevicePairingLock(directory, signal) {
|
|
|
49535
49486
|
}
|
|
49536
49487
|
const reclaimed = await withGuard(
|
|
49537
49488
|
directory,
|
|
49489
|
+
options,
|
|
49538
49490
|
async () => {
|
|
49539
|
-
if (!await lockIsStale(file2,
|
|
49540
|
-
return false;
|
|
49541
|
-
}
|
|
49491
|
+
if (!await lockIsStale(file2, options.maxAgeMs)) return false;
|
|
49542
49492
|
await rm3(file2, { force: true });
|
|
49543
49493
|
return true;
|
|
49544
49494
|
},
|
|
49545
49495
|
signal
|
|
49546
49496
|
);
|
|
49547
49497
|
if (reclaimed) continue;
|
|
49548
|
-
await delay(
|
|
49549
|
-
DEVICE_PAIRING_LOCK_POLL_MS,
|
|
49550
|
-
void 0,
|
|
49551
|
-
signal ? { signal } : void 0
|
|
49552
|
-
);
|
|
49498
|
+
await delay(options.pollMs, void 0, signal ? { signal } : void 0);
|
|
49553
49499
|
}
|
|
49554
49500
|
}
|
|
49555
|
-
async function
|
|
49556
|
-
const lock = await
|
|
49501
|
+
async function withProcessLease(action, options, signal, directory) {
|
|
49502
|
+
const lock = await acquireProcessLease(directory, options, signal);
|
|
49557
49503
|
try {
|
|
49558
49504
|
return await action();
|
|
49559
49505
|
} finally {
|
|
49560
|
-
await withGuard(
|
|
49506
|
+
await withGuard(
|
|
49507
|
+
directory,
|
|
49508
|
+
options,
|
|
49509
|
+
async () => await removeOwnedLock(lock.file, lock.token),
|
|
49510
|
+
signal
|
|
49511
|
+
);
|
|
49512
|
+
}
|
|
49513
|
+
}
|
|
49514
|
+
|
|
49515
|
+
// src/update-state.ts
|
|
49516
|
+
var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
49517
|
+
var UPDATE_STATE_LOCK_POLL_MS = 25;
|
|
49518
|
+
var UPDATE_STATE_LOCK_MAX_AGE_MS = 6e4;
|
|
49519
|
+
var UPDATE_STATE_GUARD_MAX_AGE_MS = 3e4;
|
|
49520
|
+
function defaultUpdateChannel(version2) {
|
|
49521
|
+
return version2.includes("-") ? "beta" : "stable";
|
|
49522
|
+
}
|
|
49523
|
+
function updateStateFile() {
|
|
49524
|
+
return path5.join(configDirectory(), "updates.json");
|
|
49525
|
+
}
|
|
49526
|
+
function isPolicy(value) {
|
|
49527
|
+
return value === "notify" || value === "auto" || value === "off";
|
|
49528
|
+
}
|
|
49529
|
+
function isChannel(value) {
|
|
49530
|
+
return value === "beta" || value === "stable";
|
|
49531
|
+
}
|
|
49532
|
+
function optionalString(value) {
|
|
49533
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
49534
|
+
}
|
|
49535
|
+
async function withUpdateStateLease(action, file2 = updateStateFile()) {
|
|
49536
|
+
return await withProcessLease(
|
|
49537
|
+
action,
|
|
49538
|
+
{
|
|
49539
|
+
lockName: `${path5.basename(file2)}.lock`,
|
|
49540
|
+
pollMs: UPDATE_STATE_LOCK_POLL_MS,
|
|
49541
|
+
maxAgeMs: UPDATE_STATE_LOCK_MAX_AGE_MS,
|
|
49542
|
+
guardMaxAgeMs: UPDATE_STATE_GUARD_MAX_AGE_MS
|
|
49543
|
+
},
|
|
49544
|
+
void 0,
|
|
49545
|
+
path5.dirname(file2)
|
|
49546
|
+
);
|
|
49547
|
+
}
|
|
49548
|
+
async function loadUpdateState(currentVersion, file2 = updateStateFile()) {
|
|
49549
|
+
const defaults = {
|
|
49550
|
+
policy: "notify",
|
|
49551
|
+
channel: defaultUpdateChannel(currentVersion)
|
|
49552
|
+
};
|
|
49553
|
+
try {
|
|
49554
|
+
const parsed = JSON.parse(await readFile4(file2, "utf8"));
|
|
49555
|
+
const lastCheckedAt = optionalString(parsed.lastCheckedAt);
|
|
49556
|
+
const mcpContractVersion = optionalString(parsed.mcpContractVersion);
|
|
49557
|
+
return {
|
|
49558
|
+
policy: isPolicy(parsed.policy) ? parsed.policy : defaults.policy,
|
|
49559
|
+
channel: isChannel(parsed.channel) ? parsed.channel : defaults.channel,
|
|
49560
|
+
...lastCheckedAt ? { lastCheckedAt } : {},
|
|
49561
|
+
...mcpContractVersion ? { mcpContractVersion } : {}
|
|
49562
|
+
};
|
|
49563
|
+
} catch (error46) {
|
|
49564
|
+
if (error46.code === "ENOENT" || error46 instanceof SyntaxError) {
|
|
49565
|
+
return defaults;
|
|
49566
|
+
}
|
|
49567
|
+
throw error46;
|
|
49568
|
+
}
|
|
49569
|
+
}
|
|
49570
|
+
async function saveUpdateState(state, file2) {
|
|
49571
|
+
const directory = path5.dirname(file2);
|
|
49572
|
+
const temporary = `${file2}.${process.pid}.tmp`;
|
|
49573
|
+
await mkdir5(directory, { recursive: true, mode: 448 });
|
|
49574
|
+
try {
|
|
49575
|
+
await writeFile5(temporary, `${JSON.stringify(state, null, 2)}
|
|
49576
|
+
`, {
|
|
49577
|
+
encoding: "utf8",
|
|
49578
|
+
mode: 384
|
|
49579
|
+
});
|
|
49580
|
+
if (process.platform !== "win32") await chmod2(temporary, 384);
|
|
49581
|
+
await rename(temporary, file2);
|
|
49582
|
+
} finally {
|
|
49583
|
+
await rm4(temporary, { force: true });
|
|
49584
|
+
}
|
|
49585
|
+
}
|
|
49586
|
+
async function configureUpdates(currentVersion, changes, file2 = updateStateFile()) {
|
|
49587
|
+
return await withUpdateStateLease(async () => {
|
|
49588
|
+
const previous = await loadUpdateState(currentVersion, file2);
|
|
49589
|
+
const state = {
|
|
49590
|
+
policy: changes.policy ?? previous.policy,
|
|
49591
|
+
channel: changes.channel ?? previous.channel,
|
|
49592
|
+
...previous.mcpContractVersion ? { mcpContractVersion: previous.mcpContractVersion } : {}
|
|
49593
|
+
};
|
|
49594
|
+
await saveUpdateState(state, file2);
|
|
49595
|
+
return state;
|
|
49596
|
+
}, file2);
|
|
49597
|
+
}
|
|
49598
|
+
async function recordUpdateCheck(currentVersion, checkedAt = /* @__PURE__ */ new Date(), file2 = updateStateFile()) {
|
|
49599
|
+
return await withUpdateStateLease(async () => {
|
|
49600
|
+
const state = {
|
|
49601
|
+
...await loadUpdateState(currentVersion, file2),
|
|
49602
|
+
lastCheckedAt: checkedAt.toISOString()
|
|
49603
|
+
};
|
|
49604
|
+
await saveUpdateState(state, file2);
|
|
49605
|
+
return state;
|
|
49606
|
+
}, file2);
|
|
49607
|
+
}
|
|
49608
|
+
async function observeMcpContractVersion(currentVersion, mcpContractVersion, file2 = updateStateFile()) {
|
|
49609
|
+
return await withUpdateStateLease(async () => {
|
|
49610
|
+
const previous = await loadUpdateState(currentVersion, file2);
|
|
49611
|
+
if (previous.mcpContractVersion === mcpContractVersion) return false;
|
|
49612
|
+
await saveUpdateState({ ...previous, mcpContractVersion }, file2);
|
|
49613
|
+
return previous.mcpContractVersion !== void 0;
|
|
49614
|
+
}, file2);
|
|
49615
|
+
}
|
|
49616
|
+
function isUpdateCheckDue(lastCheckedAt, now = Date.now()) {
|
|
49617
|
+
if (!lastCheckedAt) return true;
|
|
49618
|
+
const checkedAt = Date.parse(lastCheckedAt);
|
|
49619
|
+
return !Number.isFinite(checkedAt) || now - checkedAt >= UPDATE_CHECK_INTERVAL_MS;
|
|
49620
|
+
}
|
|
49621
|
+
|
|
49622
|
+
// src/device-store.ts
|
|
49623
|
+
import path6 from "node:path";
|
|
49624
|
+
var FILE_DEVICE_WARNING = "Warning: the operating-system credential store is unavailable. Glossa is using a mode-0600 device credential file.";
|
|
49625
|
+
function parseDeviceCredential(value) {
|
|
49626
|
+
let parsed;
|
|
49627
|
+
try {
|
|
49628
|
+
parsed = JSON.parse(value);
|
|
49629
|
+
} catch {
|
|
49630
|
+
throw new Error("Stored Glossa device credentials are invalid.");
|
|
49631
|
+
}
|
|
49632
|
+
let relayOriginValid = false;
|
|
49633
|
+
if (typeof parsed.relayOrigin === "string") {
|
|
49634
|
+
try {
|
|
49635
|
+
relayOriginValid = new URL(parsed.relayOrigin).origin === parsed.relayOrigin;
|
|
49636
|
+
} catch {
|
|
49637
|
+
relayOriginValid = false;
|
|
49638
|
+
}
|
|
49639
|
+
}
|
|
49640
|
+
if (!relayOriginValid || typeof parsed.deviceId !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
|
49641
|
+
parsed.deviceId
|
|
49642
|
+
) || typeof parsed.deviceName !== "string" || parsed.deviceName.length === 0 || parsed.accountSubject !== void 0 && (typeof parsed.accountSubject !== "string" || parsed.accountSubject.length === 0) || typeof parsed.token !== "string" || !parsed.token.startsWith(`gld_${parsed.deviceId}_`)) {
|
|
49643
|
+
throw new Error("Stored Glossa device credentials are invalid.");
|
|
49561
49644
|
}
|
|
49645
|
+
return parsed;
|
|
49646
|
+
}
|
|
49647
|
+
var store = new SecureStore({
|
|
49648
|
+
account: "device",
|
|
49649
|
+
file: path6.join(configDirectory(), "device.json"),
|
|
49650
|
+
warning: FILE_DEVICE_WARNING,
|
|
49651
|
+
parse: parseDeviceCredential
|
|
49652
|
+
});
|
|
49653
|
+
async function loadDeviceCredential() {
|
|
49654
|
+
return (await store.load())?.value ?? null;
|
|
49655
|
+
}
|
|
49656
|
+
async function saveDeviceCredential(credential) {
|
|
49657
|
+
await store.save(credential);
|
|
49658
|
+
}
|
|
49659
|
+
async function deleteDeviceCredential() {
|
|
49660
|
+
await store.delete();
|
|
49661
|
+
}
|
|
49662
|
+
|
|
49663
|
+
// src/device-pairing-lock.ts
|
|
49664
|
+
var DEVICE_PAIRING_LEASE = {
|
|
49665
|
+
lockName: "device-pairing.lock",
|
|
49666
|
+
pollMs: 100,
|
|
49667
|
+
maxAgeMs: 6 * 6e4,
|
|
49668
|
+
guardMaxAgeMs: 3e4
|
|
49669
|
+
};
|
|
49670
|
+
async function withDevicePairingLease(action, signal, directory = updateRuntimeDirectory()) {
|
|
49671
|
+
return await withProcessLease(action, DEVICE_PAIRING_LEASE, signal, directory);
|
|
49562
49672
|
}
|
|
49563
49673
|
|
|
49564
49674
|
// src/device-pairing.ts
|
|
@@ -50208,27 +50318,27 @@ var CommandService = class {
|
|
|
50208
50318
|
// src/worker/file-service.ts
|
|
50209
50319
|
import { createHash, randomUUID as randomUUID4 } from "node:crypto";
|
|
50210
50320
|
import {
|
|
50211
|
-
chmod as
|
|
50321
|
+
chmod as chmod3,
|
|
50212
50322
|
link as link2,
|
|
50213
50323
|
lstat as lstat2,
|
|
50214
|
-
mkdir as
|
|
50324
|
+
mkdir as mkdir6,
|
|
50215
50325
|
opendir,
|
|
50216
50326
|
open,
|
|
50217
|
-
readFile as
|
|
50218
|
-
rename,
|
|
50219
|
-
rm as
|
|
50327
|
+
readFile as readFile5,
|
|
50328
|
+
rename as rename2,
|
|
50329
|
+
rm as rm5,
|
|
50220
50330
|
rmdir,
|
|
50221
50331
|
stat as stat3,
|
|
50222
|
-
writeFile as
|
|
50332
|
+
writeFile as writeFile6
|
|
50223
50333
|
} from "node:fs/promises";
|
|
50224
|
-
import
|
|
50334
|
+
import path8 from "node:path";
|
|
50225
50335
|
import { performance as performance2 } from "node:perf_hooks";
|
|
50226
50336
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
50227
50337
|
|
|
50228
50338
|
// src/worker/path-policy.ts
|
|
50229
50339
|
import { lstat, realpath, stat as stat2 } from "node:fs/promises";
|
|
50230
50340
|
import os5 from "node:os";
|
|
50231
|
-
import
|
|
50341
|
+
import path7 from "node:path";
|
|
50232
50342
|
function samePath(left, right) {
|
|
50233
50343
|
return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
50234
50344
|
}
|
|
@@ -50240,15 +50350,15 @@ function accountHomeDirectory() {
|
|
|
50240
50350
|
}
|
|
50241
50351
|
}
|
|
50242
50352
|
function isWithin(root, candidate) {
|
|
50243
|
-
const relative =
|
|
50244
|
-
return relative === "" || !relative.startsWith(`..${
|
|
50353
|
+
const relative = path7.relative(root, candidate);
|
|
50354
|
+
return relative === "" || !relative.startsWith(`..${path7.sep}`) && relative !== ".." && !path7.isAbsolute(relative);
|
|
50245
50355
|
}
|
|
50246
50356
|
function validateRelativePath(value) {
|
|
50247
50357
|
if (value.includes("\0")) {
|
|
50248
50358
|
throw new WorkerError("invalid_path", "Paths cannot contain null bytes.");
|
|
50249
50359
|
}
|
|
50250
50360
|
const explicitNativePosixPath = process.platform !== "win32" && value.startsWith("./");
|
|
50251
|
-
if (
|
|
50361
|
+
if (path7.isAbsolute(value) || path7.posix.isAbsolute(value) || !explicitNativePosixPath && path7.win32.isAbsolute(value)) {
|
|
50252
50362
|
throw new WorkerError("absolute_path", "Absolute paths are not allowed.");
|
|
50253
50363
|
}
|
|
50254
50364
|
const segments = explicitNativePosixPath ? value.split(/\/+/).filter(Boolean) : value.split(/[\\/]+/);
|
|
@@ -50258,7 +50368,7 @@ function validateRelativePath(value) {
|
|
|
50258
50368
|
return value === "" ? "." : value;
|
|
50259
50369
|
}
|
|
50260
50370
|
async function canonicalizeRoot(candidate) {
|
|
50261
|
-
const root = await realpath(
|
|
50371
|
+
const root = await realpath(path7.resolve(candidate)).catch((error46) => {
|
|
50262
50372
|
if (error46.code === "ENOENT") {
|
|
50263
50373
|
throw new WorkerError("root_not_found", "The workspace directory does not exist.");
|
|
50264
50374
|
}
|
|
@@ -50268,10 +50378,10 @@ async function canonicalizeRoot(candidate) {
|
|
|
50268
50378
|
if (!rootStat.isDirectory()) {
|
|
50269
50379
|
throw new WorkerError("root_not_directory", "The exposed root must be a directory.");
|
|
50270
50380
|
}
|
|
50271
|
-
const filesystemRoot =
|
|
50381
|
+
const filesystemRoot = path7.parse(root).root;
|
|
50272
50382
|
const homes = await Promise.all(
|
|
50273
50383
|
[os5.homedir(), accountHomeDirectory()].map(
|
|
50274
|
-
async (home) => await realpath(home).catch(() =>
|
|
50384
|
+
async (home) => await realpath(home).catch(() => path7.resolve(home))
|
|
50275
50385
|
)
|
|
50276
50386
|
);
|
|
50277
50387
|
const isHomeDirectory = homes.some((home) => samePath(root, home));
|
|
@@ -50307,7 +50417,7 @@ var PathPolicy = class _PathPolicy {
|
|
|
50307
50417
|
return canonical;
|
|
50308
50418
|
}
|
|
50309
50419
|
async resolveDiscoveredExisting(candidate) {
|
|
50310
|
-
const lexical =
|
|
50420
|
+
const lexical = path7.resolve(candidate);
|
|
50311
50421
|
if (!isWithin(this.root, lexical)) {
|
|
50312
50422
|
throw new WorkerError("path_escape", "The requested path escapes the exposed root.");
|
|
50313
50423
|
}
|
|
@@ -50325,7 +50435,7 @@ var PathPolicy = class _PathPolicy {
|
|
|
50325
50435
|
}
|
|
50326
50436
|
async resolveWritableFile(relativePath) {
|
|
50327
50437
|
const lexical = this.resolveLexical(relativePath);
|
|
50328
|
-
const parent =
|
|
50438
|
+
const parent = path7.dirname(lexical);
|
|
50329
50439
|
await this.rejectLinkedComponents(parent);
|
|
50330
50440
|
const canonicalParent = await realpath(parent).catch((error46) => {
|
|
50331
50441
|
if (error46.code === "ENOENT") {
|
|
@@ -50356,7 +50466,7 @@ var PathPolicy = class _PathPolicy {
|
|
|
50356
50466
|
if (error46 instanceof WorkerError) throw error46;
|
|
50357
50467
|
if (error46.code !== "ENOENT") throw error46;
|
|
50358
50468
|
}
|
|
50359
|
-
return
|
|
50469
|
+
return path7.join(canonicalParent, path7.basename(lexical));
|
|
50360
50470
|
}
|
|
50361
50471
|
async resolveWritableDirectory(relativePath, recursive) {
|
|
50362
50472
|
const lexical = this.resolveLexical(relativePath);
|
|
@@ -50379,7 +50489,7 @@ var PathPolicy = class _PathPolicy {
|
|
|
50379
50489
|
if (error46.code !== "ENOENT") throw error46;
|
|
50380
50490
|
}
|
|
50381
50491
|
if (!recursive) {
|
|
50382
|
-
const parent =
|
|
50492
|
+
const parent = path7.dirname(lexical);
|
|
50383
50493
|
await this.rejectLinkedComponents(parent);
|
|
50384
50494
|
const canonicalParent = await realpath(parent).catch(
|
|
50385
50495
|
(error46) => {
|
|
@@ -50399,11 +50509,11 @@ var PathPolicy = class _PathPolicy {
|
|
|
50399
50509
|
throw new WorkerError("not_directory", "The destination parent is not a directory.");
|
|
50400
50510
|
}
|
|
50401
50511
|
return {
|
|
50402
|
-
target:
|
|
50512
|
+
target: path7.join(canonicalParent, path7.basename(lexical)),
|
|
50403
50513
|
exists: false
|
|
50404
50514
|
};
|
|
50405
50515
|
}
|
|
50406
|
-
let existingAncestor =
|
|
50516
|
+
let existingAncestor = path7.dirname(lexical);
|
|
50407
50517
|
while (!samePath(existingAncestor, this.root)) {
|
|
50408
50518
|
try {
|
|
50409
50519
|
await this.rejectLinkedComponents(existingAncestor);
|
|
@@ -50415,9 +50525,9 @@ var PathPolicy = class _PathPolicy {
|
|
|
50415
50525
|
throw new WorkerError("not_directory", "The destination parent is not a directory.");
|
|
50416
50526
|
}
|
|
50417
50527
|
return {
|
|
50418
|
-
target:
|
|
50528
|
+
target: path7.join(
|
|
50419
50529
|
canonicalAncestor,
|
|
50420
|
-
|
|
50530
|
+
path7.relative(existingAncestor, lexical)
|
|
50421
50531
|
),
|
|
50422
50532
|
exists: false
|
|
50423
50533
|
};
|
|
@@ -50425,13 +50535,13 @@ var PathPolicy = class _PathPolicy {
|
|
|
50425
50535
|
if (error46 instanceof WorkerError) throw error46;
|
|
50426
50536
|
if (error46.code !== "ENOENT") throw error46;
|
|
50427
50537
|
}
|
|
50428
|
-
existingAncestor =
|
|
50538
|
+
existingAncestor = path7.dirname(existingAncestor);
|
|
50429
50539
|
}
|
|
50430
50540
|
return { target: lexical, exists: false };
|
|
50431
50541
|
}
|
|
50432
50542
|
async resolveVacantPath(relativePath) {
|
|
50433
50543
|
const lexical = this.resolveLexical(relativePath);
|
|
50434
|
-
const parent =
|
|
50544
|
+
const parent = path7.dirname(lexical);
|
|
50435
50545
|
await this.rejectLinkedComponents(parent);
|
|
50436
50546
|
const canonicalParent = await realpath(parent).catch(
|
|
50437
50547
|
(error46) => {
|
|
@@ -50460,11 +50570,11 @@ var PathPolicy = class _PathPolicy {
|
|
|
50460
50570
|
if (error46 instanceof WorkerError) throw error46;
|
|
50461
50571
|
if (error46.code !== "ENOENT") throw error46;
|
|
50462
50572
|
}
|
|
50463
|
-
return
|
|
50573
|
+
return path7.join(canonicalParent, path7.basename(lexical));
|
|
50464
50574
|
}
|
|
50465
50575
|
resolveLexical(relativePath) {
|
|
50466
50576
|
const validated = validateRelativePath(relativePath);
|
|
50467
|
-
const candidate =
|
|
50577
|
+
const candidate = path7.resolve(this.root, validated);
|
|
50468
50578
|
if (!isWithin(this.root, candidate)) {
|
|
50469
50579
|
throw new WorkerError("path_escape", "The requested path escapes the exposed root.");
|
|
50470
50580
|
}
|
|
@@ -50474,11 +50584,11 @@ var PathPolicy = class _PathPolicy {
|
|
|
50474
50584
|
if (!isWithin(this.root, candidate)) {
|
|
50475
50585
|
throw new WorkerError("path_escape", "The requested path escapes the exposed root.");
|
|
50476
50586
|
}
|
|
50477
|
-
const relative =
|
|
50587
|
+
const relative = path7.relative(this.root, candidate);
|
|
50478
50588
|
if (!relative) return;
|
|
50479
50589
|
let current = this.root;
|
|
50480
|
-
for (const segment of relative.split(
|
|
50481
|
-
current =
|
|
50590
|
+
for (const segment of relative.split(path7.sep)) {
|
|
50591
|
+
current = path7.join(current, segment);
|
|
50482
50592
|
try {
|
|
50483
50593
|
const currentStat = await lstat(current);
|
|
50484
50594
|
if (currentStat.isSymbolicLink()) {
|
|
@@ -50513,12 +50623,12 @@ function imageMimeType(content) {
|
|
|
50513
50623
|
return void 0;
|
|
50514
50624
|
}
|
|
50515
50625
|
function isPathWithin(root, candidate) {
|
|
50516
|
-
const relative =
|
|
50517
|
-
return relative === "" || !relative.startsWith(`..${
|
|
50626
|
+
const relative = path8.relative(root, candidate);
|
|
50627
|
+
return relative === "" || !relative.startsWith(`..${path8.sep}`) && relative !== ".." && !path8.isAbsolute(relative);
|
|
50518
50628
|
}
|
|
50519
50629
|
var fileWriteTails = /* @__PURE__ */ new Map();
|
|
50520
50630
|
async function withFileWriteLock(target, operation) {
|
|
50521
|
-
const normalized =
|
|
50631
|
+
const normalized = path8.normalize(target);
|
|
50522
50632
|
const key = process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
50523
50633
|
const predecessor = fileWriteTails.get(key);
|
|
50524
50634
|
let release;
|
|
@@ -50535,7 +50645,7 @@ async function withFileWriteLock(target, operation) {
|
|
|
50535
50645
|
}
|
|
50536
50646
|
}
|
|
50537
50647
|
async function withFileWriteLocks(targets, operation) {
|
|
50538
|
-
const unique = [...new Set(targets.map((target) =>
|
|
50648
|
+
const unique = [...new Set(targets.map((target) => path8.normalize(target)))].sort(
|
|
50539
50649
|
(left, right) => left.localeCompare(right)
|
|
50540
50650
|
);
|
|
50541
50651
|
const run = async (index) => {
|
|
@@ -50547,7 +50657,7 @@ async function withFileWriteLocks(targets, operation) {
|
|
|
50547
50657
|
async function requireRevision(target, expectedSha256) {
|
|
50548
50658
|
let actual = null;
|
|
50549
50659
|
try {
|
|
50550
|
-
actual = sha256(await
|
|
50660
|
+
actual = sha256(await readFile5(target));
|
|
50551
50661
|
} catch (error46) {
|
|
50552
50662
|
if (error46.code !== "ENOENT") throw error46;
|
|
50553
50663
|
}
|
|
@@ -50571,7 +50681,7 @@ function compareNames(left, right) {
|
|
|
50571
50681
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
50572
50682
|
}
|
|
50573
50683
|
function relativeSortKey(root, target) {
|
|
50574
|
-
const relative =
|
|
50684
|
+
const relative = path8.relative(root, target);
|
|
50575
50685
|
if (!relative) return ".";
|
|
50576
50686
|
return process.platform === "win32" ? relative.replaceAll("\\", "/") : relative;
|
|
50577
50687
|
}
|
|
@@ -50992,7 +51102,7 @@ var FileService = class {
|
|
|
50992
51102
|
if (batch.overflow) throw scanLimitError();
|
|
50993
51103
|
scannedEntries += batch.children.length;
|
|
50994
51104
|
for (const child of batch.children) {
|
|
50995
|
-
const target =
|
|
51105
|
+
const target = path8.join(directory, child.name);
|
|
50996
51106
|
heapPush(frontier, {
|
|
50997
51107
|
target,
|
|
50998
51108
|
sortKey: relativeSortKey(this.policy.root, target),
|
|
@@ -51016,7 +51126,7 @@ var FileService = class {
|
|
|
51016
51126
|
throw scanLimitError();
|
|
51017
51127
|
}
|
|
51018
51128
|
scannedEntries += 1;
|
|
51019
|
-
const target =
|
|
51129
|
+
const target = path8.join(directory, child.name);
|
|
51020
51130
|
let childStat;
|
|
51021
51131
|
try {
|
|
51022
51132
|
childStat = await this.#withinDeadline(
|
|
@@ -51168,7 +51278,7 @@ var FileService = class {
|
|
|
51168
51278
|
if (!patterns) return false;
|
|
51169
51279
|
const normalized = relativePath.replaceAll("\\", "/");
|
|
51170
51280
|
try {
|
|
51171
|
-
return patterns.some((pattern) =>
|
|
51281
|
+
return patterns.some((pattern) => path8.posix.matchesGlob(normalized, pattern));
|
|
51172
51282
|
} catch {
|
|
51173
51283
|
throw new WorkerError("invalid_search", "Search glob pattern is invalid.");
|
|
51174
51284
|
}
|
|
@@ -51197,7 +51307,7 @@ var FileService = class {
|
|
|
51197
51307
|
const searchFile = async (target) => {
|
|
51198
51308
|
const relative = displayPath(this.policy.root, target);
|
|
51199
51309
|
if (extensions && !extensions.some(
|
|
51200
|
-
(extension) =>
|
|
51310
|
+
(extension) => path8.basename(target).toLowerCase().endsWith(extension)
|
|
51201
51311
|
)) {
|
|
51202
51312
|
return false;
|
|
51203
51313
|
}
|
|
@@ -51292,7 +51402,7 @@ var FileService = class {
|
|
|
51292
51402
|
scannedEntries += batch.children.length;
|
|
51293
51403
|
for (const child of batch.children) {
|
|
51294
51404
|
this.#assertBeforeDeadline(deadlineAt);
|
|
51295
|
-
const target =
|
|
51405
|
+
const target = path8.join(directory, child.name);
|
|
51296
51406
|
let targetType;
|
|
51297
51407
|
if (this.#trustDirectoryEntryTypes) {
|
|
51298
51408
|
if (child.isSymbolicLink()) {
|
|
@@ -51440,7 +51550,7 @@ var FileService = class {
|
|
|
51440
51550
|
);
|
|
51441
51551
|
if (current.exists) return { created: false };
|
|
51442
51552
|
try {
|
|
51443
|
-
await
|
|
51553
|
+
await mkdir6(current.target, { recursive });
|
|
51444
51554
|
} catch (error46) {
|
|
51445
51555
|
if (error46.code !== "EEXIST") throw error46;
|
|
51446
51556
|
}
|
|
@@ -51477,12 +51587,12 @@ var FileService = class {
|
|
|
51477
51587
|
try {
|
|
51478
51588
|
if (targetStat.isDirectory()) {
|
|
51479
51589
|
if (recursive) {
|
|
51480
|
-
await
|
|
51590
|
+
await rm5(target, { recursive: true, force: false });
|
|
51481
51591
|
} else {
|
|
51482
51592
|
await rmdir(target);
|
|
51483
51593
|
}
|
|
51484
51594
|
} else {
|
|
51485
|
-
await
|
|
51595
|
+
await rm5(target, { force: false });
|
|
51486
51596
|
}
|
|
51487
51597
|
} catch (error46) {
|
|
51488
51598
|
const code = error46.code;
|
|
@@ -51532,7 +51642,7 @@ var FileService = class {
|
|
|
51532
51642
|
"A directory cannot be moved inside itself."
|
|
51533
51643
|
);
|
|
51534
51644
|
}
|
|
51535
|
-
await
|
|
51645
|
+
await rename2(source, destination);
|
|
51536
51646
|
return {
|
|
51537
51647
|
movedType: sourceStat.isDirectory() ? "directory" : "file"
|
|
51538
51648
|
};
|
|
@@ -51602,20 +51712,20 @@ var FileService = class {
|
|
|
51602
51712
|
);
|
|
51603
51713
|
}
|
|
51604
51714
|
if (expectedSha256) await requireRevision(target, expectedSha256);
|
|
51605
|
-
const temporary =
|
|
51715
|
+
const temporary = path8.join(path8.dirname(target), `.glossa-${randomUUID4()}.tmp`);
|
|
51606
51716
|
try {
|
|
51607
|
-
await
|
|
51717
|
+
await writeFile6(temporary, bytes, { flag: "wx", mode: 384 });
|
|
51608
51718
|
target = await this.policy.resolveWritableFile(relativePath);
|
|
51609
51719
|
const tempStat = await lstat2(temporary);
|
|
51610
51720
|
if (!tempStat.isFile() || tempStat.isSymbolicLink()) {
|
|
51611
51721
|
throw new WorkerError("unsafe_temporary_file", "The atomic write temporary file changed.");
|
|
51612
51722
|
}
|
|
51613
51723
|
if (existingMode !== void 0 && process.platform !== "win32") {
|
|
51614
|
-
await
|
|
51724
|
+
await chmod3(temporary, existingMode);
|
|
51615
51725
|
}
|
|
51616
51726
|
if (expectedSha256) {
|
|
51617
51727
|
await requireRevision(target, expectedSha256);
|
|
51618
|
-
await
|
|
51728
|
+
await rename2(temporary, target);
|
|
51619
51729
|
} else {
|
|
51620
51730
|
try {
|
|
51621
51731
|
await link2(temporary, target);
|
|
@@ -51630,7 +51740,7 @@ var FileService = class {
|
|
|
51630
51740
|
}
|
|
51631
51741
|
}
|
|
51632
51742
|
} finally {
|
|
51633
|
-
await
|
|
51743
|
+
await rm5(temporary, { force: true });
|
|
51634
51744
|
}
|
|
51635
51745
|
return { sha256: sha256(bytes), bytes: bytes.byteLength };
|
|
51636
51746
|
});
|
|
@@ -52016,7 +52126,8 @@ var RemoteWorker = class {
|
|
|
52016
52126
|
registeredSession = session;
|
|
52017
52127
|
this.#onStatus({
|
|
52018
52128
|
state: "connected",
|
|
52019
|
-
reconnected: connectedBefore
|
|
52129
|
+
reconnected: connectedBefore,
|
|
52130
|
+
...session.mcpContractVersion ? { mcpContractVersion: session.mcpContractVersion } : {}
|
|
52020
52131
|
});
|
|
52021
52132
|
connectedBefore = true;
|
|
52022
52133
|
failures = 0;
|
|
@@ -52087,10 +52198,12 @@ var RemoteWorker = class {
|
|
|
52087
52198
|
if (typeof value !== "object" || value === null || !("generation" in value) || typeof value.generation !== "string" || !("workerId" in value) || value.workerId !== this.#workerId || !("workerToken" in value) || !("accessProfile" in value) || value.accessProfile !== this.#accessProfile || !acceptsCapabilities(value, imageReads) || this.#workspaceLabel !== void 0 && (!("workspaceLabel" in value) || value.workspaceLabel !== this.#workspaceLabel)) {
|
|
52088
52199
|
throw new RelayProtocolUnsupportedError();
|
|
52089
52200
|
}
|
|
52201
|
+
const mcpContractVersion = "mcpContractVersion" in value && typeof value.mcpContractVersion === "string" && value.mcpContractVersion.length > 0 && value.mcpContractVersion.length <= 32 ? value.mcpContractVersion : void 0;
|
|
52090
52202
|
return {
|
|
52091
52203
|
generation: value.generation,
|
|
52092
52204
|
workerToken: requiredWorkerToken(value.workerToken),
|
|
52093
|
-
imageReads
|
|
52205
|
+
imageReads,
|
|
52206
|
+
...mcpContractVersion ? { mcpContractVersion } : {}
|
|
52094
52207
|
};
|
|
52095
52208
|
}
|
|
52096
52209
|
async #pollGeneration(session) {
|
|
@@ -52315,6 +52428,196 @@ function activityResultLabel(job, result) {
|
|
|
52315
52428
|
}
|
|
52316
52429
|
return `${job.type} completed`;
|
|
52317
52430
|
}
|
|
52431
|
+
var MAX_ACTIVITY_OUTPUT_CHARS = 512;
|
|
52432
|
+
var OUTPUT_TRUNCATION_MARKER = "\u2026 output truncated \u2026";
|
|
52433
|
+
function isRecord(value) {
|
|
52434
|
+
return typeof value === "object" && value !== null;
|
|
52435
|
+
}
|
|
52436
|
+
function escapeActivityOutputControls(text) {
|
|
52437
|
+
let escaped = "";
|
|
52438
|
+
for (const character of text) {
|
|
52439
|
+
const code = character.codePointAt(0);
|
|
52440
|
+
if (character === "\n") {
|
|
52441
|
+
escaped += character;
|
|
52442
|
+
} else if (code < 32 || code === 127 || code >= 8234 && code <= 8238 || code >= 8294 && code <= 8297) {
|
|
52443
|
+
escaped += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
52444
|
+
} else {
|
|
52445
|
+
escaped += character;
|
|
52446
|
+
}
|
|
52447
|
+
}
|
|
52448
|
+
return escaped;
|
|
52449
|
+
}
|
|
52450
|
+
function boundedActivityPreview(text, sourceTruncated = false) {
|
|
52451
|
+
const normalized = text.replaceAll("\r\n", "\n").trimEnd();
|
|
52452
|
+
if (containsRestrictedAuthenticationData(normalized)) {
|
|
52453
|
+
return { preview: "[restricted output blocked]" };
|
|
52454
|
+
}
|
|
52455
|
+
const safe = escapeActivityOutputControls(normalized);
|
|
52456
|
+
if (!safe) return sourceTruncated ? { preview: OUTPUT_TRUNCATION_MARKER, truncated: true } : {};
|
|
52457
|
+
const characters = Array.from(safe);
|
|
52458
|
+
if (characters.length <= MAX_ACTIVITY_OUTPUT_CHARS && (!sourceTruncated || characters.length + OUTPUT_TRUNCATION_MARKER.length + 1 <= MAX_ACTIVITY_OUTPUT_CHARS)) {
|
|
52459
|
+
return sourceTruncated ? { preview: `${safe}
|
|
52460
|
+
${OUTPUT_TRUNCATION_MARKER}`, truncated: true } : { preview: safe };
|
|
52461
|
+
}
|
|
52462
|
+
const marker = `
|
|
52463
|
+
${OUTPUT_TRUNCATION_MARKER}
|
|
52464
|
+
`;
|
|
52465
|
+
const remaining = Math.max(2, MAX_ACTIVITY_OUTPUT_CHARS - marker.length);
|
|
52466
|
+
const headLength = Math.floor(remaining * 0.7);
|
|
52467
|
+
const tailLength = remaining - headLength;
|
|
52468
|
+
return {
|
|
52469
|
+
preview: `${characters.slice(0, headLength).join("")}${marker}${characters.slice(-tailLength).join("")}`,
|
|
52470
|
+
truncated: true
|
|
52471
|
+
};
|
|
52472
|
+
}
|
|
52473
|
+
function formatOutputBytes(bytes) {
|
|
52474
|
+
if (typeof bytes !== "number" || !Number.isFinite(bytes) || bytes < 0) return void 0;
|
|
52475
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
52476
|
+
const kibibytes = bytes / 1024;
|
|
52477
|
+
if (kibibytes < 1024) return `${kibibytes.toFixed(kibibytes < 10 ? 1 : 0)} KiB`;
|
|
52478
|
+
return `${(kibibytes / 1024).toFixed(1)} MiB`;
|
|
52479
|
+
}
|
|
52480
|
+
function activitySuccess(preview, sourceTruncated = false) {
|
|
52481
|
+
return {
|
|
52482
|
+
kind: "success",
|
|
52483
|
+
...boundedActivityPreview(preview, sourceTruncated)
|
|
52484
|
+
};
|
|
52485
|
+
}
|
|
52486
|
+
function commandActivityOutput(value) {
|
|
52487
|
+
if (!isRecord(value) || typeof value.status !== "string") return void 0;
|
|
52488
|
+
const status = value.status;
|
|
52489
|
+
let kind;
|
|
52490
|
+
let fallback;
|
|
52491
|
+
if (status === "running") {
|
|
52492
|
+
kind = "running";
|
|
52493
|
+
fallback = "Command started and is still running.";
|
|
52494
|
+
} else if (status === "succeeded") {
|
|
52495
|
+
kind = "success";
|
|
52496
|
+
fallback = "Command completed successfully.";
|
|
52497
|
+
} else if (status === "canceled") {
|
|
52498
|
+
kind = "success";
|
|
52499
|
+
fallback = "Command canceled.";
|
|
52500
|
+
} else if (status === "timed_out") {
|
|
52501
|
+
kind = "error";
|
|
52502
|
+
fallback = "Command timed out.";
|
|
52503
|
+
} else if (status === "failed") {
|
|
52504
|
+
kind = "error";
|
|
52505
|
+
fallback = typeof value.exitCode === "number" ? `Command failed with exit code ${value.exitCode}.` : "Command failed.";
|
|
52506
|
+
} else {
|
|
52507
|
+
return void 0;
|
|
52508
|
+
}
|
|
52509
|
+
const stdout = typeof value.stdout === "string" ? value.stdout : "";
|
|
52510
|
+
const stderr = typeof value.stderr === "string" ? value.stderr : "";
|
|
52511
|
+
const preferError = kind === "error";
|
|
52512
|
+
const previewText = preferError ? stderr || stdout : stdout || stderr;
|
|
52513
|
+
const sourceTruncated = previewText === stderr ? value.stderrTruncated === true : value.stdoutTruncated === true;
|
|
52514
|
+
return {
|
|
52515
|
+
kind,
|
|
52516
|
+
...boundedActivityPreview(previewText || fallback, sourceTruncated)
|
|
52517
|
+
};
|
|
52518
|
+
}
|
|
52519
|
+
function listFilesActivityOutput(value) {
|
|
52520
|
+
if (!isRecord(value) || !Array.isArray(value.entries)) return void 0;
|
|
52521
|
+
const lines = value.entries.flatMap((entry) => {
|
|
52522
|
+
if (!isRecord(entry) || typeof entry.path !== "string") return [];
|
|
52523
|
+
const suffix = entry.type === "directory" ? "/" : formatOutputBytes(entry.bytes) ? ` \xB7 ${formatOutputBytes(entry.bytes)}` : "";
|
|
52524
|
+
return [`${entry.path}${suffix}`];
|
|
52525
|
+
});
|
|
52526
|
+
return activitySuccess(
|
|
52527
|
+
lines.length > 0 ? lines.join("\n") : "No entries.",
|
|
52528
|
+
value.truncated === true
|
|
52529
|
+
);
|
|
52530
|
+
}
|
|
52531
|
+
function searchTextActivityOutput(value) {
|
|
52532
|
+
if (!isRecord(value) || !Array.isArray(value.matches)) return void 0;
|
|
52533
|
+
const lines = value.matches.flatMap((match) => {
|
|
52534
|
+
if (!isRecord(match) || typeof match.path !== "string" || typeof match.line !== "number" || typeof match.column !== "number" || typeof match.text !== "string") return [];
|
|
52535
|
+
return [`${match.path}:${match.line}:${match.column} ${match.text}${match.lineTruncated === true ? " \u2026" : ""}`];
|
|
52536
|
+
});
|
|
52537
|
+
return activitySuccess(
|
|
52538
|
+
lines.length > 0 ? lines.join("\n") : "No matches.",
|
|
52539
|
+
value.truncated === true
|
|
52540
|
+
);
|
|
52541
|
+
}
|
|
52542
|
+
function activityOutput(job, result) {
|
|
52543
|
+
if (!result.ok) {
|
|
52544
|
+
return {
|
|
52545
|
+
kind: "error",
|
|
52546
|
+
...boundedActivityPreview(result.error?.message ?? "The worker operation failed.")
|
|
52547
|
+
};
|
|
52548
|
+
}
|
|
52549
|
+
const value = result.value;
|
|
52550
|
+
switch (job.type) {
|
|
52551
|
+
case "read_file":
|
|
52552
|
+
if (isRecord(value) && typeof value.content === "string") {
|
|
52553
|
+
return activitySuccess(value.content || "(empty file)");
|
|
52554
|
+
}
|
|
52555
|
+
break;
|
|
52556
|
+
case "view_image":
|
|
52557
|
+
if (isRecord(value)) {
|
|
52558
|
+
const size = formatOutputBytes(value.bytes);
|
|
52559
|
+
const mimeType = typeof value.mimeType === "string" ? value.mimeType : "image";
|
|
52560
|
+
return activitySuccess(`Loaded ${mimeType}${size ? ` \xB7 ${size}` : ""}.`);
|
|
52561
|
+
}
|
|
52562
|
+
break;
|
|
52563
|
+
case "list_files": {
|
|
52564
|
+
const output = listFilesActivityOutput(value);
|
|
52565
|
+
if (output) return output;
|
|
52566
|
+
break;
|
|
52567
|
+
}
|
|
52568
|
+
case "search_text": {
|
|
52569
|
+
const output = searchTextActivityOutput(value);
|
|
52570
|
+
if (output) return output;
|
|
52571
|
+
break;
|
|
52572
|
+
}
|
|
52573
|
+
case "read_file_range":
|
|
52574
|
+
if (isRecord(value) && typeof value.content === "string") {
|
|
52575
|
+
return activitySuccess(value.content || "(empty range)", value.nextLine !== void 0);
|
|
52576
|
+
}
|
|
52577
|
+
break;
|
|
52578
|
+
case "write_file":
|
|
52579
|
+
if (isRecord(value)) {
|
|
52580
|
+
const size = formatOutputBytes(value.bytes);
|
|
52581
|
+
return activitySuccess(size ? `Wrote ${size}.` : "File written.");
|
|
52582
|
+
}
|
|
52583
|
+
break;
|
|
52584
|
+
case "edit_file":
|
|
52585
|
+
if (isRecord(value) && typeof value.diff === "string") {
|
|
52586
|
+
return activitySuccess(value.diff || "Edit applied.", value.diffTruncated === true);
|
|
52587
|
+
}
|
|
52588
|
+
break;
|
|
52589
|
+
case "make_directory":
|
|
52590
|
+
if (isRecord(value) && typeof value.created === "boolean") {
|
|
52591
|
+
return activitySuccess(value.created ? "Directory created." : "Directory already existed.");
|
|
52592
|
+
}
|
|
52593
|
+
break;
|
|
52594
|
+
case "delete_path":
|
|
52595
|
+
if (isRecord(value) && typeof value.deletedType === "string") {
|
|
52596
|
+
return activitySuccess(`Deleted ${value.deletedType}.`);
|
|
52597
|
+
}
|
|
52598
|
+
break;
|
|
52599
|
+
case "move_path":
|
|
52600
|
+
if (isRecord(value) && typeof value.movedType === "string") {
|
|
52601
|
+
return activitySuccess(`Moved ${value.movedType}.`);
|
|
52602
|
+
}
|
|
52603
|
+
break;
|
|
52604
|
+
case "run_command":
|
|
52605
|
+
case "get_command":
|
|
52606
|
+
case "cancel_command": {
|
|
52607
|
+
const output = commandActivityOutput(value);
|
|
52608
|
+
if (output) return output;
|
|
52609
|
+
break;
|
|
52610
|
+
}
|
|
52611
|
+
case "read_command_output":
|
|
52612
|
+
if (isRecord(value)) {
|
|
52613
|
+
const content = typeof value.content === "string" ? value.content : "";
|
|
52614
|
+
const sourceTruncated = value.nextOffset !== void 0 || value.retentionTruncated === true;
|
|
52615
|
+
return activitySuccess(content || "No output in this range.", sourceTruncated);
|
|
52616
|
+
}
|
|
52617
|
+
break;
|
|
52618
|
+
}
|
|
52619
|
+
return activitySuccess("Completed successfully.");
|
|
52620
|
+
}
|
|
52318
52621
|
function activitySafeJob(job) {
|
|
52319
52622
|
if (!containsRestrictedAuthenticationData(job)) return job;
|
|
52320
52623
|
switch (job.type) {
|
|
@@ -52387,7 +52690,8 @@ function visibleWorker(worker, options) {
|
|
|
52387
52690
|
type: "activity",
|
|
52388
52691
|
phase: "returned",
|
|
52389
52692
|
job: visibleJob,
|
|
52390
|
-
ok: result.ok
|
|
52693
|
+
ok: result.ok,
|
|
52694
|
+
output: activityOutput(job, result)
|
|
52391
52695
|
},
|
|
52392
52696
|
`${activityResultLabel(job, result)} (${job.requestId}).`
|
|
52393
52697
|
);
|
|
@@ -52399,7 +52703,13 @@ function visibleWorker(worker, options) {
|
|
|
52399
52703
|
type: "activity",
|
|
52400
52704
|
phase: "returned",
|
|
52401
52705
|
job: visibleJob,
|
|
52402
|
-
ok: false
|
|
52706
|
+
ok: false,
|
|
52707
|
+
output: {
|
|
52708
|
+
kind: "error",
|
|
52709
|
+
...boundedActivityPreview(
|
|
52710
|
+
error46 instanceof Error ? error46.message : "The worker operation failed."
|
|
52711
|
+
)
|
|
52712
|
+
}
|
|
52403
52713
|
},
|
|
52404
52714
|
`${job.type} failed (${job.requestId}).`
|
|
52405
52715
|
);
|
|
@@ -52453,7 +52763,9 @@ function statusMessage(status, connectedBefore) {
|
|
|
52453
52763
|
}
|
|
52454
52764
|
if (status.state === "retrying") {
|
|
52455
52765
|
const prefix = connectedBefore ? "Connection lost" : "Could not connect";
|
|
52456
|
-
|
|
52766
|
+
const message = status.error.message.trim();
|
|
52767
|
+
const reason = /[.!?]$/.test(message) ? message : `${message}.`;
|
|
52768
|
+
return `${prefix}: ${reason} ${retryMessage(status.retryInMs)}`;
|
|
52457
52769
|
}
|
|
52458
52770
|
return "Disconnected from Glossa.";
|
|
52459
52771
|
}
|
|
@@ -52461,6 +52773,8 @@ async function connectRemoteWorker(endpoints, device, worker, options, signal, o
|
|
|
52461
52773
|
let connectionState;
|
|
52462
52774
|
let connectedBefore = false;
|
|
52463
52775
|
let connectHintTask;
|
|
52776
|
+
let mcpContractTask = Promise.resolve();
|
|
52777
|
+
let observedMcpContractVersion;
|
|
52464
52778
|
const remoteWorker = new RemoteWorker({
|
|
52465
52779
|
origin: endpoints.workerOrigin,
|
|
52466
52780
|
deviceToken: device.token,
|
|
@@ -52479,6 +52793,15 @@ async function connectRemoteWorker(endpoints, device, worker, options, signal, o
|
|
|
52479
52793
|
} else {
|
|
52480
52794
|
options.onEvent?.({ type: "status", status });
|
|
52481
52795
|
}
|
|
52796
|
+
if (status.state === "connected" && options.workerVersion && status.mcpContractVersion && status.mcpContractVersion !== observedMcpContractVersion) {
|
|
52797
|
+
observedMcpContractVersion = status.mcpContractVersion;
|
|
52798
|
+
const mcpContractVersion = status.mcpContractVersion;
|
|
52799
|
+
mcpContractTask = mcpContractTask.then(async () => {
|
|
52800
|
+
if (!await observeMcpContractVersion(options.workerVersion, mcpContractVersion)) return;
|
|
52801
|
+
const message = "Glossa's ChatGPT tools changed. Refresh or rescan the Glossa app in ChatGPT before using new tools.";
|
|
52802
|
+
report(options, { type: "notice", message }, message);
|
|
52803
|
+
}).catch(() => void 0);
|
|
52804
|
+
}
|
|
52482
52805
|
if (status.state === "connected" && !status.reconnected && shouldShowConnectHint(endpoints.relayOrigin) && !connectHintTask) {
|
|
52483
52806
|
connectHintTask = announceConnectHint(
|
|
52484
52807
|
connectHintStore(),
|
|
@@ -52498,6 +52821,7 @@ async function connectRemoteWorker(endpoints, device, worker, options, signal, o
|
|
|
52498
52821
|
await remoteWorker.run();
|
|
52499
52822
|
} finally {
|
|
52500
52823
|
await connectHintTask;
|
|
52824
|
+
await mcpContractTask;
|
|
52501
52825
|
}
|
|
52502
52826
|
}
|
|
52503
52827
|
async function runManagedSession(root, endpoints, options = {}) {
|
|
@@ -52561,18 +52885,455 @@ async function runManagedSession(root, endpoints, options = {}) {
|
|
|
52561
52885
|
}
|
|
52562
52886
|
}
|
|
52563
52887
|
|
|
52564
|
-
// src/ui-hud-
|
|
52565
|
-
|
|
52566
|
-
|
|
52888
|
+
// src/ui-hud-activity.ts
|
|
52889
|
+
var INLINE_DEFAULT_IGNORABLE = new RegExp("\\p{Default_Ignorable_Code_Point}", "u");
|
|
52890
|
+
function escapeCodePoint(codePoint) {
|
|
52891
|
+
const hexadecimal = codePoint.toString(16);
|
|
52892
|
+
return codePoint <= 65535 ? `\\u${hexadecimal.padStart(4, "0")}` : `\\u{${hexadecimal}}`;
|
|
52567
52893
|
}
|
|
52568
|
-
function
|
|
52569
|
-
|
|
52894
|
+
function escapeActivityText(value, quote2 = false) {
|
|
52895
|
+
let escaped = "";
|
|
52896
|
+
for (const character of value) {
|
|
52897
|
+
const codePoint = character.codePointAt(0);
|
|
52898
|
+
if (character === "\\") escaped += "\\\\";
|
|
52899
|
+
else if (quote2 && character === '"') escaped += '\\"';
|
|
52900
|
+
else if (character === "\n") escaped += "\\n";
|
|
52901
|
+
else if (character === "\r") escaped += "\\r";
|
|
52902
|
+
else if (character === " ") escaped += "\\t";
|
|
52903
|
+
else if (character === "\b") escaped += "\\b";
|
|
52904
|
+
else if (character === "\f") escaped += "\\f";
|
|
52905
|
+
else if (codePoint < 32 || codePoint >= 127 && codePoint <= 159 || INLINE_DEFAULT_IGNORABLE.test(character) || codePoint === 8232 || codePoint === 8233) {
|
|
52906
|
+
escaped += escapeCodePoint(codePoint);
|
|
52907
|
+
} else escaped += character;
|
|
52908
|
+
}
|
|
52909
|
+
return escaped;
|
|
52910
|
+
}
|
|
52911
|
+
function quote(value) {
|
|
52912
|
+
return `"${escapeActivityText(value, true)}"`;
|
|
52913
|
+
}
|
|
52914
|
+
function formatByteCount(bytes) {
|
|
52915
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
52916
|
+
const kibibytes = bytes / 1024;
|
|
52917
|
+
if (kibibytes < 1024) {
|
|
52918
|
+
return `${kibibytes.toFixed(kibibytes < 10 ? 1 : 0)} KiB`;
|
|
52919
|
+
}
|
|
52920
|
+
return `${(kibibytes / 1024).toFixed(1)} MiB`;
|
|
52921
|
+
}
|
|
52922
|
+
function truncateMiddle(value, width) {
|
|
52923
|
+
if (width <= 0) return "";
|
|
52924
|
+
if (value.length <= width) return value;
|
|
52925
|
+
if (width === 1) return "\u2026";
|
|
52926
|
+
const visible = width - 1;
|
|
52927
|
+
const leading = Math.max(1, Math.floor(visible * 0.45));
|
|
52928
|
+
const trailing = visible - leading;
|
|
52929
|
+
let start = value.slice(0, leading);
|
|
52930
|
+
if (/[\ud800-\udbff]$/.test(start)) start = start.slice(0, -1);
|
|
52931
|
+
let end = trailing > 0 ? value.slice(-trailing) : "";
|
|
52932
|
+
if (/^[\udc00-\udfff]/.test(end)) end = end.slice(1);
|
|
52933
|
+
return `${start}\u2026${end}`;
|
|
52934
|
+
}
|
|
52935
|
+
function fitPath(path12, width, quoted = false) {
|
|
52936
|
+
const wrapper = quoted ? 2 : 0;
|
|
52937
|
+
const innerWidth = Math.max(0, width - wrapper);
|
|
52938
|
+
const escaped = escapeActivityText(path12, quoted);
|
|
52939
|
+
if (escaped.length <= innerWidth) return quoted ? `"${escaped}"` : escaped;
|
|
52940
|
+
const slash = path12.includes("/") ? "/" : path12.includes("\\") ? "\\" : void 0;
|
|
52941
|
+
if (!slash) {
|
|
52942
|
+
const fitted2 = truncateMiddle(escaped, innerWidth);
|
|
52943
|
+
return quoted ? `"${fitted2}"` : fitted2;
|
|
52944
|
+
}
|
|
52945
|
+
const parts = path12.split(slash).map((part) => escapeActivityText(part, quoted));
|
|
52946
|
+
if (parts.length < 3) {
|
|
52947
|
+
const fitted2 = truncateMiddle(escaped, innerWidth);
|
|
52948
|
+
return quoted ? `"${fitted2}"` : fitted2;
|
|
52949
|
+
}
|
|
52950
|
+
const first = parts[0];
|
|
52951
|
+
const tail = [parts.at(-1)];
|
|
52952
|
+
for (let index = parts.length - 2; index > 0; index -= 1) {
|
|
52953
|
+
const candidateTail = [parts[index], ...tail];
|
|
52954
|
+
const candidate2 = `${first}${slash}\u2026${slash}${candidateTail.join(slash)}`;
|
|
52955
|
+
if (candidate2.length > innerWidth) break;
|
|
52956
|
+
tail.unshift(parts[index]);
|
|
52957
|
+
}
|
|
52958
|
+
const candidate = `${first}${slash}\u2026${slash}${tail.join(slash)}`;
|
|
52959
|
+
const filename = parts.at(-1);
|
|
52960
|
+
const collapsedFilename = `\u2026${slash}${filename}`;
|
|
52961
|
+
const fitted = candidate.length <= innerWidth ? candidate : collapsedFilename.length <= innerWidth ? collapsedFilename : truncateMiddle(filename, innerWidth);
|
|
52962
|
+
return quoted ? `"${fitted}"` : fitted;
|
|
52963
|
+
}
|
|
52964
|
+
function compactToken(value) {
|
|
52965
|
+
const escaped = escapeActivityText(value, true);
|
|
52966
|
+
return /^[A-Za-z0-9_@./:=+,-]+$/.test(escaped) && escaped.length > 0 ? escaped : `"${escaped}"`;
|
|
52967
|
+
}
|
|
52968
|
+
function fitToken(token, width) {
|
|
52969
|
+
if (width <= 0) return "";
|
|
52970
|
+
if (token.length <= width) return token;
|
|
52971
|
+
if (token.startsWith('"') && token.endsWith('"') && width >= 3) {
|
|
52972
|
+
return `"${truncateMiddle(token.slice(1, -1), width - 2)}"`;
|
|
52973
|
+
}
|
|
52974
|
+
return truncateMiddle(token, width);
|
|
52975
|
+
}
|
|
52976
|
+
function fitDelimitedTokens(prefix, tokens, suffix, width, separator) {
|
|
52977
|
+
const full = `${prefix}${tokens.join(separator)}${suffix}`;
|
|
52978
|
+
if (full.length <= width || tokens.length <= 2) return truncateMiddle(full, width);
|
|
52979
|
+
const left = [tokens[0]];
|
|
52980
|
+
const right = [tokens.at(-1)];
|
|
52981
|
+
let leftIndex = 1;
|
|
52982
|
+
let rightIndex = tokens.length - 2;
|
|
52983
|
+
while (leftIndex <= rightIndex) {
|
|
52984
|
+
let changed = false;
|
|
52985
|
+
const withLeft = `${prefix}${[...left, tokens[leftIndex], "\u2026", ...right].join(separator)}${suffix}`;
|
|
52986
|
+
if (withLeft.length <= width) {
|
|
52987
|
+
left.push(tokens[leftIndex]);
|
|
52988
|
+
leftIndex += 1;
|
|
52989
|
+
changed = true;
|
|
52990
|
+
}
|
|
52991
|
+
if (leftIndex > rightIndex) break;
|
|
52992
|
+
const withRight = `${prefix}${[...left, "\u2026", tokens[rightIndex], ...right].join(separator)}${suffix}`;
|
|
52993
|
+
if (withRight.length <= width) {
|
|
52994
|
+
right.unshift(tokens[rightIndex]);
|
|
52995
|
+
rightIndex -= 1;
|
|
52996
|
+
changed = true;
|
|
52997
|
+
}
|
|
52998
|
+
if (!changed) break;
|
|
52999
|
+
}
|
|
53000
|
+
const candidate = `${prefix}${[...left, "\u2026", ...right].join(separator)}${suffix}`;
|
|
53001
|
+
if (candidate.length <= width) return candidate;
|
|
53002
|
+
const minimalOverhead = prefix.length + suffix.length + separator.length * 2 + 1;
|
|
53003
|
+
const available = width - minimalOverhead;
|
|
53004
|
+
if (available < 2) {
|
|
53005
|
+
const structural = `${prefix}\u2026${suffix}`;
|
|
53006
|
+
return structural.length <= width ? structural : truncateMiddle(structural, width);
|
|
53007
|
+
}
|
|
53008
|
+
const first = tokens[0];
|
|
53009
|
+
const last = tokens.at(-1);
|
|
53010
|
+
let firstWidth = Math.min(first.length, Math.max(1, Math.floor(available / 2)));
|
|
53011
|
+
let lastWidth = available - firstWidth;
|
|
53012
|
+
if (last.length < lastWidth) {
|
|
53013
|
+
lastWidth = last.length;
|
|
53014
|
+
firstWidth = available - lastWidth;
|
|
53015
|
+
} else if (first.length < firstWidth) {
|
|
53016
|
+
firstWidth = first.length;
|
|
53017
|
+
lastWidth = available - firstWidth;
|
|
53018
|
+
}
|
|
53019
|
+
return `${prefix}${fitToken(first, firstWidth)}${separator}\u2026${separator}${fitToken(last, lastWidth)}${suffix}`;
|
|
53020
|
+
}
|
|
53021
|
+
function compactArgv(argv, width) {
|
|
53022
|
+
return fitDelimitedTokens("", argv.map(compactToken), "", width, " ");
|
|
53023
|
+
}
|
|
53024
|
+
function detailedArgv(argv, width) {
|
|
53025
|
+
return fitDelimitedTokens("argv [", argv.map(quote), "]", width, ", ");
|
|
53026
|
+
}
|
|
53027
|
+
function shortId(value) {
|
|
53028
|
+
return value.length <= 18 ? value : `${value.slice(0, 8)}\u2026${value.slice(-4)}`;
|
|
53029
|
+
}
|
|
53030
|
+
function appendDetails(target, details, width) {
|
|
53031
|
+
let result = target;
|
|
53032
|
+
for (const detail of details) {
|
|
53033
|
+
const candidate = `${result} \xB7 ${detail}`;
|
|
53034
|
+
if (candidate.length > width) continue;
|
|
53035
|
+
result = candidate;
|
|
53036
|
+
}
|
|
53037
|
+
return truncateMiddle(result, width);
|
|
53038
|
+
}
|
|
53039
|
+
function lineRange(call) {
|
|
53040
|
+
if (call.startLine && call.lineCount) return `lines ${call.startLine}\u2013${call.startLine + call.lineCount - 1}`;
|
|
53041
|
+
if (call.startLine) return `from line ${call.startLine}`;
|
|
53042
|
+
if (call.lineCount) return `first ${call.lineCount} lines`;
|
|
53043
|
+
return void 0;
|
|
53044
|
+
}
|
|
53045
|
+
function activityCallFromJob(job) {
|
|
53046
|
+
switch (job.type) {
|
|
53047
|
+
case "read_file":
|
|
53048
|
+
case "view_image":
|
|
53049
|
+
return { type: job.type, path: job.path };
|
|
53050
|
+
case "list_files":
|
|
53051
|
+
return {
|
|
53052
|
+
type: job.type,
|
|
53053
|
+
...job.path === void 0 ? {} : { path: job.path },
|
|
53054
|
+
...job.recursive === void 0 ? {} : { recursive: job.recursive },
|
|
53055
|
+
...job.cursor === void 0 ? {} : { cursor: job.cursor },
|
|
53056
|
+
...job.limit === void 0 ? {} : { limit: job.limit },
|
|
53057
|
+
timeoutMs: job.timeoutMs
|
|
53058
|
+
};
|
|
53059
|
+
case "search_text":
|
|
53060
|
+
return {
|
|
53061
|
+
type: job.type,
|
|
53062
|
+
query: job.query,
|
|
53063
|
+
...job.path === void 0 ? {} : { path: job.path },
|
|
53064
|
+
...job.matchMode === void 0 ? {} : { matchMode: job.matchMode },
|
|
53065
|
+
...job.caseSensitive === void 0 ? {} : { caseSensitive: job.caseSensitive },
|
|
53066
|
+
...job.maxResults === void 0 ? {} : { maxResults: job.maxResults },
|
|
53067
|
+
...job.extensions === void 0 ? {} : { extensions: job.extensions },
|
|
53068
|
+
...job.includeGlobs === void 0 ? {} : { includeGlobs: job.includeGlobs },
|
|
53069
|
+
...job.excludeGlobs === void 0 ? {} : { excludeGlobs: job.excludeGlobs },
|
|
53070
|
+
timeoutMs: job.timeoutMs
|
|
53071
|
+
};
|
|
53072
|
+
case "read_file_range":
|
|
53073
|
+
return {
|
|
53074
|
+
type: job.type,
|
|
53075
|
+
path: job.path,
|
|
53076
|
+
...job.startLine === void 0 ? {} : { startLine: job.startLine },
|
|
53077
|
+
...job.lineCount === void 0 ? {} : { lineCount: job.lineCount },
|
|
53078
|
+
timeoutMs: job.timeoutMs
|
|
53079
|
+
};
|
|
53080
|
+
case "write_file":
|
|
53081
|
+
return {
|
|
53082
|
+
type: job.type,
|
|
53083
|
+
path: job.path,
|
|
53084
|
+
contentBytes: Buffer.byteLength(job.content, "utf8"),
|
|
53085
|
+
...job.expectedSha256 === void 0 ? {} : { expectedSha256: job.expectedSha256 }
|
|
53086
|
+
};
|
|
53087
|
+
case "edit_file":
|
|
53088
|
+
return {
|
|
53089
|
+
type: job.type,
|
|
53090
|
+
path: job.path,
|
|
53091
|
+
editCount: job.edits.length,
|
|
53092
|
+
editBytes: job.edits.reduce(
|
|
53093
|
+
(total, edit) => total + Buffer.byteLength(edit.oldText, "utf8") + Buffer.byteLength(edit.newText, "utf8"),
|
|
53094
|
+
0
|
|
53095
|
+
),
|
|
53096
|
+
...job.expectedSha256 === void 0 ? {} : { expectedSha256: job.expectedSha256 }
|
|
53097
|
+
};
|
|
53098
|
+
case "make_directory":
|
|
53099
|
+
case "delete_path":
|
|
53100
|
+
return {
|
|
53101
|
+
type: job.type,
|
|
53102
|
+
path: job.path,
|
|
53103
|
+
...job.recursive === void 0 ? {} : { recursive: job.recursive }
|
|
53104
|
+
};
|
|
53105
|
+
case "move_path":
|
|
53106
|
+
return { type: job.type, source: job.source, destination: job.destination };
|
|
53107
|
+
case "run_command":
|
|
53108
|
+
return {
|
|
53109
|
+
type: job.type,
|
|
53110
|
+
...job.argv === void 0 ? {} : { argv: job.argv },
|
|
53111
|
+
...job.shellCommand === void 0 ? {} : { shellCommand: job.shellCommand },
|
|
53112
|
+
...job.stdin === void 0 ? {} : { stdinBytes: Buffer.byteLength(job.stdin, "utf8") },
|
|
53113
|
+
timeoutMs: job.timeoutMs,
|
|
53114
|
+
...job.waitMs === void 0 ? {} : { waitMs: job.waitMs }
|
|
53115
|
+
};
|
|
53116
|
+
case "get_command":
|
|
53117
|
+
return {
|
|
53118
|
+
type: job.type,
|
|
53119
|
+
commandId: job.commandId,
|
|
53120
|
+
...job.waitMs === void 0 ? {} : { waitMs: job.waitMs },
|
|
53121
|
+
...job.afterSequence === void 0 ? {} : { afterSequence: job.afterSequence }
|
|
53122
|
+
};
|
|
53123
|
+
case "read_command_output":
|
|
53124
|
+
return {
|
|
53125
|
+
type: job.type,
|
|
53126
|
+
commandId: job.commandId,
|
|
53127
|
+
stream: job.stream,
|
|
53128
|
+
...job.offset === void 0 ? {} : { offset: job.offset },
|
|
53129
|
+
...job.maxBytes === void 0 ? {} : { maxBytes: job.maxBytes }
|
|
53130
|
+
};
|
|
53131
|
+
case "cancel_command":
|
|
53132
|
+
return { type: job.type, commandId: job.commandId };
|
|
53133
|
+
}
|
|
53134
|
+
}
|
|
53135
|
+
function activityCallByteLength(call) {
|
|
53136
|
+
return Buffer.byteLength(JSON.stringify(call), "utf8");
|
|
53137
|
+
}
|
|
53138
|
+
function formatActivityCall(call, mode, width) {
|
|
53139
|
+
const detailed = mode === "detailed";
|
|
53140
|
+
const pathWidth = detailed ? Math.max(1, width - 5) : width;
|
|
53141
|
+
switch (call.type) {
|
|
53142
|
+
case "read_file":
|
|
53143
|
+
case "view_image":
|
|
53144
|
+
return detailed ? `path ${fitPath(call.path, pathWidth, true)}` : fitPath(call.path, width);
|
|
53145
|
+
case "list_files": {
|
|
53146
|
+
const target = detailed ? `path ${fitPath(call.path ?? ".", pathWidth, true)}` : fitPath(call.path ?? ".", width);
|
|
53147
|
+
const details = detailed ? [
|
|
53148
|
+
...call.recursive ? ["recursive"] : [],
|
|
53149
|
+
...call.limit ? [`limit ${call.limit}`] : [],
|
|
53150
|
+
...call.cursor ? [`after ${truncateMiddle(quote(call.cursor), 28)}`] : [],
|
|
53151
|
+
...call.timeoutMs === MAX_STRUCTURED_READ_TIMEOUT_MS ? [] : [`timeout ${call.timeoutMs} ms`]
|
|
53152
|
+
] : call.recursive ? ["recursive"] : [];
|
|
53153
|
+
return appendDetails(target, details, width);
|
|
53154
|
+
}
|
|
53155
|
+
case "search_text": {
|
|
53156
|
+
const queryPrefix = detailed ? "query " : "";
|
|
53157
|
+
const connector = detailed ? " in path " : " in ";
|
|
53158
|
+
const contentWidth = width - queryPrefix.length - connector.length;
|
|
53159
|
+
if (contentWidth < 6) {
|
|
53160
|
+
return `${queryPrefix}${fitToken(quote(call.query), Math.max(1, width - queryPrefix.length))}`;
|
|
53161
|
+
}
|
|
53162
|
+
let pathBudget = Math.max(3, Math.floor(contentWidth * 0.42));
|
|
53163
|
+
let path12 = fitPath(call.path ?? ".", pathBudget, detailed);
|
|
53164
|
+
let queryWidth = contentWidth - path12.length;
|
|
53165
|
+
if (queryWidth < 3) {
|
|
53166
|
+
pathBudget = Math.max(3, pathBudget - (3 - queryWidth));
|
|
53167
|
+
path12 = fitPath(call.path ?? ".", pathBudget, detailed);
|
|
53168
|
+
queryWidth = contentWidth - path12.length;
|
|
53169
|
+
}
|
|
53170
|
+
const query = fitToken(quote(call.query), Math.max(1, queryWidth));
|
|
53171
|
+
const target = `${queryPrefix}${query}${connector}${path12}`;
|
|
53172
|
+
const details = detailed ? [
|
|
53173
|
+
...call.matchMode === "regex" ? ["regex"] : [],
|
|
53174
|
+
...call.caseSensitive ? ["case-sensitive"] : [],
|
|
53175
|
+
...call.extensions?.length ? [`extensions ${call.extensions.join(", ")}`] : [],
|
|
53176
|
+
...call.includeGlobs?.length ? [`${call.includeGlobs.length} include ${call.includeGlobs.length === 1 ? "glob" : "globs"}`] : [],
|
|
53177
|
+
...call.excludeGlobs?.length ? [`${call.excludeGlobs.length} exclude ${call.excludeGlobs.length === 1 ? "glob" : "globs"}`] : [],
|
|
53178
|
+
...call.maxResults ? [`limit ${call.maxResults}`] : [],
|
|
53179
|
+
...call.timeoutMs === MAX_STRUCTURED_READ_TIMEOUT_MS ? [] : [`timeout ${call.timeoutMs} ms`]
|
|
53180
|
+
] : [];
|
|
53181
|
+
return appendDetails(target, details, width);
|
|
53182
|
+
}
|
|
53183
|
+
case "read_file_range": {
|
|
53184
|
+
const range = lineRange(call);
|
|
53185
|
+
const rangeWidth = range ? range.length + 3 : 0;
|
|
53186
|
+
const target = detailed ? `path ${fitPath(call.path, Math.max(8, pathWidth - rangeWidth), true)}` : fitPath(call.path, Math.max(8, width - rangeWidth));
|
|
53187
|
+
return appendDetails(target, [range, detailed && call.timeoutMs !== MAX_STRUCTURED_READ_TIMEOUT_MS ? `timeout ${call.timeoutMs} ms` : void 0].filter((value) => Boolean(value)), width);
|
|
53188
|
+
}
|
|
53189
|
+
case "write_file": {
|
|
53190
|
+
const target = detailed ? `path ${fitPath(call.path, pathWidth, true)}` : fitPath(call.path, width);
|
|
53191
|
+
return appendDetails(target, [formatByteCount(call.contentBytes), ...call.expectedSha256 ? ["guarded"] : []], width);
|
|
53192
|
+
}
|
|
53193
|
+
case "edit_file": {
|
|
53194
|
+
const target = detailed ? `path ${fitPath(call.path, pathWidth, true)}` : fitPath(call.path, width);
|
|
53195
|
+
const editLabel = `${call.editCount} ${call.editCount === 1 ? "edit" : "edits"}`;
|
|
53196
|
+
return appendDetails(target, [editLabel, ...call.expectedSha256 ? ["guarded"] : [], ...detailed ? [formatByteCount(call.editBytes)] : []], width);
|
|
53197
|
+
}
|
|
53198
|
+
case "make_directory":
|
|
53199
|
+
case "delete_path": {
|
|
53200
|
+
const target = detailed ? `path ${fitPath(call.path, pathWidth, true)}` : fitPath(call.path, width);
|
|
53201
|
+
return appendDetails(target, call.recursive ? ["recursive"] : [], width);
|
|
53202
|
+
}
|
|
53203
|
+
case "move_path": {
|
|
53204
|
+
const leftWidth = Math.max(4, Math.floor((width - 3) / 2));
|
|
53205
|
+
const rightWidth = Math.max(4, width - leftWidth - 3);
|
|
53206
|
+
return `${fitPath(call.source, leftWidth, detailed)} \u2192 ${fitPath(call.destination, rightWidth, detailed)}`;
|
|
53207
|
+
}
|
|
53208
|
+
case "run_command": {
|
|
53209
|
+
const target = call.argv ? detailed ? detailedArgv(call.argv, width) : compactArgv(call.argv, width) : detailed ? `shell ${truncateMiddle(quote(call.shellCommand ?? ""), Math.max(1, width - 6))}` : truncateMiddle(escapeActivityText(call.shellCommand ?? ""), width);
|
|
53210
|
+
if (!detailed) return target;
|
|
53211
|
+
return appendDetails(target, [
|
|
53212
|
+
...call.stdinBytes === void 0 ? [] : [`stdin ${formatByteCount(call.stdinBytes)}`],
|
|
53213
|
+
...call.timeoutMs === DEFAULT_COMMAND_TIMEOUT_MS ? [] : [`timeout ${call.timeoutMs} ms`],
|
|
53214
|
+
...call.waitMs === void 0 || call.waitMs === DEFAULT_COMMAND_FAST_WAIT_MS ? [] : [`wait ${call.waitMs} ms`]
|
|
53215
|
+
], width);
|
|
53216
|
+
}
|
|
53217
|
+
case "get_command": {
|
|
53218
|
+
const target = `command ${detailed ? call.commandId : shortId(call.commandId)}`;
|
|
53219
|
+
return detailed ? appendDetails(target, [
|
|
53220
|
+
...call.waitMs ? [`wait ${call.waitMs} ms`] : [],
|
|
53221
|
+
...call.afterSequence === void 0 ? [] : [`after sequence ${call.afterSequence}`]
|
|
53222
|
+
], width) : truncateMiddle(target, width);
|
|
53223
|
+
}
|
|
53224
|
+
case "read_command_output": {
|
|
53225
|
+
const target = `command ${detailed ? call.commandId : shortId(call.commandId)} ${call.stream}`;
|
|
53226
|
+
return detailed ? appendDetails(target, [
|
|
53227
|
+
...call.offset === void 0 ? [] : [`offset ${call.offset}`],
|
|
53228
|
+
...call.maxBytes === void 0 ? [] : [`max ${call.maxBytes} bytes`]
|
|
53229
|
+
], width) : truncateMiddle(target, width);
|
|
53230
|
+
}
|
|
53231
|
+
case "cancel_command":
|
|
53232
|
+
return truncateMiddle(`command ${detailed ? call.commandId : shortId(call.commandId)}`, width);
|
|
53233
|
+
}
|
|
53234
|
+
}
|
|
53235
|
+
function listValue(values) {
|
|
53236
|
+
return `[${values.map(quote).join(", ")}]`;
|
|
53237
|
+
}
|
|
53238
|
+
function activityCallDetailFields(call) {
|
|
53239
|
+
switch (call.type) {
|
|
53240
|
+
case "read_file":
|
|
53241
|
+
case "view_image":
|
|
53242
|
+
return [{ label: "path", value: quote(call.path) }];
|
|
53243
|
+
case "list_files":
|
|
53244
|
+
return [
|
|
53245
|
+
{ label: "path", value: call.path === void 0 ? '"."' : quote(call.path) },
|
|
53246
|
+
...call.recursive ? [{ label: "recursive", value: "true" }] : [],
|
|
53247
|
+
...call.cursor === void 0 ? [] : [{ label: "cursor", value: quote(call.cursor) }],
|
|
53248
|
+
...call.limit === void 0 ? [] : [{ label: "limit", value: String(call.limit) }],
|
|
53249
|
+
...call.timeoutMs === MAX_STRUCTURED_READ_TIMEOUT_MS ? [] : [{ label: "timeoutMs", value: String(call.timeoutMs) }]
|
|
53250
|
+
];
|
|
53251
|
+
case "search_text":
|
|
53252
|
+
return [
|
|
53253
|
+
{ label: "query", value: quote(call.query) },
|
|
53254
|
+
{ label: "path", value: call.path === void 0 ? '"."' : quote(call.path) },
|
|
53255
|
+
...call.matchMode === "regex" ? [{ label: "matchMode", value: "regex" }] : [],
|
|
53256
|
+
...call.caseSensitive ? [{ label: "caseSensitive", value: "true" }] : [],
|
|
53257
|
+
...call.maxResults === void 0 ? [] : [{ label: "maxResults", value: String(call.maxResults) }],
|
|
53258
|
+
...call.extensions === void 0 ? [] : [{ label: "extensions", value: listValue(call.extensions) }],
|
|
53259
|
+
...call.includeGlobs === void 0 ? [] : [{ label: "includeGlobs", value: listValue(call.includeGlobs) }],
|
|
53260
|
+
...call.excludeGlobs === void 0 ? [] : [{ label: "excludeGlobs", value: listValue(call.excludeGlobs) }],
|
|
53261
|
+
...call.timeoutMs === MAX_STRUCTURED_READ_TIMEOUT_MS ? [] : [{ label: "timeoutMs", value: String(call.timeoutMs) }]
|
|
53262
|
+
];
|
|
53263
|
+
case "read_file_range":
|
|
53264
|
+
return [
|
|
53265
|
+
{ label: "path", value: quote(call.path) },
|
|
53266
|
+
...call.startLine === void 0 ? [] : [{ label: "startLine", value: String(call.startLine) }],
|
|
53267
|
+
...call.lineCount === void 0 ? [] : [{ label: "lineCount", value: String(call.lineCount) }],
|
|
53268
|
+
...call.timeoutMs === MAX_STRUCTURED_READ_TIMEOUT_MS ? [] : [{ label: "timeoutMs", value: String(call.timeoutMs) }]
|
|
53269
|
+
];
|
|
53270
|
+
case "write_file":
|
|
53271
|
+
return [
|
|
53272
|
+
{ label: "path", value: quote(call.path) },
|
|
53273
|
+
{ label: "content", value: `${formatByteCount(call.contentBytes)} \xB7 content not retained in Activity` },
|
|
53274
|
+
...call.expectedSha256 === void 0 ? [] : [{ label: "expectedSha256", value: call.expectedSha256 }]
|
|
53275
|
+
];
|
|
53276
|
+
case "edit_file":
|
|
53277
|
+
return [
|
|
53278
|
+
{ label: "path", value: quote(call.path) },
|
|
53279
|
+
{ label: "edits", value: `${call.editCount} ${call.editCount === 1 ? "edit" : "edits"} \xB7 ${formatByteCount(call.editBytes)} \xB7 text not retained in Activity` },
|
|
53280
|
+
...call.expectedSha256 === void 0 ? [] : [{ label: "expectedSha256", value: call.expectedSha256 }]
|
|
53281
|
+
];
|
|
53282
|
+
case "make_directory":
|
|
53283
|
+
case "delete_path":
|
|
53284
|
+
return [
|
|
53285
|
+
{ label: "path", value: quote(call.path) },
|
|
53286
|
+
...call.recursive ? [{ label: "recursive", value: "true" }] : []
|
|
53287
|
+
];
|
|
53288
|
+
case "move_path":
|
|
53289
|
+
return [
|
|
53290
|
+
{ label: "source", value: quote(call.source) },
|
|
53291
|
+
{ label: "destination", value: quote(call.destination) }
|
|
53292
|
+
];
|
|
53293
|
+
case "run_command":
|
|
53294
|
+
return [
|
|
53295
|
+
...call.argv === void 0 ? [] : [{ label: "argv", value: listValue(call.argv) }],
|
|
53296
|
+
...call.shellCommand === void 0 ? [] : [{ label: "shellCommand", value: quote(call.shellCommand) }],
|
|
53297
|
+
...call.stdinBytes === void 0 ? [] : [{ label: "stdin", value: `${formatByteCount(call.stdinBytes)} \xB7 content not retained in Activity` }],
|
|
53298
|
+
...call.timeoutMs === DEFAULT_COMMAND_TIMEOUT_MS ? [] : [{ label: "timeoutMs", value: String(call.timeoutMs) }],
|
|
53299
|
+
...call.waitMs === void 0 || call.waitMs === DEFAULT_COMMAND_FAST_WAIT_MS ? [] : [{ label: "waitMs", value: String(call.waitMs) }]
|
|
53300
|
+
];
|
|
53301
|
+
case "get_command":
|
|
53302
|
+
return [
|
|
53303
|
+
{ label: "commandId", value: call.commandId },
|
|
53304
|
+
...call.waitMs === void 0 ? [] : [{ label: "waitMs", value: String(call.waitMs) }],
|
|
53305
|
+
...call.afterSequence === void 0 ? [] : [{ label: "afterSequence", value: String(call.afterSequence) }]
|
|
53306
|
+
];
|
|
53307
|
+
case "read_command_output":
|
|
53308
|
+
return [
|
|
53309
|
+
{ label: "commandId", value: call.commandId },
|
|
53310
|
+
{ label: "stream", value: call.stream },
|
|
53311
|
+
...call.offset === void 0 || call.offset === 0 ? [] : [{ label: "offset", value: String(call.offset) }],
|
|
53312
|
+
...call.maxBytes === void 0 || call.maxBytes === DEFAULT_COMMAND_OUTPUT_RANGE_BYTES ? [] : [{ label: "maxBytes", value: String(call.maxBytes) }]
|
|
53313
|
+
];
|
|
53314
|
+
case "cancel_command":
|
|
53315
|
+
return [{ label: "commandId", value: call.commandId }];
|
|
53316
|
+
}
|
|
53317
|
+
}
|
|
53318
|
+
function activityToolTitle(type) {
|
|
53319
|
+
return type.split("_").map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
|
|
53320
|
+
}
|
|
53321
|
+
|
|
53322
|
+
// src/ui-hud-model.ts
|
|
53323
|
+
function retainPostExitNotice(current, event) {
|
|
53324
|
+
return event.type === "notice" && event.persistAfterExit ? event.message : current;
|
|
53325
|
+
}
|
|
53326
|
+
function initialHudState(workspace) {
|
|
53327
|
+
return {
|
|
52570
53328
|
workspace,
|
|
52571
53329
|
connection: "starting",
|
|
52572
53330
|
connectedBefore: false,
|
|
52573
53331
|
message: void 0,
|
|
52574
53332
|
activities: [],
|
|
52575
|
-
|
|
53333
|
+
activityMode: "compact",
|
|
53334
|
+
activitySelection: void 0,
|
|
53335
|
+
activityBrowseAnchor: void 0,
|
|
53336
|
+
activityDetailScroll: 0,
|
|
52576
53337
|
view: "workspace",
|
|
52577
53338
|
status: void 0,
|
|
52578
53339
|
deviceSelection: 0,
|
|
@@ -52580,18 +53341,21 @@ function initialHudState(workspace) {
|
|
|
52580
53341
|
statusLoading: false,
|
|
52581
53342
|
prompt: void 0,
|
|
52582
53343
|
busy: false,
|
|
52583
|
-
|
|
53344
|
+
busyMessage: void 0,
|
|
53345
|
+
notice: void 0,
|
|
53346
|
+
noticeTone: void 0
|
|
52584
53347
|
};
|
|
52585
53348
|
}
|
|
52586
53349
|
var MAX_STORED_ACTIVITIES = 9999;
|
|
52587
53350
|
var MAX_STORED_ACTIVITY_TARGET_CHARS = 512;
|
|
53351
|
+
var MAX_RETAINED_ACTIVITY_CALL_BYTES = 16 * 1024 * 1024;
|
|
52588
53352
|
function truncate(value, width) {
|
|
52589
53353
|
if (width <= 0) return "";
|
|
52590
53354
|
if (value.length <= width) return value;
|
|
52591
53355
|
if (width === 1) return "\u2026";
|
|
52592
53356
|
return `${value.slice(0, width - 1)}\u2026`;
|
|
52593
53357
|
}
|
|
52594
|
-
function
|
|
53358
|
+
function truncateMiddle2(value, width) {
|
|
52595
53359
|
if (width <= 0) return "";
|
|
52596
53360
|
if (value.length <= width) return value;
|
|
52597
53361
|
if (width === 1) return "\u2026";
|
|
@@ -52604,24 +53368,24 @@ function truncateMiddle(value, width) {
|
|
|
52604
53368
|
if (/^[\udc00-\udfff]/.test(end)) end = end.slice(1);
|
|
52605
53369
|
return `${start}\u2026${end}`;
|
|
52606
53370
|
}
|
|
52607
|
-
var
|
|
52608
|
-
function
|
|
53371
|
+
var INLINE_DEFAULT_IGNORABLE2 = new RegExp("\\p{Default_Ignorable_Code_Point}", "u");
|
|
53372
|
+
function escapeCodePoint2(codePoint) {
|
|
52609
53373
|
const hexadecimal = codePoint.toString(16);
|
|
52610
53374
|
return codePoint <= 65535 ? `\\u${hexadecimal.padStart(4, "0")}` : `\\u{${hexadecimal}}`;
|
|
52611
53375
|
}
|
|
52612
|
-
function escapeInline(value,
|
|
53376
|
+
function escapeInline(value, quote2 = false) {
|
|
52613
53377
|
let escaped = "";
|
|
52614
53378
|
for (const character of value) {
|
|
52615
53379
|
const codePoint = character.codePointAt(0);
|
|
52616
53380
|
if (character === "\\") escaped += "\\\\";
|
|
52617
|
-
else if (
|
|
53381
|
+
else if (quote2 && character === '"') escaped += '\\"';
|
|
52618
53382
|
else if (character === "\n") escaped += "\\n";
|
|
52619
53383
|
else if (character === "\r") escaped += "\\r";
|
|
52620
53384
|
else if (character === " ") escaped += "\\t";
|
|
52621
53385
|
else if (character === "\b") escaped += "\\b";
|
|
52622
53386
|
else if (character === "\f") escaped += "\\f";
|
|
52623
|
-
else if (codePoint < 32 || codePoint >= 127 && codePoint <= 159 ||
|
|
52624
|
-
escaped +=
|
|
53387
|
+
else if (codePoint < 32 || codePoint >= 127 && codePoint <= 159 || INLINE_DEFAULT_IGNORABLE2.test(character) || codePoint === 8232 || codePoint === 8233) {
|
|
53388
|
+
escaped += escapeCodePoint2(codePoint);
|
|
52625
53389
|
} else escaped += character;
|
|
52626
53390
|
}
|
|
52627
53391
|
return escaped;
|
|
@@ -52630,12 +53394,12 @@ function quoteInline(value) {
|
|
|
52630
53394
|
return `"${escapeInline(value, true)}"`;
|
|
52631
53395
|
}
|
|
52632
53396
|
function boundInlineInput(value) {
|
|
52633
|
-
return
|
|
53397
|
+
return truncateMiddle2(value, MAX_STORED_ACTIVITY_TARGET_CHARS);
|
|
52634
53398
|
}
|
|
52635
53399
|
function quoteActivityInput(value) {
|
|
52636
53400
|
return quoteInline(boundInlineInput(value));
|
|
52637
53401
|
}
|
|
52638
|
-
function
|
|
53402
|
+
function formatByteCount2(value) {
|
|
52639
53403
|
const bytes = Buffer.byteLength(value, "utf8");
|
|
52640
53404
|
if (bytes < 1024) return `${bytes} B`;
|
|
52641
53405
|
const kibibytes = bytes / 1024;
|
|
@@ -52699,7 +53463,7 @@ function summarizeJob(job) {
|
|
|
52699
53463
|
}
|
|
52700
53464
|
case "write_file":
|
|
52701
53465
|
return pathSummary(job.path, [
|
|
52702
|
-
|
|
53466
|
+
formatByteCount2(job.content),
|
|
52703
53467
|
...job.expectedSha256 ? ["guarded"] : []
|
|
52704
53468
|
]);
|
|
52705
53469
|
case "edit_file":
|
|
@@ -52721,7 +53485,7 @@ function summarizeJob(job) {
|
|
|
52721
53485
|
return {
|
|
52722
53486
|
target: job.argv ? `argv [${job.argv.map(quoteActivityInput).join(", ")}]` : `shell ${quoteActivityInput(job.shellCommand ?? "")}`,
|
|
52723
53487
|
details: [
|
|
52724
|
-
...job.stdin === void 0 ? [] : [`stdin ${
|
|
53488
|
+
...job.stdin === void 0 ? [] : [`stdin ${formatByteCount2(job.stdin)}`],
|
|
52725
53489
|
...job.timeoutMs === DEFAULT_COMMAND_TIMEOUT_MS ? [] : [`timeout ${job.timeoutMs} ms`],
|
|
52726
53490
|
...job.waitMs === void 0 || job.waitMs === DEFAULT_COMMAND_FAST_WAIT_MS ? [] : [`wait ${job.waitMs} ms`]
|
|
52727
53491
|
],
|
|
@@ -52766,9 +53530,9 @@ function fitTargetSegments(segments, width) {
|
|
|
52766
53530
|
const balancedTrailingWidth = available - balancedLeadingWidth;
|
|
52767
53531
|
const leadingWidth = leading.length <= balancedLeadingWidth ? leading.length : trailing.length <= balancedTrailingWidth ? available - trailing.length : balancedLeadingWidth;
|
|
52768
53532
|
return [
|
|
52769
|
-
|
|
53533
|
+
truncateMiddle2(leading, leadingWidth),
|
|
52770
53534
|
separator,
|
|
52771
|
-
|
|
53535
|
+
truncateMiddle2(trailing, available - leadingWidth)
|
|
52772
53536
|
];
|
|
52773
53537
|
}
|
|
52774
53538
|
function boundActivitySummary(summary) {
|
|
@@ -52779,8 +53543,28 @@ function boundActivitySummary(summary) {
|
|
|
52779
53543
|
return {
|
|
52780
53544
|
...summary,
|
|
52781
53545
|
...targetSegments ? { targetSegments } : {},
|
|
52782
|
-
target: targetSegments ? targetSegments.join("") : summary.truncation === "middle" ?
|
|
52783
|
-
};
|
|
53546
|
+
target: targetSegments ? targetSegments.join("") : summary.truncation === "middle" ? truncateMiddle2(summary.target, MAX_STORED_ACTIVITY_TARGET_CHARS) : truncate(summary.target, MAX_STORED_ACTIVITY_TARGET_CHARS)
|
|
53547
|
+
};
|
|
53548
|
+
}
|
|
53549
|
+
function pruneActivityCalls(activities) {
|
|
53550
|
+
let retainedBytes2 = 0;
|
|
53551
|
+
const next = [...activities];
|
|
53552
|
+
for (let index = next.length - 1; index >= 0; index -= 1) {
|
|
53553
|
+
const activity = next[index];
|
|
53554
|
+
if (!activity.call || activity.callBytes === void 0) continue;
|
|
53555
|
+
if (activity.callBytes > MAX_RETAINED_ACTIVITY_CALL_BYTES) {
|
|
53556
|
+
const { call: _call, callBytes: _callBytes, ...summaryOnly } = activity;
|
|
53557
|
+
next[index] = { ...summaryOnly, callUnavailable: "oversized" };
|
|
53558
|
+
continue;
|
|
53559
|
+
}
|
|
53560
|
+
if (retainedBytes2 + activity.callBytes > MAX_RETAINED_ACTIVITY_CALL_BYTES) {
|
|
53561
|
+
const { call: _call, callBytes: _callBytes, ...summaryOnly } = activity;
|
|
53562
|
+
next[index] = { ...summaryOnly, callUnavailable: "expired" };
|
|
53563
|
+
continue;
|
|
53564
|
+
}
|
|
53565
|
+
retainedBytes2 += activity.callBytes;
|
|
53566
|
+
}
|
|
53567
|
+
return next;
|
|
52784
53568
|
}
|
|
52785
53569
|
function applyHudEvent(state, event) {
|
|
52786
53570
|
if (event.type === "session") {
|
|
@@ -52789,19 +53573,33 @@ function applyHudEvent(state, event) {
|
|
|
52789
53573
|
...state,
|
|
52790
53574
|
workspace: event.root,
|
|
52791
53575
|
deviceName: event.deviceName,
|
|
52792
|
-
accessProfile: event.accessProfile,
|
|
53576
|
+
...accessHandoff && state.accessProfile ? { accessProfile: state.accessProfile } : { accessProfile: event.accessProfile },
|
|
52793
53577
|
pendingAccessProfile: accessHandoff ? state.pendingAccessProfile : void 0
|
|
52794
53578
|
};
|
|
52795
53579
|
}
|
|
52796
53580
|
if (event.type === "status") {
|
|
52797
53581
|
if (state.pendingAccessProfile && state.connectedBefore) {
|
|
52798
|
-
if (event.status.state
|
|
53582
|
+
if (event.status.state === "connected") {
|
|
53583
|
+
return {
|
|
53584
|
+
...state,
|
|
53585
|
+
connection: "connected",
|
|
53586
|
+
connectedBefore: true,
|
|
53587
|
+
message: void 0,
|
|
53588
|
+
accessProfile: state.pendingAccessProfile,
|
|
53589
|
+
pendingAccessProfile: void 0
|
|
53590
|
+
};
|
|
53591
|
+
}
|
|
53592
|
+
if (event.status.state === "retrying") {
|
|
53593
|
+
return {
|
|
53594
|
+
...state,
|
|
53595
|
+
connection: "retrying",
|
|
53596
|
+
message: statusMessage(event.status, true)
|
|
53597
|
+
};
|
|
53598
|
+
}
|
|
52799
53599
|
return {
|
|
52800
53600
|
...state,
|
|
52801
|
-
connection:
|
|
52802
|
-
|
|
52803
|
-
message: void 0,
|
|
52804
|
-
pendingAccessProfile: void 0
|
|
53601
|
+
connection: event.status.state,
|
|
53602
|
+
message: event.status.state === "disconnected" ? statusMessage(event.status, true) : void 0
|
|
52805
53603
|
};
|
|
52806
53604
|
}
|
|
52807
53605
|
if (event.status.state === "retrying") {
|
|
@@ -52819,26 +53617,46 @@ function applyHudEvent(state, event) {
|
|
|
52819
53617
|
};
|
|
52820
53618
|
}
|
|
52821
53619
|
if (event.type === "notice") {
|
|
52822
|
-
return { ...state, notice: event.message };
|
|
53620
|
+
return { ...state, notice: event.message, noticeTone: "info" };
|
|
52823
53621
|
}
|
|
52824
53622
|
const requestId = event.job.requestId;
|
|
52825
53623
|
const existingIndex = state.activities.findIndex(
|
|
52826
53624
|
(activity2) => activity2.requestId === requestId
|
|
52827
53625
|
);
|
|
53626
|
+
const existing = existingIndex >= 0 ? state.activities[existingIndex] : void 0;
|
|
52828
53627
|
const activityTimestamp = Date.now();
|
|
53628
|
+
const freshCall = existing?.callUnavailable ? void 0 : existing?.call ?? activityCallFromJob(event.job);
|
|
53629
|
+
const freshCallBytes = existing?.callBytes ?? (freshCall ? activityCallByteLength(freshCall) : void 0);
|
|
53630
|
+
const retainFreshCall = freshCall !== void 0 && freshCallBytes !== void 0 && freshCallBytes <= MAX_RETAINED_ACTIVITY_CALL_BYTES;
|
|
53631
|
+
const formatCall = freshCall ?? activityCallFromJob(event.job);
|
|
53632
|
+
const eventOutput = event.phase === "returned" ? event.output ?? {
|
|
53633
|
+
kind: event.ok ? "success" : "error"
|
|
53634
|
+
} : void 0;
|
|
52829
53635
|
const activity = {
|
|
52830
53636
|
tool: event.job.type,
|
|
52831
53637
|
summary: boundActivitySummary(summarizeJob(event.job)),
|
|
53638
|
+
compactSummary: existing?.compactSummary ?? formatActivityCall(
|
|
53639
|
+
formatCall,
|
|
53640
|
+
"compact",
|
|
53641
|
+
MAX_STORED_ACTIVITY_TARGET_CHARS
|
|
53642
|
+
),
|
|
53643
|
+
...retainFreshCall ? { call: freshCall, callBytes: freshCallBytes } : {},
|
|
53644
|
+
...!retainFreshCall && !existing?.callUnavailable ? { callUnavailable: "oversized" } : existing?.callUnavailable ? { callUnavailable: existing.callUnavailable } : {},
|
|
53645
|
+
...eventOutput ? { output: eventOutput } : {},
|
|
52832
53646
|
requestId,
|
|
52833
|
-
state: event.phase === "started" ? "working" :
|
|
53647
|
+
state: event.phase === "started" ? "working" : eventOutput?.kind === "error" ? "failed" : "returned",
|
|
53648
|
+
startedAt: existing?.startedAt ?? activityTimestamp,
|
|
52834
53649
|
updatedAt: activityTimestamp
|
|
52835
53650
|
};
|
|
52836
53651
|
const activities = [...state.activities];
|
|
52837
53652
|
if (existingIndex >= 0) activities[existingIndex] = activity;
|
|
52838
53653
|
else activities.push(activity);
|
|
53654
|
+
const boundedActivities = pruneActivityCalls(activities.slice(-MAX_STORED_ACTIVITIES));
|
|
53655
|
+
const activitySelection = state.activitySelection && boundedActivities.some((item) => item.requestId === state.activitySelection) ? state.activitySelection : void 0;
|
|
52839
53656
|
return {
|
|
52840
53657
|
...state,
|
|
52841
|
-
activities:
|
|
53658
|
+
activities: boundedActivities,
|
|
53659
|
+
activitySelection
|
|
52842
53660
|
};
|
|
52843
53661
|
}
|
|
52844
53662
|
|
|
@@ -52856,7 +53674,9 @@ var COLORS = {
|
|
|
52856
53674
|
function Text2({ color, ...props }) {
|
|
52857
53675
|
return color === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { ...props }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { ...props, color });
|
|
52858
53676
|
}
|
|
52859
|
-
var
|
|
53677
|
+
var ACTIVITY_IDLE_REFRESH_INTERVAL_MS = 1e4;
|
|
53678
|
+
var ACTIVITY_LIVE_REFRESH_INTERVAL_MS = 1e3;
|
|
53679
|
+
var ACTIVITY_SELECTOR_COLUMN_WIDTH = 2;
|
|
52860
53680
|
var ACTIVITY_STATUS_COLUMN_WIDTH = 2;
|
|
52861
53681
|
var ACTIVITY_TOOL_COLUMN_WIDTH = 15;
|
|
52862
53682
|
var ACTIVITY_AGE_COLUMN_WIDTH = 10;
|
|
@@ -52864,8 +53684,11 @@ var ACTIVITY_PREAMBLE_LINES = 1;
|
|
|
52864
53684
|
var HudStore = class {
|
|
52865
53685
|
#state;
|
|
52866
53686
|
#listeners = /* @__PURE__ */ new Set();
|
|
52867
|
-
constructor(workspace) {
|
|
52868
|
-
this.#state =
|
|
53687
|
+
constructor(workspace, initialNotice) {
|
|
53688
|
+
this.#state = {
|
|
53689
|
+
...initialHudState(workspace),
|
|
53690
|
+
...initialNotice ? { notice: initialNotice } : {}
|
|
53691
|
+
};
|
|
52869
53692
|
}
|
|
52870
53693
|
getSnapshot = () => this.#state;
|
|
52871
53694
|
subscribe = (listener) => {
|
|
@@ -52895,10 +53718,22 @@ function connectionLabel(state) {
|
|
|
52895
53718
|
if (state.connection === "error") return "Error";
|
|
52896
53719
|
return "Disconnected";
|
|
52897
53720
|
}
|
|
52898
|
-
function
|
|
52899
|
-
|
|
52900
|
-
if (
|
|
52901
|
-
|
|
53721
|
+
function liveDuration(elapsedMs) {
|
|
53722
|
+
const seconds = Math.floor(Math.max(0, elapsedMs) / 1e3);
|
|
53723
|
+
if (seconds < 1) return "now";
|
|
53724
|
+
if (seconds < 60) return `${seconds}s`;
|
|
53725
|
+
const minutes = Math.floor(seconds / 60);
|
|
53726
|
+
if (minutes < 60) return `${minutes}m ${String(seconds % 60).padStart(2, "0")}s`;
|
|
53727
|
+
const hours = Math.floor(minutes / 60);
|
|
53728
|
+
return `${hours}h ${String(minutes % 60).padStart(2, "0")}m`;
|
|
53729
|
+
}
|
|
53730
|
+
function activityAge(activity, now) {
|
|
53731
|
+
if (activity.state === "working") {
|
|
53732
|
+
const startedAt = activity.startedAt ?? activity.updatedAt;
|
|
53733
|
+
return startedAt === void 0 ? "now" : liveDuration(now - startedAt);
|
|
53734
|
+
}
|
|
53735
|
+
if (activity.updatedAt === void 0) return "";
|
|
53736
|
+
const elapsedMs = Math.max(0, now - activity.updatedAt);
|
|
52902
53737
|
if (elapsedMs < 1e4) return "just now";
|
|
52903
53738
|
if (elapsedMs < 6e4) return `${Math.floor(elapsedMs / 1e3)}s ago`;
|
|
52904
53739
|
if (elapsedMs < 36e5) return `${Math.floor(elapsedMs / 6e4)}m ago`;
|
|
@@ -52913,6 +53748,14 @@ function activityStatus(activity) {
|
|
|
52913
53748
|
function activitySummary(activity) {
|
|
52914
53749
|
return [activity.summary.target, ...activity.summary.details].join(" \xB7 ");
|
|
52915
53750
|
}
|
|
53751
|
+
function selectedActivity(state) {
|
|
53752
|
+
if (!state.activitySelection) return void 0;
|
|
53753
|
+
return state.activities.find((activity) => activity.requestId === state.activitySelection);
|
|
53754
|
+
}
|
|
53755
|
+
function selectedActivityIndex(state) {
|
|
53756
|
+
const selected = selectedActivity(state);
|
|
53757
|
+
return selected ? state.activities.findIndex((activity) => activity.requestId === selected.requestId) : -1;
|
|
53758
|
+
}
|
|
52916
53759
|
function sectionLabel(value) {
|
|
52917
53760
|
return value.toUpperCase();
|
|
52918
53761
|
}
|
|
@@ -52926,42 +53769,68 @@ function adjacentAccessProfile(accessProfile, direction) {
|
|
|
52926
53769
|
}
|
|
52927
53770
|
function accessProfileCapabilities(accessProfile) {
|
|
52928
53771
|
if (accessProfile === "read-only") {
|
|
52929
|
-
return { summary: "
|
|
53772
|
+
return { summary: "read files", detail: "No writes \xB7 no commands" };
|
|
52930
53773
|
}
|
|
52931
53774
|
if (accessProfile === "workspace") {
|
|
52932
|
-
return { summary: "
|
|
53775
|
+
return { summary: "read + write files", detail: "Commands off" };
|
|
52933
53776
|
}
|
|
52934
53777
|
return {
|
|
52935
|
-
summary: "
|
|
52936
|
-
detail: "OS
|
|
53778
|
+
summary: "read + write files + commands",
|
|
53779
|
+
detail: "OS permissions \xB7 credentials \xB7 network"
|
|
52937
53780
|
};
|
|
52938
53781
|
}
|
|
52939
|
-
function primaryFooterHints() {
|
|
53782
|
+
function primaryFooterHints(state) {
|
|
53783
|
+
if (state.prompt) return [];
|
|
53784
|
+
if (state.busy) return [{ key: "Q", label: "Quit", tone: COLORS.coral }];
|
|
52940
53785
|
return [
|
|
52941
53786
|
{ key: "A", label: "Activity" },
|
|
52942
53787
|
{ key: "W", label: "Workspace" },
|
|
52943
53788
|
{ key: "D", label: "Devices" },
|
|
52944
|
-
{ key: "?", label: "Help" },
|
|
52945
53789
|
{ key: "Q", label: "Quit", tone: COLORS.coral }
|
|
52946
53790
|
];
|
|
52947
53791
|
}
|
|
52948
|
-
function contextualFooterHints(state) {
|
|
53792
|
+
function contextualFooterHints(state, usable, bodyBudget) {
|
|
53793
|
+
if (state.prompt || state.busy) return [];
|
|
52949
53794
|
if (state.view === "activity") {
|
|
53795
|
+
if (state.activities.length === 0) return [];
|
|
53796
|
+
const density = {
|
|
53797
|
+
key: "Tab",
|
|
53798
|
+
label: state.activityMode === "compact" ? "Detailed" : "Compact",
|
|
53799
|
+
labelWidth: "Detailed".length
|
|
53800
|
+
};
|
|
53801
|
+
if (state.activitySelection) {
|
|
53802
|
+
return [
|
|
53803
|
+
density,
|
|
53804
|
+
{ key: "\u2191\u2193", label: "Select" },
|
|
53805
|
+
{ key: "Enter", label: "Inspect" },
|
|
53806
|
+
{ key: "Esc", label: "Browse" }
|
|
53807
|
+
];
|
|
53808
|
+
}
|
|
53809
|
+
const window2 = activityBrowseWindow(state, bodyBudget);
|
|
53810
|
+
return [
|
|
53811
|
+
density,
|
|
53812
|
+
...window2.start > 0 ? [{ key: "\u2191", label: "Older" }] : [],
|
|
53813
|
+
...window2.end < state.activities.length ? [{ key: "\u2193", label: "Newer" }] : [],
|
|
53814
|
+
...window2.end > window2.start ? [{ key: "Enter", label: "Select" }] : []
|
|
53815
|
+
];
|
|
53816
|
+
}
|
|
53817
|
+
if (state.view === "activity-detail") {
|
|
53818
|
+
const maxScroll = activityDetailMaxScroll(state, usable, bodyBudget, Date.now());
|
|
53819
|
+
const hiddenBelow = Math.max(0, maxScroll - state.activityDetailScroll);
|
|
52950
53820
|
return [
|
|
52951
|
-
{ key: "\
|
|
52952
|
-
{ key: "
|
|
53821
|
+
...hiddenBelow > 0 ? [{ key: "\u2193", label: `${hiddenBelow} more` }] : [],
|
|
53822
|
+
{ key: "Esc", label: "Back" }
|
|
52953
53823
|
];
|
|
52954
53824
|
}
|
|
52955
|
-
if (state.view === "devices" && (state.status?.devices.length ?? 0) > 0) {
|
|
53825
|
+
if (state.view === "devices" && (state.status?.devices.length ?? 0) > 0 && statusDeviceCapacity(state, bodyBudget, usable) > 0) {
|
|
52956
53826
|
return [
|
|
52957
53827
|
{ key: "\u2191\u2193", label: "Select" },
|
|
52958
|
-
{ key: "Enter
|
|
53828
|
+
{ key: "Enter", label: "Revoke", tone: COLORS.coral }
|
|
52959
53829
|
];
|
|
52960
53830
|
}
|
|
52961
|
-
if (state.view === "workspace" && state.accessProfile) {
|
|
52962
|
-
const
|
|
52963
|
-
const
|
|
52964
|
-
const higher = adjacentAccessProfile(displayedAccessProfile, 1);
|
|
53831
|
+
if (state.view === "workspace" && state.connection === "connected" && state.accessProfile && !state.pendingAccessProfile) {
|
|
53832
|
+
const lower = adjacentAccessProfile(state.accessProfile, -1);
|
|
53833
|
+
const higher = adjacentAccessProfile(state.accessProfile, 1);
|
|
52965
53834
|
return [
|
|
52966
53835
|
...lower ? [{ key: "\u2190", label: accessProfileLabel(lower) }] : [],
|
|
52967
53836
|
...higher ? [{ key: "\u2192", label: accessProfileLabel(higher), tone: COLORS.coral }] : []
|
|
@@ -52970,7 +53839,7 @@ function contextualFooterHints(state) {
|
|
|
52970
53839
|
return [];
|
|
52971
53840
|
}
|
|
52972
53841
|
function footerHintWidth(hint) {
|
|
52973
|
-
return hint.key.length + hint.label.length + 1;
|
|
53842
|
+
return hint.key.length + Math.max(hint.label.length, hint.labelWidth ?? 0) + 1;
|
|
52974
53843
|
}
|
|
52975
53844
|
function footerHintsWidth(hints) {
|
|
52976
53845
|
if (hints.length === 0) return 0;
|
|
@@ -52991,13 +53860,19 @@ function splitFooterHints(hints, usable) {
|
|
|
52991
53860
|
}
|
|
52992
53861
|
return rows;
|
|
52993
53862
|
}
|
|
52994
|
-
function buildFooterRows(state, usable) {
|
|
52995
|
-
const rows = splitFooterHints(primaryFooterHints(), usable).map((left) => ({
|
|
53863
|
+
function buildFooterRows(state, usable, bodyBudget) {
|
|
53864
|
+
const rows = splitFooterHints(primaryFooterHints(state), usable).map((left) => ({
|
|
52996
53865
|
left,
|
|
52997
53866
|
right: []
|
|
52998
53867
|
}));
|
|
52999
|
-
const contextualRows = splitFooterHints(
|
|
53868
|
+
const contextualRows = splitFooterHints(
|
|
53869
|
+
contextualFooterHints(state, usable, bodyBudget),
|
|
53870
|
+
usable
|
|
53871
|
+
);
|
|
53000
53872
|
if (contextualRows.length === 0) return rows;
|
|
53873
|
+
if (rows.length === 0) {
|
|
53874
|
+
return contextualRows.map((right) => ({ left: [], right }));
|
|
53875
|
+
}
|
|
53001
53876
|
const firstContextual = contextualRows[0];
|
|
53002
53877
|
const lastPrimary = rows.at(-1);
|
|
53003
53878
|
const combinedWidth = footerHintsWidth(lastPrimary.left) + 3 + footerHintsWidth(firstContextual);
|
|
@@ -53009,57 +53884,177 @@ function buildFooterRows(state, usable) {
|
|
|
53009
53884
|
}
|
|
53010
53885
|
return rows;
|
|
53011
53886
|
}
|
|
53012
|
-
function
|
|
53013
|
-
if (
|
|
53014
|
-
|
|
53015
|
-
if (
|
|
53016
|
-
|
|
53887
|
+
function wrapOverlayText(value, width) {
|
|
53888
|
+
if (width <= 0) return [""];
|
|
53889
|
+
const words = value.split(/\s+/).filter(Boolean);
|
|
53890
|
+
if (words.length === 0) return [""];
|
|
53891
|
+
const lines = [];
|
|
53892
|
+
let line = "";
|
|
53893
|
+
for (const word of words) {
|
|
53894
|
+
if (!line) {
|
|
53895
|
+
line = word;
|
|
53896
|
+
continue;
|
|
53897
|
+
}
|
|
53898
|
+
if (`${line} ${word}`.length <= width) {
|
|
53899
|
+
line += ` ${word}`;
|
|
53900
|
+
continue;
|
|
53901
|
+
}
|
|
53902
|
+
lines.push(line);
|
|
53903
|
+
line = word;
|
|
53904
|
+
}
|
|
53905
|
+
if (line) lines.push(line);
|
|
53906
|
+
return lines.flatMap((part) => {
|
|
53907
|
+
if (part.length <= width) return [part];
|
|
53908
|
+
const chunks = [];
|
|
53909
|
+
for (let index = 0; index < part.length; index += width) {
|
|
53910
|
+
chunks.push(part.slice(index, index + width));
|
|
53911
|
+
}
|
|
53912
|
+
return chunks;
|
|
53913
|
+
});
|
|
53914
|
+
}
|
|
53915
|
+
function overlayContent(state, usable) {
|
|
53916
|
+
if (state.busy) {
|
|
53017
53917
|
return {
|
|
53018
|
-
|
|
53019
|
-
|
|
53918
|
+
lines: wrapOverlayText(state.busyMessage ?? "Working\u2026", usable),
|
|
53919
|
+
tone: COLORS.purpleReadable,
|
|
53920
|
+
bold: true
|
|
53020
53921
|
};
|
|
53021
53922
|
}
|
|
53022
|
-
|
|
53923
|
+
if (state.prompt?.type === "access-confirm") {
|
|
53924
|
+
const warning = state.prompt.accessProfile === "system" ? "Commands use this OS account's permissions, environment, credentials, and network." : "Allows guarded file writes inside this workspace.";
|
|
53925
|
+
return {
|
|
53926
|
+
lines: [
|
|
53927
|
+
...wrapOverlayText(`Increase access to ${accessProfileLabel(state.prompt.accessProfile)}?`, usable),
|
|
53928
|
+
...wrapOverlayText(warning, usable)
|
|
53929
|
+
],
|
|
53930
|
+
choices: "Y Confirm N Cancel",
|
|
53931
|
+
tone: COLORS.coral,
|
|
53932
|
+
bold: true
|
|
53933
|
+
};
|
|
53934
|
+
}
|
|
53935
|
+
if (state.prompt?.type === "revoke-confirm") {
|
|
53936
|
+
const device = state.status?.devices[state.prompt.deviceIndex];
|
|
53937
|
+
return {
|
|
53938
|
+
lines: wrapOverlayText(`Revoke ${device?.name ?? "this device"}?`, usable),
|
|
53939
|
+
choices: "Y Confirm N Cancel",
|
|
53940
|
+
tone: COLORS.coral,
|
|
53941
|
+
bold: true
|
|
53942
|
+
};
|
|
53943
|
+
}
|
|
53944
|
+
if (!state.notice) return void 0;
|
|
53945
|
+
const tone = state.noticeTone === "error" ? COLORS.coral : state.noticeTone === "success" ? COLORS.success : COLORS.purpleReadable;
|
|
53023
53946
|
return {
|
|
53024
|
-
|
|
53025
|
-
|
|
53947
|
+
lines: wrapOverlayText(state.notice, usable),
|
|
53948
|
+
tone,
|
|
53949
|
+
bold: false
|
|
53026
53950
|
};
|
|
53027
53951
|
}
|
|
53028
53952
|
function screenMetrics(state, columns, rows) {
|
|
53029
53953
|
const margin = columns >= 24 ? 2 : 0;
|
|
53030
53954
|
const usable = Math.max(8, columns - margin * 2);
|
|
53031
53955
|
const terminalRows = Math.max(6, rows);
|
|
53032
|
-
const
|
|
53033
|
-
const
|
|
53034
|
-
|
|
53035
|
-
|
|
53036
|
-
|
|
53037
|
-
|
|
53038
|
-
|
|
53956
|
+
const overlay = overlayContent(state, usable);
|
|
53957
|
+
const overlayRows = overlay ? 1 + overlay.lines.length + (overlay.choices ? 1 : 0) : 0;
|
|
53958
|
+
let bodyBudget = Math.max(0, terminalRows - 2 - overlayRows - 1);
|
|
53959
|
+
let footerRows = [];
|
|
53960
|
+
for (let iteration = 0; iteration < 4; iteration += 1) {
|
|
53961
|
+
const nextFooterRows = buildFooterRows(state, usable, bodyBudget);
|
|
53962
|
+
const nextBodyBudget = Math.max(
|
|
53963
|
+
0,
|
|
53964
|
+
terminalRows - 2 - overlayRows - 1 - nextFooterRows.length
|
|
53965
|
+
);
|
|
53966
|
+
footerRows = nextFooterRows;
|
|
53967
|
+
if (nextBodyBudget === bodyBudget) break;
|
|
53968
|
+
bodyBudget = nextBodyBudget;
|
|
53969
|
+
}
|
|
53039
53970
|
return { usable, bodyBudget, footerRows, overlayRows };
|
|
53040
53971
|
}
|
|
53041
|
-
function
|
|
53972
|
+
function activityListCapacity(bodyBudget) {
|
|
53042
53973
|
return Math.max(0, bodyBudget - ACTIVITY_PREAMBLE_LINES);
|
|
53043
53974
|
}
|
|
53044
|
-
function
|
|
53045
|
-
|
|
53046
|
-
|
|
53047
|
-
}
|
|
53048
|
-
|
|
53049
|
-
|
|
53050
|
-
|
|
53051
|
-
|
|
53975
|
+
function activityBrowseWindow(state, bodyBudget) {
|
|
53976
|
+
const capacity = activityListCapacity(bodyBudget);
|
|
53977
|
+
const total = state.activities.length;
|
|
53978
|
+
if (capacity <= 0 || total === 0) return { capacity, start: 0, end: 0 };
|
|
53979
|
+
let end = total;
|
|
53980
|
+
if (state.activityBrowseAnchor) {
|
|
53981
|
+
const anchorIndex = state.activities.findIndex(
|
|
53982
|
+
(activity) => activity.requestId === state.activityBrowseAnchor
|
|
53983
|
+
);
|
|
53984
|
+
end = anchorIndex >= 0 ? anchorIndex + 1 : Math.min(total, capacity);
|
|
53985
|
+
}
|
|
53052
53986
|
return {
|
|
53053
53987
|
capacity,
|
|
53054
|
-
|
|
53055
|
-
|
|
53056
|
-
|
|
53057
|
-
|
|
53988
|
+
start: Math.max(0, end - capacity),
|
|
53989
|
+
end
|
|
53990
|
+
};
|
|
53991
|
+
}
|
|
53992
|
+
function activityWindow(state, bodyBudget) {
|
|
53993
|
+
const browsing = activityBrowseWindow(state, bodyBudget);
|
|
53994
|
+
const selection = selectedActivityIndex(state);
|
|
53995
|
+
if (selection < 0 || browsing.capacity <= 0 || selection >= browsing.start && selection < browsing.end) {
|
|
53996
|
+
return { ...browsing, selection };
|
|
53997
|
+
}
|
|
53998
|
+
const total = state.activities.length;
|
|
53999
|
+
const maxStart = Math.max(0, total - browsing.capacity);
|
|
54000
|
+
const centered = selection - Math.floor(browsing.capacity / 2);
|
|
54001
|
+
const start = Math.min(maxStart, Math.max(0, centered));
|
|
54002
|
+
return {
|
|
54003
|
+
capacity: browsing.capacity,
|
|
54004
|
+
selection,
|
|
54005
|
+
start,
|
|
54006
|
+
end: Math.min(total, start + browsing.capacity)
|
|
54007
|
+
};
|
|
54008
|
+
}
|
|
54009
|
+
function activityBrowseAnchorForEnd(activities, end) {
|
|
54010
|
+
if (end >= activities.length) return void 0;
|
|
54011
|
+
return end > 0 ? activities[end - 1]?.requestId : void 0;
|
|
54012
|
+
}
|
|
54013
|
+
function activityCenterSelection(state, bodyBudget) {
|
|
54014
|
+
const { start, end } = activityBrowseWindow(state, bodyBudget);
|
|
54015
|
+
if (end <= start) return void 0;
|
|
54016
|
+
const index = start + Math.floor((end - start) / 2);
|
|
54017
|
+
return state.activities[index]?.requestId;
|
|
54018
|
+
}
|
|
54019
|
+
function activityPageUpdate(state, bodyBudget, direction) {
|
|
54020
|
+
const window2 = activityBrowseWindow(state, bodyBudget);
|
|
54021
|
+
if (window2.capacity <= 0) return void 0;
|
|
54022
|
+
if (direction === "older") {
|
|
54023
|
+
if (window2.start <= 0) return void 0;
|
|
54024
|
+
return {
|
|
54025
|
+
activityBrowseAnchor: activityBrowseAnchorForEnd(state.activities, window2.start)
|
|
54026
|
+
};
|
|
54027
|
+
}
|
|
54028
|
+
if (window2.end >= state.activities.length) return void 0;
|
|
54029
|
+
const end = Math.min(state.activities.length, window2.end + window2.capacity);
|
|
54030
|
+
return {
|
|
54031
|
+
activityBrowseAnchor: activityBrowseAnchorForEnd(state.activities, end)
|
|
54032
|
+
};
|
|
54033
|
+
}
|
|
54034
|
+
function activitySelectionUpdate(state, bodyBudget, direction) {
|
|
54035
|
+
const currentIndex = selectedActivityIndex(state);
|
|
54036
|
+
if (currentIndex < 0) return void 0;
|
|
54037
|
+
const targetIndex = Math.min(
|
|
54038
|
+
state.activities.length - 1,
|
|
54039
|
+
Math.max(0, currentIndex + direction)
|
|
54040
|
+
);
|
|
54041
|
+
if (targetIndex === currentIndex) return void 0;
|
|
54042
|
+
const window2 = activityWindow(state, bodyBudget);
|
|
54043
|
+
let activityBrowseAnchor = state.activityBrowseAnchor;
|
|
54044
|
+
if (targetIndex < window2.start) {
|
|
54045
|
+
activityBrowseAnchor = activityBrowseAnchorForEnd(state.activities, window2.start);
|
|
54046
|
+
} else if (targetIndex >= window2.end) {
|
|
54047
|
+
const end = Math.min(state.activities.length, window2.end + window2.capacity);
|
|
54048
|
+
activityBrowseAnchor = activityBrowseAnchorForEnd(state.activities, end);
|
|
54049
|
+
}
|
|
54050
|
+
return {
|
|
54051
|
+
activitySelection: state.activities[targetIndex].requestId,
|
|
54052
|
+
activityBrowseAnchor
|
|
53058
54053
|
};
|
|
53059
54054
|
}
|
|
53060
54055
|
function statusDeviceCapacity(state, bodyBudget, usable) {
|
|
53061
54056
|
if (!state.status || state.statusLoading || state.status.devices.length === 0) return 0;
|
|
53062
|
-
const preamble = usable >= 64 ?
|
|
54057
|
+
const preamble = usable >= 64 ? 2 : 1;
|
|
53063
54058
|
return Math.min(9, state.status.devices.length, Math.max(0, bodyBudget - preamble));
|
|
53064
54059
|
}
|
|
53065
54060
|
function deviceListWindow(state, bodyBudget, usable) {
|
|
@@ -53081,9 +54076,10 @@ function Line({ usable, color }) {
|
|
|
53081
54076
|
}
|
|
53082
54077
|
function Header({ state, usable, bodyBudget, color }) {
|
|
53083
54078
|
const statusColor = state.connection === "error" ? COLORS.coral : COLORS.purpleReadable;
|
|
53084
|
-
const
|
|
53085
|
-
const
|
|
53086
|
-
const
|
|
54079
|
+
const selected = selectedActivity(state);
|
|
54080
|
+
const pageTitle = state.view === "activity" ? "Activity" : state.view === "activity-detail" ? `Activity / ${selected ? activityToolTitle(selected.tool) : "Call"}` : state.view === "devices" ? "Devices" : "Workspace";
|
|
54081
|
+
const activityListWindow = state.view === "activity" ? activityWindow(state, bodyBudget) : void 0;
|
|
54082
|
+
const activityRange = activityListWindow && activityListWindow.capacity > 0 && state.activities.length > activityListWindow.capacity ? ` (${activityListWindow.start + 1}-${activityListWindow.end}/${state.activities.length})` : "";
|
|
53087
54083
|
const deviceWindow = state.view === "devices" ? deviceListWindow(state, bodyBudget, usable) : void 0;
|
|
53088
54084
|
const deviceRange = deviceWindow && state.status && deviceWindow.capacity > 0 && state.status.devices.length > deviceWindow.capacity ? ` (${deviceWindow.start + 1}-${deviceWindow.end}/${state.status.devices.length})` : "";
|
|
53089
54085
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", height: 2, flexShrink: 0, children: [
|
|
@@ -53107,76 +54103,105 @@ function SectionTitle({ children, color, tone = COLORS.purpleReadable }) {
|
|
|
53107
54103
|
function Blank() {
|
|
53108
54104
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { height: 1 });
|
|
53109
54105
|
}
|
|
53110
|
-
function
|
|
53111
|
-
|
|
53112
|
-
|
|
53113
|
-
|
|
53114
|
-
|
|
53115
|
-
|
|
54106
|
+
function WorkspaceFact({ label, value, usable, color, tone, hint }) {
|
|
54107
|
+
const labelWidth = Math.min(10, Math.max(7, Math.floor(usable * 0.16)));
|
|
54108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { width: usable, height: 1, flexShrink: 0, children: [
|
|
54109
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: labelWidth, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: label }) }),
|
|
54110
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1, flexShrink: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? tone ?? COLORS.ink : void 0, wrap: "truncate", children: value }) }),
|
|
54111
|
+
hint && usable >= 40 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { marginLeft: 2, flexShrink: 0, children: [
|
|
54112
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? hint.tone ?? COLORS.purpleReadable : void 0, children: hint.key }),
|
|
54113
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: ` ${hint.label}` })
|
|
53116
54114
|
] }) : null
|
|
53117
54115
|
] });
|
|
53118
54116
|
}
|
|
53119
|
-
function
|
|
53120
|
-
const lower = adjacentAccessProfile(accessProfile, -1);
|
|
53121
|
-
const higher = adjacentAccessProfile(accessProfile, 1);
|
|
53122
|
-
const key = lower && higher ? "\u2190/\u2192" : lower ? "\u2190" : "\u2192";
|
|
54117
|
+
function WorkspaceActivityHeader({ usable, color }) {
|
|
53123
54118
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { width: usable, children: [
|
|
53124
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, children: "
|
|
53125
|
-
usable >=
|
|
53126
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? COLORS.purpleReadable : void 0, children:
|
|
53127
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "
|
|
54119
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1, flexShrink: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, children: "Activity" }) }),
|
|
54120
|
+
usable >= 32 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { marginLeft: 2, flexShrink: 0, children: [
|
|
54121
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? COLORS.purpleReadable : void 0, children: "A" }),
|
|
54122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: " View all" })
|
|
53128
54123
|
] }) : null
|
|
53129
54124
|
] });
|
|
53130
54125
|
}
|
|
53131
|
-
function activityLayout(usable) {
|
|
54126
|
+
function activityLayout(usable, selectable) {
|
|
54127
|
+
const selectorWidth = selectable ? ACTIVITY_SELECTOR_COLUMN_WIDTH : 0;
|
|
54128
|
+
const leadingWidth = selectorWidth + ACTIVITY_STATUS_COLUMN_WIDTH;
|
|
53132
54129
|
const toolWidth = Math.min(
|
|
53133
54130
|
ACTIVITY_TOOL_COLUMN_WIDTH,
|
|
53134
|
-
Math.max(0, usable -
|
|
54131
|
+
Math.max(0, usable - leadingWidth)
|
|
53135
54132
|
);
|
|
53136
|
-
|
|
53137
|
-
|
|
53138
|
-
|
|
53139
|
-
|
|
53140
|
-
|
|
54133
|
+
const showSummary = usable >= leadingWidth + toolWidth + 5;
|
|
54134
|
+
const showAge = usable >= leadingWidth + toolWidth + ACTIVITY_AGE_COLUMN_WIDTH + 10;
|
|
54135
|
+
const summaryWidth = Math.max(
|
|
54136
|
+
0,
|
|
54137
|
+
usable - leadingWidth - toolWidth - (showSummary ? 2 : 0) - (showAge ? ACTIVITY_AGE_COLUMN_WIDTH + 2 : 0)
|
|
54138
|
+
);
|
|
54139
|
+
return { toolWidth, showSummary, showAge, summaryWidth };
|
|
53141
54140
|
}
|
|
53142
54141
|
function WorkspaceView({ state, usable, bodyBudget, color, now }) {
|
|
53143
|
-
const displayedAccessProfile = state.pendingAccessProfile ?? state.accessProfile;
|
|
53144
54142
|
const showConnectionMessage = Boolean(
|
|
53145
54143
|
state.message && (state.connection === "retrying" || state.connection === "error")
|
|
53146
54144
|
);
|
|
53147
|
-
|
|
53148
|
-
|
|
53149
|
-
if (
|
|
54145
|
+
const hasFacts = Boolean(state.deviceName || state.accessProfile);
|
|
54146
|
+
let fixedLines = 2;
|
|
54147
|
+
if (hasFacts) fixedLines += 1;
|
|
54148
|
+
if (state.deviceName) fixedLines += 1;
|
|
54149
|
+
if (state.accessProfile) fixedLines += 2;
|
|
53150
54150
|
if (showConnectionMessage) fixedLines += 2;
|
|
53151
|
-
const activityCapacity = Math.min(3, Math.max(0, bodyBudget - fixedLines -
|
|
54151
|
+
const activityCapacity = !state.prompt && !state.busy && state.activities.length > 0 ? Math.min(3, Math.max(0, bodyBudget - fixedLines - 3)) : 0;
|
|
53152
54152
|
const activityPreview = activityCapacity > 0 ? state.activities.slice(-activityCapacity) : [];
|
|
54153
|
+
const accessHint = state.connection === "connected" && state.accessProfile && !state.pendingAccessProfile && !state.prompt && !state.busy ? (() => {
|
|
54154
|
+
const lower = adjacentAccessProfile(state.accessProfile, -1);
|
|
54155
|
+
const higher = adjacentAccessProfile(state.accessProfile, 1);
|
|
54156
|
+
return {
|
|
54157
|
+
key: lower && higher ? "\u2190/\u2192" : lower ? "\u2190" : "\u2192",
|
|
54158
|
+
label: "Switch"
|
|
54159
|
+
};
|
|
54160
|
+
})() : void 0;
|
|
53153
54161
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { height: bodyBudget, flexDirection: "column", flexShrink: 0, overflow: "hidden", children: [
|
|
53154
54162
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53155
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, children: "Workspace" }),
|
|
53156
54163
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.ink : void 0, wrap: "truncate-middle", children: state.workspace }),
|
|
53157
|
-
|
|
53158
|
-
|
|
54164
|
+
hasFacts ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}) : null,
|
|
54165
|
+
state.deviceName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54166
|
+
WorkspaceFact,
|
|
54167
|
+
{
|
|
54168
|
+
label: "Device",
|
|
54169
|
+
value: state.deviceName,
|
|
54170
|
+
usable,
|
|
54171
|
+
color
|
|
54172
|
+
}
|
|
54173
|
+
) : null,
|
|
54174
|
+
state.accessProfile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
53159
54175
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53160
|
-
|
|
54176
|
+
WorkspaceFact,
|
|
53161
54177
|
{
|
|
53162
|
-
|
|
54178
|
+
label: "Access",
|
|
54179
|
+
value: `${accessProfileLabel(state.accessProfile)} \xB7 ${accessProfileCapabilities(state.accessProfile).summary}`,
|
|
53163
54180
|
usable,
|
|
53164
|
-
color
|
|
54181
|
+
color,
|
|
54182
|
+
hint: accessHint
|
|
53165
54183
|
}
|
|
53166
54184
|
),
|
|
53167
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53168
|
-
|
|
53169
|
-
|
|
54185
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54186
|
+
WorkspaceFact,
|
|
54187
|
+
{
|
|
54188
|
+
label: "",
|
|
54189
|
+
value: accessProfileCapabilities(state.accessProfile).detail,
|
|
54190
|
+
usable,
|
|
54191
|
+
color
|
|
54192
|
+
}
|
|
54193
|
+
)
|
|
53170
54194
|
] }) : null,
|
|
53171
|
-
|
|
54195
|
+
showConnectionMessage ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
53172
54196
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53173
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53174
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.ink : void 0, wrap: "truncate", children: state.deviceName })
|
|
54197
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.coral : void 0, wrap: "wrap", children: state.message })
|
|
53175
54198
|
] }) : null,
|
|
53176
54199
|
activityCapacity > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
53177
54200
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53178
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53179
|
-
|
|
54201
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Line, { usable, color }),
|
|
54202
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
54203
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceActivityHeader, { usable, color }),
|
|
54204
|
+
activityPreview.map((activity) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53180
54205
|
ActivityRow,
|
|
53181
54206
|
{
|
|
53182
54207
|
activity,
|
|
@@ -53186,29 +54211,35 @@ function WorkspaceView({ state, usable, bodyBudget, color, now }) {
|
|
|
53186
54211
|
},
|
|
53187
54212
|
activity.requestId
|
|
53188
54213
|
))
|
|
53189
|
-
] }) : null,
|
|
53190
|
-
showConnectionMessage ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
53191
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53192
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.coral : void 0, wrap: "truncate", children: state.message })
|
|
53193
54214
|
] }) : null
|
|
53194
54215
|
] });
|
|
53195
54216
|
}
|
|
53196
|
-
function ActivityRow({
|
|
53197
|
-
|
|
53198
|
-
|
|
54217
|
+
function ActivityRow({
|
|
54218
|
+
activity,
|
|
54219
|
+
usable,
|
|
54220
|
+
color,
|
|
54221
|
+
now,
|
|
54222
|
+
selectable = false,
|
|
54223
|
+
selected = false,
|
|
54224
|
+
mode = "compact"
|
|
54225
|
+
}) {
|
|
54226
|
+
const { toolWidth, showSummary, showAge, summaryWidth } = activityLayout(usable, selectable);
|
|
54227
|
+
const age = activityAge(activity, now);
|
|
53199
54228
|
const status = activityStatus(activity);
|
|
54229
|
+
const summary = activity.call ? formatActivityCall(activity.call, mode, summaryWidth) : mode === "compact" ? activity.compactSummary ?? activitySummary(activity) : activitySummary(activity);
|
|
53200
54230
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { width: usable, height: 1, flexShrink: 0, children: [
|
|
54231
|
+
selectable ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: ACTIVITY_SELECTOR_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? COLORS.purpleReadable : void 0, children: selected ? "\u203A" : " " }) }) : null,
|
|
53201
54232
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: ACTIVITY_STATUS_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? status.tone : void 0, children: status.symbol }) }),
|
|
53202
54233
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: toolWidth, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53203
54234
|
Text2,
|
|
53204
54235
|
{
|
|
53205
54236
|
bold: true,
|
|
53206
|
-
color: color ? COLORS.ink : void 0,
|
|
54237
|
+
color: color ? selected ? COLORS.purpleReadable : COLORS.ink : void 0,
|
|
53207
54238
|
wrap: "truncate",
|
|
53208
54239
|
children: activity.tool
|
|
53209
54240
|
}
|
|
53210
54241
|
) }),
|
|
53211
|
-
showSummary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { marginLeft: 2, flexGrow: 1, flexShrink: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, wrap: "truncate
|
|
54242
|
+
showSummary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { marginLeft: 2, flexGrow: 1, flexShrink: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, wrap: "truncate", children: summary }) }) : null,
|
|
53212
54243
|
showAge ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53213
54244
|
Box_default,
|
|
53214
54245
|
{
|
|
@@ -53222,10 +54253,9 @@ function ActivityRow({ activity, usable, color, now }) {
|
|
|
53222
54253
|
] });
|
|
53223
54254
|
}
|
|
53224
54255
|
function ActivityView({ state, usable, bodyBudget, color, now }) {
|
|
53225
|
-
const
|
|
53226
|
-
const
|
|
53227
|
-
const
|
|
53228
|
-
const visible = capacity > 0 ? state.activities.slice(pageStart, pageEnd) : [];
|
|
54256
|
+
const window2 = activityWindow(state, bodyBudget);
|
|
54257
|
+
const visible = window2.capacity > 0 ? state.activities.slice(window2.start, window2.end) : [];
|
|
54258
|
+
const selection = selectedActivity(state)?.requestId;
|
|
53229
54259
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { height: bodyBudget, flexDirection: "column", flexShrink: 0, overflow: "hidden", children: [
|
|
53230
54260
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53231
54261
|
state.activities.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "No activity yet." }) : visible.map((activity) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -53234,25 +54264,132 @@ function ActivityView({ state, usable, bodyBudget, color, now }) {
|
|
|
53234
54264
|
activity,
|
|
53235
54265
|
usable,
|
|
53236
54266
|
color,
|
|
53237
|
-
now
|
|
54267
|
+
now,
|
|
54268
|
+
selectable: true,
|
|
54269
|
+
selected: activity.requestId === selection,
|
|
54270
|
+
mode: state.activityMode
|
|
53238
54271
|
},
|
|
53239
54272
|
activity.requestId
|
|
53240
54273
|
))
|
|
53241
54274
|
] });
|
|
53242
54275
|
}
|
|
53243
|
-
function
|
|
53244
|
-
|
|
53245
|
-
|
|
53246
|
-
|
|
53247
|
-
|
|
53248
|
-
|
|
53249
|
-
|
|
54276
|
+
function wrapDetailValue(value, width) {
|
|
54277
|
+
if (width <= 0) return [""];
|
|
54278
|
+
const characters = Array.from(value);
|
|
54279
|
+
if (characters.length <= width) return [value];
|
|
54280
|
+
const lines = [];
|
|
54281
|
+
let remaining = characters;
|
|
54282
|
+
while (remaining.length > width) {
|
|
54283
|
+
let cut = width;
|
|
54284
|
+
for (let index = width - 1; index >= Math.floor(width * 0.55); index -= 1) {
|
|
54285
|
+
if (remaining[index] === " ") {
|
|
54286
|
+
cut = index;
|
|
54287
|
+
break;
|
|
54288
|
+
}
|
|
54289
|
+
}
|
|
54290
|
+
lines.push(remaining.slice(0, cut).join(""));
|
|
54291
|
+
remaining = remaining.slice(cut);
|
|
54292
|
+
while (remaining[0] === " ") remaining = remaining.slice(1);
|
|
54293
|
+
}
|
|
54294
|
+
if (remaining.length > 0) lines.push(remaining.join(""));
|
|
54295
|
+
return lines;
|
|
54296
|
+
}
|
|
54297
|
+
function detailFieldLines(label, value, usable) {
|
|
54298
|
+
const labelWidth = Math.min(14, Math.max(8, Math.floor(usable * 0.3)));
|
|
54299
|
+
const valueWidth = Math.max(1, usable - labelWidth);
|
|
54300
|
+
return wrapDetailValue(value, valueWidth).map((part, index) => ({
|
|
54301
|
+
label: index === 0 ? label : "",
|
|
54302
|
+
value: part
|
|
54303
|
+
}));
|
|
54304
|
+
}
|
|
54305
|
+
function activityInspectOutputLines(activity, usable) {
|
|
54306
|
+
const preview = activity.output?.preview;
|
|
54307
|
+
if (!preview) return [];
|
|
54308
|
+
const tone = activity.output?.kind === "error" ? COLORS.coral : void 0;
|
|
54309
|
+
const lines = [];
|
|
54310
|
+
for (const part of preview.split("\n")) {
|
|
54311
|
+
for (const wrapped of wrapDetailValue(part || " ", usable)) {
|
|
54312
|
+
lines.push({ value: wrapped, fullWidth: true, ...tone ? { tone } : {} });
|
|
54313
|
+
}
|
|
54314
|
+
}
|
|
54315
|
+
return lines;
|
|
54316
|
+
}
|
|
54317
|
+
function formatClock(timestamp) {
|
|
54318
|
+
const date5 = new Date(timestamp);
|
|
54319
|
+
return `${String(date5.getHours()).padStart(2, "0")}:${String(date5.getMinutes()).padStart(2, "0")}:${String(date5.getSeconds()).padStart(2, "0")}`;
|
|
54320
|
+
}
|
|
54321
|
+
function activityInspectLines(activity, usable, now) {
|
|
54322
|
+
const lines = [{}];
|
|
54323
|
+
if (activity.call) {
|
|
54324
|
+
for (const field of activityCallDetailFields(activity.call)) {
|
|
54325
|
+
lines.push(...detailFieldLines(field.label, field.value, usable));
|
|
54326
|
+
}
|
|
54327
|
+
} else {
|
|
54328
|
+
const reason = activity.callUnavailable === "oversized" ? "Full invocation metadata exceeded the local Activity detail budget and was not retained." : "Full invocation metadata has expired from the local Activity detail budget; the compact history remains available.";
|
|
54329
|
+
lines.push(...detailFieldLines("details", reason, usable));
|
|
54330
|
+
}
|
|
54331
|
+
if (activity.startedAt !== void 0) {
|
|
54332
|
+
lines.push(...detailFieldLines("started", formatClock(activity.startedAt), usable));
|
|
54333
|
+
const end = activity.state === "working" ? now : activity.updatedAt ?? now;
|
|
54334
|
+
lines.push(...detailFieldLines("duration", liveDuration(end - activity.startedAt), usable));
|
|
54335
|
+
}
|
|
54336
|
+
lines.push({}, { separator: true }, {}, { section: "Output" });
|
|
54337
|
+
lines.push(...activityInspectOutputLines(activity, usable));
|
|
54338
|
+
return lines;
|
|
54339
|
+
}
|
|
54340
|
+
function ActivityDetailLine({ line, usable, color }) {
|
|
54341
|
+
if (line.section) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, children: line.section });
|
|
54342
|
+
if (line.separator) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Line, { usable, color });
|
|
54343
|
+
if (line.fullWidth) {
|
|
54344
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54345
|
+
Text2,
|
|
54346
|
+
{
|
|
54347
|
+
bold: Boolean(line.bold),
|
|
54348
|
+
color: color ? line.tone ?? COLORS.ink : void 0,
|
|
54349
|
+
wrap: "truncate",
|
|
54350
|
+
children: line.value ?? ""
|
|
54351
|
+
}
|
|
54352
|
+
);
|
|
54353
|
+
}
|
|
54354
|
+
if (line.label === void 0 && line.value === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {});
|
|
54355
|
+
const labelWidth = Math.min(14, Math.max(8, Math.floor(usable * 0.3)));
|
|
54356
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { width: usable, height: 1, flexShrink: 0, children: [
|
|
54357
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: labelWidth, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: line.label ?? "" }) }),
|
|
54358
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54359
|
+
Text2,
|
|
54360
|
+
{
|
|
54361
|
+
bold: Boolean(line.bold),
|
|
54362
|
+
color: color ? line.tone ?? COLORS.ink : void 0,
|
|
54363
|
+
wrap: "truncate",
|
|
54364
|
+
children: line.value ?? ""
|
|
54365
|
+
}
|
|
54366
|
+
)
|
|
53250
54367
|
] });
|
|
53251
54368
|
}
|
|
54369
|
+
function ActivityDetailView({ state, usable, bodyBudget, color, now }) {
|
|
54370
|
+
const activity = selectedActivity(state);
|
|
54371
|
+
if (!activity) {
|
|
54372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { height: bodyBudget, flexDirection: "column", flexShrink: 0, overflow: "hidden", children: [
|
|
54373
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
54374
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "No activity selected." })
|
|
54375
|
+
] });
|
|
54376
|
+
}
|
|
54377
|
+
const lines = activityInspectLines(activity, usable, now);
|
|
54378
|
+
const maxScroll = Math.max(0, lines.length - bodyBudget);
|
|
54379
|
+
const scroll = Math.min(state.activityDetailScroll, maxScroll);
|
|
54380
|
+
const visible = lines.slice(scroll, scroll + bodyBudget);
|
|
54381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { height: bodyBudget, flexDirection: "column", flexShrink: 0, overflow: "hidden", children: visible.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActivityDetailLine, { line, usable, color }, `${scroll}-${index}`)) });
|
|
54382
|
+
}
|
|
54383
|
+
function activityDetailMaxScroll(state, usable, bodyBudget, now) {
|
|
54384
|
+
const activity = selectedActivity(state);
|
|
54385
|
+
if (!activity) return 0;
|
|
54386
|
+
return Math.max(0, activityInspectLines(activity, usable, now).length - bodyBudget);
|
|
54387
|
+
}
|
|
53252
54388
|
function DeviceRow({ device, selected, usable, color }) {
|
|
53253
54389
|
const active = device.status.includes("active");
|
|
53254
54390
|
const tone = active ? COLORS.purpleReadable : COLORS.muted;
|
|
53255
54391
|
const selector = selected ? "\u203A" : " ";
|
|
54392
|
+
const name = device.current ? `${device.name} \xB7 this device` : device.name;
|
|
53256
54393
|
if (usable < 64) {
|
|
53257
54394
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { width: usable, children: [
|
|
53258
54395
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 2, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? COLORS.purpleReadable : void 0, children: selector }) }),
|
|
@@ -53262,7 +54399,7 @@ function DeviceRow({ device, selected, usable, color }) {
|
|
|
53262
54399
|
bold: selected,
|
|
53263
54400
|
color: color ? selected ? COLORS.purpleReadable : tone : void 0,
|
|
53264
54401
|
wrap: "truncate",
|
|
53265
|
-
children: `${
|
|
54402
|
+
children: `${name} \xB7 ${device.status} \xB7 ${device.platform} \xB7 ${device.lastSeen}`
|
|
53266
54403
|
}
|
|
53267
54404
|
)
|
|
53268
54405
|
] });
|
|
@@ -53275,12 +54412,12 @@ function DeviceRow({ device, selected, usable, color }) {
|
|
|
53275
54412
|
bold: selected,
|
|
53276
54413
|
color: color ? selected ? COLORS.purpleReadable : COLORS.ink : void 0,
|
|
53277
54414
|
wrap: "truncate",
|
|
53278
|
-
children:
|
|
54415
|
+
children: name
|
|
53279
54416
|
}
|
|
53280
54417
|
) }),
|
|
53281
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width:
|
|
54418
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 20, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? tone : void 0, wrap: "truncate", children: device.status }) }),
|
|
53282
54419
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 14, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, wrap: "truncate", children: device.platform }) }),
|
|
53283
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width:
|
|
54420
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 14, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, wrap: "truncate", children: device.lastSeen }) })
|
|
53284
54421
|
] });
|
|
53285
54422
|
}
|
|
53286
54423
|
function DeviceHeading({ usable, color }) {
|
|
@@ -53288,9 +54425,9 @@ function DeviceHeading({ usable, color }) {
|
|
|
53288
54425
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { width: usable, children: [
|
|
53289
54426
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 2 }),
|
|
53290
54427
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "Device" }) }),
|
|
53291
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width:
|
|
54428
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 20, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "Workspaces" }) }),
|
|
53292
54429
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "Platform" }) }),
|
|
53293
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width:
|
|
54430
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "Last seen" }) })
|
|
53294
54431
|
] });
|
|
53295
54432
|
}
|
|
53296
54433
|
function DevicesView({ state, usable, bodyBudget, color }) {
|
|
@@ -53298,98 +54435,47 @@ function DevicesView({ state, usable, bodyBudget, color }) {
|
|
|
53298
54435
|
const devices = state.status?.devices.slice(window2.start, window2.end) ?? [];
|
|
53299
54436
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { height: bodyBudget, flexDirection: "column", flexShrink: 0, overflow: "hidden", children: [
|
|
53300
54437
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53301
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53302
|
-
|
|
53303
|
-
|
|
53304
|
-
|
|
53305
|
-
|
|
53306
|
-
|
|
53307
|
-
|
|
53308
|
-
|
|
53309
|
-
|
|
53310
|
-
|
|
53311
|
-
|
|
53312
|
-
|
|
53313
|
-
|
|
53314
|
-
|
|
53315
|
-
|
|
53316
|
-
value: state.status.activeWorkers === null ? "Unavailable" : String(state.status.activeWorkers),
|
|
53317
|
-
label: "Active workspaces",
|
|
53318
|
-
color
|
|
53319
|
-
}
|
|
53320
|
-
),
|
|
53321
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Metric, { value: String(state.status.devices.length), label: "Devices", color }),
|
|
53322
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53323
|
-
state.status.devices.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "No devices." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
53324
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeviceHeading, { usable, color }),
|
|
53325
|
-
devices.map((device, index) => {
|
|
53326
|
-
const deviceIndex = window2.start + index;
|
|
53327
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53328
|
-
DeviceRow,
|
|
53329
|
-
{
|
|
53330
|
-
device,
|
|
53331
|
-
selected: deviceIndex === window2.selection,
|
|
53332
|
-
usable,
|
|
53333
|
-
color
|
|
53334
|
-
},
|
|
53335
|
-
device.id
|
|
53336
|
-
);
|
|
53337
|
-
})
|
|
53338
|
-
] })
|
|
54438
|
+
state.statusLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "Loading\u2026" }) : !state.status ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "Devices unavailable." }) : state.status.devices.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: "No paired devices." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
54439
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeviceHeading, { usable, color }),
|
|
54440
|
+
devices.map((device, index) => {
|
|
54441
|
+
const deviceIndex = window2.start + index;
|
|
54442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54443
|
+
DeviceRow,
|
|
54444
|
+
{
|
|
54445
|
+
device,
|
|
54446
|
+
selected: deviceIndex === window2.selection,
|
|
54447
|
+
usable,
|
|
54448
|
+
color
|
|
54449
|
+
},
|
|
54450
|
+
device.id
|
|
54451
|
+
);
|
|
54452
|
+
})
|
|
53339
54453
|
] })
|
|
53340
54454
|
] });
|
|
53341
54455
|
}
|
|
53342
|
-
function HelpRow({ keyLabel, label, color, tone = COLORS.purpleReadable }) {
|
|
53343
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { children: [
|
|
53344
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { width: 8, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? tone : void 0, children: keyLabel }) }),
|
|
53345
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, wrap: "truncate", children: label })
|
|
53346
|
-
] });
|
|
53347
|
-
}
|
|
53348
|
-
function HelpView({ bodyBudget, color }) {
|
|
53349
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { height: bodyBudget, flexDirection: "column", flexShrink: 0, overflow: "hidden", children: [
|
|
53350
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53351
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, children: "Navigate" }),
|
|
53352
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "A", label: "Activity", color }),
|
|
53353
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "W", label: "Workspace", color }),
|
|
53354
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "D", label: "Devices", color }),
|
|
53355
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "?", label: "Help", color }),
|
|
53356
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "Esc", label: "Workspace", color }),
|
|
53357
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53358
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, tone: COLORS.coral, children: "Manage" }),
|
|
53359
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "\u2190/\u2192", label: "Change workspace access", color, tone: COLORS.coral }),
|
|
53360
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "Enter/R", label: "Revoke selected device", color, tone: COLORS.coral }),
|
|
53361
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Blank, {}),
|
|
53362
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionTitle, { color, children: "App" }),
|
|
53363
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "Q", label: "Disconnect and quit", color, tone: COLORS.coral }),
|
|
53364
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(HelpRow, { keyLabel: "Ctrl+C", label: "Disconnect and quit", color, tone: COLORS.coral })
|
|
53365
|
-
] });
|
|
53366
|
-
}
|
|
53367
54456
|
function Overlay({ state, usable, color }) {
|
|
53368
|
-
const
|
|
53369
|
-
|
|
53370
|
-
if (!message) return null;
|
|
54457
|
+
const overlay = overlayContent(state, usable);
|
|
54458
|
+
if (!overlay) return null;
|
|
53371
54459
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", flexShrink: 0, children: [
|
|
53372
54460
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Line, { usable, color }),
|
|
53373
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54461
|
+
overlay.lines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53374
54462
|
Text2,
|
|
53375
54463
|
{
|
|
53376
|
-
bold:
|
|
53377
|
-
color: color ?
|
|
54464
|
+
bold: overlay.bold,
|
|
54465
|
+
color: color ? overlay.tone : void 0,
|
|
53378
54466
|
wrap: "truncate",
|
|
53379
|
-
children:
|
|
53380
|
-
}
|
|
53381
|
-
|
|
53382
|
-
|
|
54467
|
+
children: line
|
|
54468
|
+
},
|
|
54469
|
+
index
|
|
54470
|
+
)),
|
|
54471
|
+
overlay.choices ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, wrap: "truncate", children: overlay.choices }) : null
|
|
53383
54472
|
] });
|
|
53384
54473
|
}
|
|
53385
54474
|
function FooterHintGroup({ hints, color }) {
|
|
53386
54475
|
return hints.map((hint, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react34.default.Fragment, { children: [
|
|
53387
54476
|
index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { children: " " }) : null,
|
|
53388
54477
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { bold: true, color: color ? hint.tone ?? COLORS.purpleReadable : void 0, children: hint.key }),
|
|
53389
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
53390
|
-
" ",
|
|
53391
|
-
hint.label
|
|
53392
|
-
] })
|
|
54478
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text2, { color: color ? COLORS.muted : void 0, children: ` ${hint.label.padEnd(Math.max(hint.label.length, hint.labelWidth ?? 0))}` })
|
|
53393
54479
|
] }, `${hint.key}-${hint.label}`));
|
|
53394
54480
|
}
|
|
53395
54481
|
function Footer({ rows, usable, color }) {
|
|
@@ -53423,6 +54509,15 @@ function HudScreen({ state, columns, rows, color = true, now = Date.now() }) {
|
|
|
53423
54509
|
color,
|
|
53424
54510
|
now
|
|
53425
54511
|
}
|
|
54512
|
+
) : state.view === "activity-detail" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54513
|
+
ActivityDetailView,
|
|
54514
|
+
{
|
|
54515
|
+
state,
|
|
54516
|
+
usable: metrics.usable,
|
|
54517
|
+
bodyBudget: metrics.bodyBudget,
|
|
54518
|
+
color,
|
|
54519
|
+
now
|
|
54520
|
+
}
|
|
53426
54521
|
) : state.view === "devices" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53427
54522
|
DevicesView,
|
|
53428
54523
|
{
|
|
@@ -53431,7 +54526,7 @@ function HudScreen({ state, columns, rows, color = true, now = Date.now() }) {
|
|
|
53431
54526
|
bodyBudget: metrics.bodyBudget,
|
|
53432
54527
|
color
|
|
53433
54528
|
}
|
|
53434
|
-
) :
|
|
54529
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53435
54530
|
WorkspaceView,
|
|
53436
54531
|
{
|
|
53437
54532
|
state,
|
|
@@ -53440,7 +54535,7 @@ function HudScreen({ state, columns, rows, color = true, now = Date.now() }) {
|
|
|
53440
54535
|
color,
|
|
53441
54536
|
now
|
|
53442
54537
|
}
|
|
53443
|
-
)
|
|
54538
|
+
),
|
|
53444
54539
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overlay, { state, usable: metrics.usable, color }),
|
|
53445
54540
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Footer, { rows: metrics.footerRows, usable: metrics.usable, color })
|
|
53446
54541
|
] });
|
|
@@ -53452,13 +54547,15 @@ async function loadDevices(store2, actions, signal) {
|
|
|
53452
54547
|
...state,
|
|
53453
54548
|
view: "devices",
|
|
53454
54549
|
prompt: void 0,
|
|
53455
|
-
notice: void 0
|
|
54550
|
+
notice: void 0,
|
|
54551
|
+
noticeTone: void 0
|
|
53456
54552
|
}));
|
|
53457
54553
|
if (current.statusLoading) return;
|
|
53458
54554
|
if (current.connection !== "connected" && current.connection !== "retrying") {
|
|
53459
54555
|
store2.update((state) => ({
|
|
53460
54556
|
...state,
|
|
53461
|
-
notice: "Devices are available after Glossa connects."
|
|
54557
|
+
notice: "Devices are available after Glossa connects.",
|
|
54558
|
+
noticeTone: "info"
|
|
53462
54559
|
}));
|
|
53463
54560
|
return;
|
|
53464
54561
|
}
|
|
@@ -53483,7 +54580,8 @@ async function loadDevices(store2, actions, signal) {
|
|
|
53483
54580
|
store2.update((state) => ({
|
|
53484
54581
|
...state,
|
|
53485
54582
|
statusLoading: false,
|
|
53486
|
-
notice: error46 instanceof Error ? error46.message : String(error46)
|
|
54583
|
+
notice: error46 instanceof Error ? error46.message : String(error46),
|
|
54584
|
+
noticeTone: "error"
|
|
53487
54585
|
}));
|
|
53488
54586
|
}
|
|
53489
54587
|
}
|
|
@@ -53491,9 +54589,11 @@ function beginAccessChange(store2, actions, accessProfile) {
|
|
|
53491
54589
|
actions.changeAccessProfile(accessProfile);
|
|
53492
54590
|
store2.update((state) => ({
|
|
53493
54591
|
...state,
|
|
54592
|
+
connection: "connecting",
|
|
53494
54593
|
pendingAccessProfile: accessProfile,
|
|
53495
54594
|
prompt: void 0,
|
|
53496
|
-
notice: void 0
|
|
54595
|
+
notice: void 0,
|
|
54596
|
+
noticeTone: void 0
|
|
53497
54597
|
}));
|
|
53498
54598
|
}
|
|
53499
54599
|
function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
@@ -53501,19 +54601,25 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53501
54601
|
const { columns, rows } = use_window_size_default();
|
|
53502
54602
|
const [, setClock] = (0, import_react34.useState)(0);
|
|
53503
54603
|
(0, import_react34.useEffect)(() => {
|
|
53504
|
-
if (state.view !== "activity" && state.view !== "workspace" || state.activities.length === 0) return;
|
|
53505
|
-
const
|
|
54604
|
+
if (state.view !== "activity" && state.view !== "activity-detail" && state.view !== "workspace" || state.activities.length === 0) return;
|
|
54605
|
+
const hasWorkingActivity = state.activities.some((activity) => activity.state === "working");
|
|
54606
|
+
const interval = hasWorkingActivity ? ACTIVITY_LIVE_REFRESH_INTERVAL_MS : ACTIVITY_IDLE_REFRESH_INTERVAL_MS;
|
|
54607
|
+
const timer = setInterval(() => setClock((value) => value + 1), interval);
|
|
53506
54608
|
return () => clearInterval(timer);
|
|
53507
|
-
}, [state.view, state.activities
|
|
54609
|
+
}, [state.view, state.activities]);
|
|
53508
54610
|
(0, import_react34.useEffect)(() => {
|
|
53509
54611
|
store2.update((current) => {
|
|
53510
54612
|
let next = current;
|
|
53511
54613
|
const metrics = screenMetrics(current, columns, rows);
|
|
53512
|
-
if (current.view === "activity") {
|
|
53513
|
-
const
|
|
53514
|
-
|
|
53515
|
-
|
|
53516
|
-
|
|
54614
|
+
if (current.view === "activity-detail") {
|
|
54615
|
+
const maxScroll = activityDetailMaxScroll(
|
|
54616
|
+
current,
|
|
54617
|
+
metrics.usable,
|
|
54618
|
+
metrics.bodyBudget,
|
|
54619
|
+
Date.now()
|
|
54620
|
+
);
|
|
54621
|
+
if (current.activityDetailScroll > maxScroll) {
|
|
54622
|
+
next = { ...next, activityDetailScroll: maxScroll };
|
|
53517
54623
|
}
|
|
53518
54624
|
}
|
|
53519
54625
|
if (current.prompt?.type === "revoke-confirm") {
|
|
@@ -53522,7 +54628,8 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53522
54628
|
next = {
|
|
53523
54629
|
...next,
|
|
53524
54630
|
prompt: void 0,
|
|
53525
|
-
notice: "Increase the terminal height to choose a device."
|
|
54631
|
+
notice: "Increase the terminal height to choose a device.",
|
|
54632
|
+
noticeTone: "info"
|
|
53526
54633
|
};
|
|
53527
54634
|
}
|
|
53528
54635
|
}
|
|
@@ -53539,7 +54646,12 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53539
54646
|
if (current.busy) return;
|
|
53540
54647
|
if (current.prompt) {
|
|
53541
54648
|
if (key.escape || value === "n") {
|
|
53542
|
-
store2.update((state2) => ({
|
|
54649
|
+
store2.update((state2) => ({
|
|
54650
|
+
...state2,
|
|
54651
|
+
prompt: void 0,
|
|
54652
|
+
notice: void 0,
|
|
54653
|
+
noticeTone: void 0
|
|
54654
|
+
}));
|
|
53543
54655
|
return;
|
|
53544
54656
|
}
|
|
53545
54657
|
if (value !== "y") return;
|
|
@@ -53552,34 +54664,121 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53552
54664
|
store2.update((state2) => ({
|
|
53553
54665
|
...state2,
|
|
53554
54666
|
busy: true,
|
|
54667
|
+
busyMessage: `Revoking ${device.name}\u2026`,
|
|
53555
54668
|
prompt: void 0,
|
|
53556
|
-
notice: void 0
|
|
54669
|
+
notice: void 0,
|
|
54670
|
+
noticeTone: void 0
|
|
53557
54671
|
}));
|
|
53558
54672
|
void actions.revokeDevice(device.id, signal).then(async () => {
|
|
53559
54673
|
if (signal.aborted) return;
|
|
53560
|
-
store2.update((state2) => ({ ...state2, busy: false }));
|
|
54674
|
+
store2.update((state2) => ({ ...state2, busy: false, busyMessage: void 0 }));
|
|
53561
54675
|
await loadDevices(store2, actions, signal);
|
|
53562
54676
|
if (signal.aborted) return;
|
|
53563
|
-
store2.update((state2) => ({
|
|
54677
|
+
store2.update((state2) => ({
|
|
54678
|
+
...state2,
|
|
54679
|
+
notice: `Revoked ${device.name}.`,
|
|
54680
|
+
noticeTone: "success"
|
|
54681
|
+
}));
|
|
53564
54682
|
}).catch((error46) => {
|
|
53565
54683
|
if (signal.aborted) return;
|
|
53566
54684
|
store2.update((state2) => ({
|
|
53567
54685
|
...state2,
|
|
53568
54686
|
busy: false,
|
|
53569
|
-
|
|
54687
|
+
busyMessage: void 0,
|
|
54688
|
+
notice: error46 instanceof Error ? error46.message : String(error46),
|
|
54689
|
+
noticeTone: "error"
|
|
53570
54690
|
}));
|
|
53571
54691
|
});
|
|
53572
54692
|
return;
|
|
53573
54693
|
}
|
|
53574
|
-
if (current.view === "activity"
|
|
53575
|
-
|
|
53576
|
-
|
|
53577
|
-
|
|
53578
|
-
|
|
53579
|
-
|
|
53580
|
-
|
|
54694
|
+
if (current.view === "activity-detail") {
|
|
54695
|
+
if (key.upArrow || key.downArrow) {
|
|
54696
|
+
const metrics = screenMetrics(current, columns, rows);
|
|
54697
|
+
const maxScroll = activityDetailMaxScroll(
|
|
54698
|
+
current,
|
|
54699
|
+
metrics.usable,
|
|
54700
|
+
metrics.bodyBudget,
|
|
54701
|
+
Date.now()
|
|
54702
|
+
);
|
|
54703
|
+
const activityDetailScroll = key.upArrow ? Math.max(0, current.activityDetailScroll - 1) : Math.min(maxScroll, current.activityDetailScroll + 1);
|
|
54704
|
+
if (activityDetailScroll !== current.activityDetailScroll) {
|
|
54705
|
+
store2.update((state2) => ({ ...state2, activityDetailScroll }));
|
|
54706
|
+
}
|
|
54707
|
+
return;
|
|
54708
|
+
}
|
|
54709
|
+
if (key.escape || key.return || input === "\r" || input === "\n") {
|
|
54710
|
+
store2.update((state2) => ({
|
|
54711
|
+
...state2,
|
|
54712
|
+
view: "activity",
|
|
54713
|
+
activityDetailScroll: 0,
|
|
54714
|
+
notice: void 0
|
|
54715
|
+
}));
|
|
54716
|
+
return;
|
|
54717
|
+
}
|
|
54718
|
+
}
|
|
54719
|
+
if (current.view === "activity") {
|
|
54720
|
+
if (key.tab || input === " ") {
|
|
54721
|
+
store2.update((state2) => ({
|
|
54722
|
+
...state2,
|
|
54723
|
+
activityMode: state2.activityMode === "compact" ? "detailed" : "compact",
|
|
54724
|
+
notice: void 0
|
|
54725
|
+
}));
|
|
54726
|
+
return;
|
|
54727
|
+
}
|
|
54728
|
+
if (key.escape && current.activitySelection) {
|
|
54729
|
+
store2.update((state2) => ({
|
|
54730
|
+
...state2,
|
|
54731
|
+
activitySelection: void 0,
|
|
54732
|
+
notice: void 0
|
|
54733
|
+
}));
|
|
54734
|
+
return;
|
|
54735
|
+
}
|
|
54736
|
+
if (key.upArrow || key.downArrow) {
|
|
54737
|
+
const metrics = screenMetrics(current, columns, rows);
|
|
54738
|
+
if (current.activitySelection) {
|
|
54739
|
+
const update = activitySelectionUpdate(
|
|
54740
|
+
current,
|
|
54741
|
+
metrics.bodyBudget,
|
|
54742
|
+
key.upArrow ? -1 : 1
|
|
54743
|
+
);
|
|
54744
|
+
if (update) {
|
|
54745
|
+
store2.update((state2) => ({ ...state2, ...update, notice: void 0 }));
|
|
54746
|
+
}
|
|
54747
|
+
} else {
|
|
54748
|
+
const update = activityPageUpdate(
|
|
54749
|
+
current,
|
|
54750
|
+
metrics.bodyBudget,
|
|
54751
|
+
key.upArrow ? "older" : "newer"
|
|
54752
|
+
);
|
|
54753
|
+
if (update) {
|
|
54754
|
+
store2.update((state2) => ({ ...state2, ...update, notice: void 0 }));
|
|
54755
|
+
}
|
|
54756
|
+
}
|
|
54757
|
+
return;
|
|
54758
|
+
}
|
|
54759
|
+
if (key.return || input === "\r" || input === "\n") {
|
|
54760
|
+
if (!current.activitySelection) {
|
|
54761
|
+
const metrics = screenMetrics(current, columns, rows);
|
|
54762
|
+
const activitySelection = activityCenterSelection(current, metrics.bodyBudget);
|
|
54763
|
+
if (activitySelection) {
|
|
54764
|
+
store2.update((state2) => ({
|
|
54765
|
+
...state2,
|
|
54766
|
+
activitySelection,
|
|
54767
|
+
notice: void 0
|
|
54768
|
+
}));
|
|
54769
|
+
}
|
|
54770
|
+
return;
|
|
54771
|
+
}
|
|
54772
|
+
const selected = selectedActivity(current);
|
|
54773
|
+
if (!selected) return;
|
|
54774
|
+
store2.update((state2) => ({
|
|
54775
|
+
...state2,
|
|
54776
|
+
view: "activity-detail",
|
|
54777
|
+
activityDetailScroll: 0,
|
|
54778
|
+
notice: void 0
|
|
54779
|
+
}));
|
|
54780
|
+
return;
|
|
53581
54781
|
}
|
|
53582
|
-
return;
|
|
53583
54782
|
}
|
|
53584
54783
|
if (current.view === "devices" && (key.upArrow || key.downArrow)) {
|
|
53585
54784
|
const total = current.status?.devices.length ?? 0;
|
|
@@ -53593,7 +54792,7 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53593
54792
|
}
|
|
53594
54793
|
return;
|
|
53595
54794
|
}
|
|
53596
|
-
if (current.view === "workspace" && current.accessProfile && !current.pendingAccessProfile && (key.leftArrow || key.rightArrow)) {
|
|
54795
|
+
if (current.view === "workspace" && current.connection === "connected" && current.accessProfile && !current.pendingAccessProfile && (key.leftArrow || key.rightArrow)) {
|
|
53597
54796
|
const direction = key.leftArrow ? -1 : 1;
|
|
53598
54797
|
const accessProfile = adjacentAccessProfile(current.accessProfile, direction);
|
|
53599
54798
|
if (!accessProfile) return;
|
|
@@ -53613,10 +54812,13 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53613
54812
|
return;
|
|
53614
54813
|
}
|
|
53615
54814
|
if (value === "a") {
|
|
54815
|
+
const preserveBrowsePage = current.view === "activity" || current.view === "activity-detail";
|
|
53616
54816
|
store2.update((state2) => ({
|
|
53617
54817
|
...state2,
|
|
53618
54818
|
view: "activity",
|
|
53619
|
-
|
|
54819
|
+
activitySelection: void 0,
|
|
54820
|
+
activityBrowseAnchor: preserveBrowsePage ? state2.activityBrowseAnchor : void 0,
|
|
54821
|
+
activityDetailScroll: 0,
|
|
53620
54822
|
notice: void 0
|
|
53621
54823
|
}));
|
|
53622
54824
|
return;
|
|
@@ -53646,27 +54848,29 @@ function HudRuntime({ store: store2, actions, signal, stop }) {
|
|
|
53646
54848
|
if ((key.return || input === "\r" || input === "\n" || value === "r") && current.view === "devices") {
|
|
53647
54849
|
const count = current.status?.devices.length ?? 0;
|
|
53648
54850
|
if (count === 0) {
|
|
53649
|
-
store2.update((state2) => ({
|
|
54851
|
+
store2.update((state2) => ({
|
|
54852
|
+
...state2,
|
|
54853
|
+
notice: "There are no paired devices to revoke.",
|
|
54854
|
+
noticeTone: "info"
|
|
54855
|
+
}));
|
|
53650
54856
|
return;
|
|
53651
54857
|
}
|
|
53652
54858
|
const metrics = screenMetrics(current, columns, rows);
|
|
53653
54859
|
const capacity = statusDeviceCapacity(current, metrics.bodyBudget, metrics.usable);
|
|
53654
54860
|
const selection = Math.min(current.deviceSelection, count - 1);
|
|
53655
|
-
store2.update((state2) => capacity === 0 ? {
|
|
54861
|
+
store2.update((state2) => capacity === 0 ? {
|
|
54862
|
+
...state2,
|
|
54863
|
+
notice: "Increase the terminal height to choose a device.",
|
|
54864
|
+
noticeTone: "info"
|
|
54865
|
+
} : {
|
|
53656
54866
|
...state2,
|
|
53657
54867
|
deviceSelection: selection,
|
|
53658
54868
|
prompt: { type: "revoke-confirm", deviceIndex: selection },
|
|
53659
|
-
notice: void 0
|
|
54869
|
+
notice: void 0,
|
|
54870
|
+
noticeTone: void 0
|
|
53660
54871
|
});
|
|
53661
54872
|
return;
|
|
53662
54873
|
}
|
|
53663
|
-
if (input === "?") {
|
|
53664
|
-
store2.update((state2) => ({
|
|
53665
|
-
...state2,
|
|
53666
|
-
view: "help",
|
|
53667
|
-
notice: void 0
|
|
53668
|
-
}));
|
|
53669
|
-
}
|
|
53670
54874
|
});
|
|
53671
54875
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
53672
54876
|
HudScreen,
|
|
@@ -53684,7 +54888,7 @@ async function runSessionHud(actions, input = process.stdin, output = process.st
|
|
|
53684
54888
|
throw new Error("Glossa requires an interactive terminal.");
|
|
53685
54889
|
}
|
|
53686
54890
|
const controller = new AbortController();
|
|
53687
|
-
const store2 = new HudStore(actions.workspace);
|
|
54891
|
+
const store2 = new HudStore(actions.workspace, actions.initialNotice);
|
|
53688
54892
|
let instance;
|
|
53689
54893
|
const stop = () => {
|
|
53690
54894
|
controller.abort();
|
|
@@ -53745,8 +54949,8 @@ async function runSessionHud(actions, input = process.stdin, output = process.st
|
|
|
53745
54949
|
var import_semver = __toESM(require_semver2(), 1);
|
|
53746
54950
|
import { spawn as spawn2 } from "node:child_process";
|
|
53747
54951
|
import { createHash as createHash2 } from "node:crypto";
|
|
53748
|
-
import { chmod as
|
|
53749
|
-
import
|
|
54952
|
+
import { chmod as chmod4, readdir as readdir2, rename as rename3, rm as rm6, writeFile as writeFile7 } from "node:fs/promises";
|
|
54953
|
+
import path9 from "node:path";
|
|
53750
54954
|
var PACKAGE_NAME = "@ariobarin/glossa";
|
|
53751
54955
|
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org/@ariobarin%2Fglossa";
|
|
53752
54956
|
var DEFAULT_RELEASE_BASE_URL = "https://github.com/ariobarin/glossa/releases/download";
|
|
@@ -53823,8 +55027,8 @@ async function cleanupUpdateBackups(distribution, options = {}) {
|
|
|
53823
55027
|
const platform2 = options.platform ?? process.platform;
|
|
53824
55028
|
if (distribution !== "standalone" || platform2 !== "win32") return;
|
|
53825
55029
|
const executable = options.executablePath ?? process.execPath;
|
|
53826
|
-
const directory =
|
|
53827
|
-
const prefix = `${
|
|
55030
|
+
const directory = path9.dirname(executable);
|
|
55031
|
+
const prefix = `${path9.basename(executable)}.old-`;
|
|
53828
55032
|
let entries;
|
|
53829
55033
|
try {
|
|
53830
55034
|
entries = await readdir2(directory, { withFileTypes: true });
|
|
@@ -53837,7 +55041,7 @@ async function cleanupUpdateBackups(distribution, options = {}) {
|
|
|
53837
55041
|
const ownerPid = backupOwnerPid(entry.name, prefix);
|
|
53838
55042
|
return ownerPid !== null && !processIsAlive(ownerPid);
|
|
53839
55043
|
}).map(async (entry) => {
|
|
53840
|
-
await
|
|
55044
|
+
await rm6(path9.join(directory, entry.name), { force: true }).catch(() => void 0);
|
|
53841
55045
|
})
|
|
53842
55046
|
);
|
|
53843
55047
|
}
|
|
@@ -53888,11 +55092,11 @@ async function runNpmInstall(version2) {
|
|
|
53888
55092
|
}
|
|
53889
55093
|
async function replaceWindowsExecutable(download, destination) {
|
|
53890
55094
|
const backup = `${destination}.old-${process.pid}-${Date.now()}`;
|
|
53891
|
-
await
|
|
55095
|
+
await rename3(destination, backup);
|
|
53892
55096
|
try {
|
|
53893
|
-
await
|
|
55097
|
+
await rename3(download, destination);
|
|
53894
55098
|
} catch (error46) {
|
|
53895
|
-
await
|
|
55099
|
+
await rename3(backup, destination).catch(() => void 0);
|
|
53896
55100
|
throw error46;
|
|
53897
55101
|
}
|
|
53898
55102
|
}
|
|
@@ -53913,21 +55117,21 @@ async function installStandaloneUpdate(info, options) {
|
|
|
53913
55117
|
if (actual !== expected) {
|
|
53914
55118
|
throw new Error("Glossa refused to update because the SHA-256 checksum did not match.");
|
|
53915
55119
|
}
|
|
53916
|
-
const download =
|
|
53917
|
-
|
|
53918
|
-
`${
|
|
55120
|
+
const download = path9.join(
|
|
55121
|
+
path9.dirname(destination),
|
|
55122
|
+
`${path9.basename(destination)}.download-${process.pid}`
|
|
53919
55123
|
);
|
|
53920
55124
|
try {
|
|
53921
|
-
await
|
|
55125
|
+
await writeFile7(download, binary, { mode: 493 });
|
|
53922
55126
|
if (platform2 === "win32") {
|
|
53923
55127
|
await replaceWindowsExecutable(download, destination);
|
|
53924
55128
|
} else {
|
|
53925
|
-
await
|
|
53926
|
-
await
|
|
55129
|
+
await chmod4(download, 493);
|
|
55130
|
+
await rename3(download, destination);
|
|
53927
55131
|
}
|
|
53928
55132
|
return "installed";
|
|
53929
55133
|
} catch (error46) {
|
|
53930
|
-
await
|
|
55134
|
+
await rm6(download, { force: true });
|
|
53931
55135
|
throw error46;
|
|
53932
55136
|
}
|
|
53933
55137
|
}
|
|
@@ -53940,84 +55144,6 @@ async function installUpdate(info, distribution, options = {}) {
|
|
|
53940
55144
|
return await installStandaloneUpdate(info, options);
|
|
53941
55145
|
}
|
|
53942
55146
|
|
|
53943
|
-
// src/update-state.ts
|
|
53944
|
-
import { chmod as chmod4, mkdir as mkdir6, readFile as readFile5, rename as rename3, rm as rm6, writeFile as writeFile7 } from "node:fs/promises";
|
|
53945
|
-
import path9 from "node:path";
|
|
53946
|
-
var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
53947
|
-
function defaultUpdateChannel(version2) {
|
|
53948
|
-
return version2.includes("-") ? "beta" : "stable";
|
|
53949
|
-
}
|
|
53950
|
-
function updateStateFile() {
|
|
53951
|
-
return path9.join(configDirectory(), "updates.json");
|
|
53952
|
-
}
|
|
53953
|
-
function isPolicy(value) {
|
|
53954
|
-
return value === "notify" || value === "auto" || value === "off";
|
|
53955
|
-
}
|
|
53956
|
-
function isChannel(value) {
|
|
53957
|
-
return value === "beta" || value === "stable";
|
|
53958
|
-
}
|
|
53959
|
-
function optionalString(value) {
|
|
53960
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
53961
|
-
}
|
|
53962
|
-
async function loadUpdateState(currentVersion, file2 = updateStateFile()) {
|
|
53963
|
-
const defaults = {
|
|
53964
|
-
policy: "notify",
|
|
53965
|
-
channel: defaultUpdateChannel(currentVersion)
|
|
53966
|
-
};
|
|
53967
|
-
try {
|
|
53968
|
-
const parsed = JSON.parse(await readFile5(file2, "utf8"));
|
|
53969
|
-
const lastCheckedAt = optionalString(parsed.lastCheckedAt);
|
|
53970
|
-
return {
|
|
53971
|
-
policy: isPolicy(parsed.policy) ? parsed.policy : defaults.policy,
|
|
53972
|
-
channel: isChannel(parsed.channel) ? parsed.channel : defaults.channel,
|
|
53973
|
-
...lastCheckedAt ? { lastCheckedAt } : {}
|
|
53974
|
-
};
|
|
53975
|
-
} catch (error46) {
|
|
53976
|
-
if (error46.code === "ENOENT" || error46 instanceof SyntaxError) {
|
|
53977
|
-
return defaults;
|
|
53978
|
-
}
|
|
53979
|
-
throw error46;
|
|
53980
|
-
}
|
|
53981
|
-
}
|
|
53982
|
-
async function saveUpdateState(state, file2 = updateStateFile()) {
|
|
53983
|
-
const directory = path9.dirname(file2);
|
|
53984
|
-
const temporary = `${file2}.${process.pid}.tmp`;
|
|
53985
|
-
await mkdir6(directory, { recursive: true, mode: 448 });
|
|
53986
|
-
try {
|
|
53987
|
-
await writeFile7(temporary, `${JSON.stringify(state, null, 2)}
|
|
53988
|
-
`, {
|
|
53989
|
-
encoding: "utf8",
|
|
53990
|
-
mode: 384
|
|
53991
|
-
});
|
|
53992
|
-
if (process.platform !== "win32") await chmod4(temporary, 384);
|
|
53993
|
-
await rename3(temporary, file2);
|
|
53994
|
-
} finally {
|
|
53995
|
-
await rm6(temporary, { force: true });
|
|
53996
|
-
}
|
|
53997
|
-
}
|
|
53998
|
-
async function configureUpdates(currentVersion, changes, file2 = updateStateFile()) {
|
|
53999
|
-
const previous = await loadUpdateState(currentVersion, file2);
|
|
54000
|
-
const state = {
|
|
54001
|
-
policy: changes.policy ?? previous.policy,
|
|
54002
|
-
channel: changes.channel ?? previous.channel
|
|
54003
|
-
};
|
|
54004
|
-
await saveUpdateState(state, file2);
|
|
54005
|
-
return state;
|
|
54006
|
-
}
|
|
54007
|
-
async function recordUpdateCheck(currentVersion, checkedAt = /* @__PURE__ */ new Date(), file2 = updateStateFile()) {
|
|
54008
|
-
const state = {
|
|
54009
|
-
...await loadUpdateState(currentVersion, file2),
|
|
54010
|
-
lastCheckedAt: checkedAt.toISOString()
|
|
54011
|
-
};
|
|
54012
|
-
await saveUpdateState(state, file2);
|
|
54013
|
-
return state;
|
|
54014
|
-
}
|
|
54015
|
-
function isUpdateCheckDue(lastCheckedAt, now = Date.now()) {
|
|
54016
|
-
if (!lastCheckedAt) return true;
|
|
54017
|
-
const checkedAt = Date.parse(lastCheckedAt);
|
|
54018
|
-
return !Number.isFinite(checkedAt) || now - checkedAt >= UPDATE_CHECK_INTERVAL_MS;
|
|
54019
|
-
}
|
|
54020
|
-
|
|
54021
55147
|
// src/unpair.ts
|
|
54022
55148
|
async function unpairComputer(dependencies = {}) {
|
|
54023
55149
|
const load = dependencies.loadDeviceCredential ?? loadDeviceCredential;
|
|
@@ -54227,7 +55353,7 @@ async function acquireWorkspaceLease(root, options = {}) {
|
|
|
54227
55353
|
}
|
|
54228
55354
|
|
|
54229
55355
|
// src/main.ts
|
|
54230
|
-
var VERSION = "0.2.
|
|
55356
|
+
var VERSION = "0.2.4";
|
|
54231
55357
|
var DISTRIBUTION = "npm";
|
|
54232
55358
|
var HELP = `Glossa ${VERSION}
|
|
54233
55359
|
|
|
@@ -54250,13 +55376,12 @@ Keys:
|
|
|
54250
55376
|
a activity
|
|
54251
55377
|
w workspace
|
|
54252
55378
|
d devices
|
|
54253
|
-
\u2191\u2193
|
|
55379
|
+
\u2191\u2193 browse or select the current list
|
|
54254
55380
|
\u2190\u2192 change workspace access
|
|
54255
|
-
Enter
|
|
54256
|
-
Esc workspace
|
|
54257
|
-
? help
|
|
55381
|
+
Enter select, inspect, or revoke
|
|
55382
|
+
Esc back to the previous view or workspace
|
|
54258
55383
|
q disconnect and quit`;
|
|
54259
|
-
async function runWorkspaceSession(path12, label, accessProfile) {
|
|
55384
|
+
async function runWorkspaceSession(path12, label, accessProfile, initialNotice) {
|
|
54260
55385
|
const root = await selectExposureRoot(path12);
|
|
54261
55386
|
const lease = await acquireWorkspaceLease(root);
|
|
54262
55387
|
try {
|
|
@@ -54268,6 +55393,7 @@ async function runWorkspaceSession(path12, label, accessProfile) {
|
|
|
54268
55393
|
await runSessionHud({
|
|
54269
55394
|
workspace: root,
|
|
54270
55395
|
...label ? { workspaceLabel: label } : {},
|
|
55396
|
+
...initialNotice ? { initialNotice } : {},
|
|
54271
55397
|
run: async (signal, onEvent) => {
|
|
54272
55398
|
while (!signal.aborted) {
|
|
54273
55399
|
const sessionAccessProfile = requestedAccessProfile;
|
|
@@ -54316,7 +55442,8 @@ async function runWorkspaceSession(path12, label, accessProfile) {
|
|
|
54316
55442
|
name: entry.name,
|
|
54317
55443
|
platform: entry.platform ?? "Unknown platform",
|
|
54318
55444
|
lastSeen: formatRelativeTime(entry.lastSeenAt),
|
|
54319
|
-
status: deviceStatus(entry)
|
|
55445
|
+
status: deviceStatus(entry),
|
|
55446
|
+
...entry.id === device.deviceId ? { current: true } : {}
|
|
54320
55447
|
}))
|
|
54321
55448
|
};
|
|
54322
55449
|
},
|
|
@@ -54339,9 +55466,9 @@ async function runWorkspaceSession(path12, label, accessProfile) {
|
|
|
54339
55466
|
await lease.release();
|
|
54340
55467
|
}
|
|
54341
55468
|
}
|
|
54342
|
-
async function runWorkspace(path12, label, accessProfile) {
|
|
55469
|
+
async function runWorkspace(path12, label, accessProfile, initialNotice) {
|
|
54343
55470
|
await withWorkspaceLease(
|
|
54344
|
-
async () => await runWorkspaceSession(path12, label, accessProfile)
|
|
55471
|
+
async () => await runWorkspaceSession(path12, label, accessProfile, initialNotice)
|
|
54345
55472
|
);
|
|
54346
55473
|
}
|
|
54347
55474
|
async function refreshUpdateInfo(timeoutMs) {
|
|
@@ -54386,7 +55513,7 @@ async function runUpdateCommand(invocation) {
|
|
|
54386
55513
|
async function updateBeforeWorkspace() {
|
|
54387
55514
|
const state = await loadUpdateState(VERSION);
|
|
54388
55515
|
if (state.policy === "off" || !isUpdateCheckDue(state.lastCheckedAt)) {
|
|
54389
|
-
return false;
|
|
55516
|
+
return { exit: false };
|
|
54390
55517
|
}
|
|
54391
55518
|
let info;
|
|
54392
55519
|
try {
|
|
@@ -54398,18 +55525,18 @@ async function updateBeforeWorkspace() {
|
|
|
54398
55525
|
`Glossa could not check for an automatic update: ${message} Continuing with ${VERSION}.`
|
|
54399
55526
|
);
|
|
54400
55527
|
}
|
|
54401
|
-
return false;
|
|
55528
|
+
return { exit: false };
|
|
54402
55529
|
}
|
|
54403
55530
|
if (!info.updateAvailable) {
|
|
54404
55531
|
await recordUpdateCheck(VERSION);
|
|
54405
|
-
return false;
|
|
55532
|
+
return { exit: false };
|
|
54406
55533
|
}
|
|
54407
55534
|
if (state.policy === "notify") {
|
|
54408
55535
|
await recordUpdateCheck(VERSION);
|
|
54409
|
-
|
|
54410
|
-
|
|
54411
|
-
|
|
54412
|
-
|
|
55536
|
+
return {
|
|
55537
|
+
exit: false,
|
|
55538
|
+
notice: `Glossa ${info.availableVersion} is available. Run glossa update after disconnecting.`
|
|
55539
|
+
};
|
|
54413
55540
|
}
|
|
54414
55541
|
try {
|
|
54415
55542
|
console.error(`Updating Glossa ${VERSION} to ${info.availableVersion}...`);
|
|
@@ -54417,13 +55544,13 @@ async function updateBeforeWorkspace() {
|
|
|
54417
55544
|
async () => await installUpdate(info, DISTRIBUTION)
|
|
54418
55545
|
);
|
|
54419
55546
|
console.error(`Updated Glossa to ${info.availableVersion}. Run glossa again.`);
|
|
54420
|
-
return true;
|
|
55547
|
+
return { exit: true };
|
|
54421
55548
|
} catch (error46) {
|
|
54422
55549
|
const message = error46 instanceof Error ? error46.message : String(error46);
|
|
54423
55550
|
console.error(
|
|
54424
55551
|
`Glossa could not update automatically: ${message} Continuing with ${VERSION}.`
|
|
54425
55552
|
);
|
|
54426
|
-
return false;
|
|
55553
|
+
return { exit: false };
|
|
54427
55554
|
}
|
|
54428
55555
|
}
|
|
54429
55556
|
async function main() {
|
|
@@ -54434,11 +55561,13 @@ async function main() {
|
|
|
54434
55561
|
} else if (invocation.command === "version") {
|
|
54435
55562
|
console.log(VERSION);
|
|
54436
55563
|
} else if (invocation.command === "workspace") {
|
|
54437
|
-
|
|
55564
|
+
const update = await updateBeforeWorkspace();
|
|
55565
|
+
if (update.exit) return;
|
|
54438
55566
|
await runWorkspace(
|
|
54439
55567
|
invocation.path,
|
|
54440
55568
|
invocation.label,
|
|
54441
|
-
invocation.accessProfile
|
|
55569
|
+
invocation.accessProfile,
|
|
55570
|
+
update.notice
|
|
54442
55571
|
);
|
|
54443
55572
|
} else if (invocation.command === "unpair") {
|
|
54444
55573
|
await unpairComputer();
|