@platless/axom-cli 0.6.36 → 0.6.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/axom-patch/cli/README.md +31 -2
- package/dist/axom-patch/cli/account-limits/generate.py +2 -2
- package/dist/axom-patch/cli/claude-replay-lifecycle.json +16 -0
- package/dist/axom-patch/cli/codex-terminal-output.json +2 -2
- package/dist/axom-patch/cli/probes/claude-replay-lifecycle.mjs +31 -0
- package/dist/axom-patch/cli/probes/codex-terminal-output.mjs +1 -1
- package/dist/axom-patch/cli/probes/zcode-env-account.mjs +81 -0
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +7 -0
- package/dist/axom-patch/cli/qoder/dist/axom-acp-compat.mjs +137 -41
- package/dist/axom-patch/cli/qoder/releases/1.1.75.json +5 -88
- package/dist/axom-patch/cli/qoder-native-acp.json +23 -23
- package/dist/axom-patch/cli/runtime.json +3 -1
- package/dist/axom-patch/cli/zcode/env-account.mjs +13 -0
- package/dist/axom-patch/cli/zcode/generate-env-account.py +52 -0
- package/dist/axom-patch/cli/zcode-account-limits.json +7 -7
- package/dist/axom-patch/cli/zcode-env-account.json +58 -0
- package/dist/axom-patch/cli/zcode-models.json +9 -9
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +10 -10
- package/dist/cli.js +9 -11
- package/dist/commands/auth.js +4 -1
- package/dist/commands/update.js +68 -7
- package/dist/commands/workstation.js +94 -223
- package/dist/commands/workstationRegistrations.js +116 -0
- package/dist/credentialBroker.js +13 -2
- package/dist/credentials.js +16 -0
- package/dist/install/claude/commands.js +2 -2
- package/dist/keepers/terminal/keeper.mjs +1089 -673
- package/dist/keepers/terminal/manifest.json +4 -4
- package/dist/native/darwin-x64/axom-quic +0 -0
- package/dist/workstation/acp/acpAgents.js +11 -4
- package/dist/workstation/acp/outbox.js +12 -5
- package/dist/workstation/acp/permission.js +2 -2
- package/dist/workstation/acp/processor/checkpoint.js +4 -3
- package/dist/workstation/acp/processor/control.js +2 -2
- package/dist/workstation/acp/processor/jsonrpc.js +8 -0
- package/dist/workstation/acp/processor/session.js +3 -2
- package/dist/workstation/acp/processor/state.js +1 -0
- package/dist/workstation/acp/processor/transport/local.js +19 -3
- package/dist/workstation/acp/processor/updates.js +25 -0
- package/dist/workstation/acp/processorSession.js +12 -1
- package/dist/workstation/acp/registry/catalog.js +6 -6
- package/dist/workstation/acp/test/keeperWorld.js +4 -3
- package/dist/workstation/agentSessions.js +76 -23
- package/dist/workstation/channels/agent.js +9 -1
- package/dist/workstation/channels/computer.js +27 -4
- package/dist/workstation/channels/management.js +36 -5
- package/dist/workstation/config.js +18 -6
- package/dist/workstation/control/bindingStore.js +4 -0
- package/dist/workstation/control/commands.js +1 -0
- package/dist/workstation/control/daemonIdentity.js +90 -0
- package/dist/workstation/control/deviceCommands.js +191 -0
- package/dist/workstation/control/deviceProtocol.js +68 -0
- package/dist/workstation/control/locks.js +51 -4
- package/dist/workstation/control/rootFormat.js +16 -0
- package/dist/workstation/control/runtimeClient.js +60 -5
- package/dist/workstation/control/runtimeHost.js +96 -9
- package/dist/workstation/control/serverIdentity.js +2 -2
- package/dist/workstation/control/updateTransition.js +91 -0
- package/dist/workstation/daemon.js +262 -360
- package/dist/workstation/daemonctl.js +150 -12
- package/dist/workstation/desktopControl/automationDevice.js +219 -0
- package/dist/workstation/desktopControl/automationJson.js +74 -0
- package/dist/workstation/desktopControl/automationLocalState.js +23 -0
- package/dist/workstation/desktopControl/automationPreparation.js +1 -0
- package/dist/workstation/desktopControl/automationProtocol.js +253 -0
- package/dist/workstation/desktopControl/automationSchema.generated.js +1 -0
- package/dist/workstation/desktopControl/automationSession.js +81 -0
- package/dist/workstation/desktopControl/automationTransport.js +138 -0
- package/dist/workstation/desktopControl/capabilities.js +2 -1
- package/dist/workstation/desktopControl/deviceAdmission.js +229 -0
- package/dist/workstation/desktopControl/deviceOwnership.js +130 -0
- package/dist/workstation/desktopControl/deviceSockets.js +2 -2
- package/dist/workstation/desktopControl/helperProcess.js +250 -1
- package/dist/workstation/desktopControl/hostGrant.js +65 -0
- package/dist/workstation/desktopControl/lobby.js +4 -2
- package/dist/workstation/desktopControl/macProvider.js +41 -40
- package/dist/workstation/desktopControl/nativeDeviceAdmission.js +207 -0
- package/dist/workstation/desktopControl/nativeProvider.js +31 -5
- package/dist/workstation/desktopControl/ownershipProtocol.js +31 -0
- package/dist/workstation/desktopControl/protocol.js +15 -6
- package/dist/workstation/desktopControl/supervisor.js +110 -17
- package/dist/workstation/desktopControl/wallpaper.js +26 -6
- package/dist/workstation/exec/policy.js +5 -0
- package/dist/workstation/files/client.js +10 -1
- package/dist/workstation/files/host.js +9 -2
- package/dist/workstation/journal.js +5 -2
- package/dist/workstation/keepers/acp/client.js +38 -2
- package/dist/workstation/keepers/kit/buildVersion.js +35 -11
- package/dist/workstation/keepers/kit/client.js +2 -2
- package/dist/workstation/keepers/kit/launcher.js +80 -4
- package/dist/workstation/keepers/legacy.js +16 -2
- package/dist/workstation/keepers/policy.js +5 -34
- package/dist/workstation/keepers/terminal/client.js +115 -23
- package/dist/workstation/keepers/terminal/exec.js +6 -3
- package/dist/workstation/keepers/terminal/frames.js +73 -0
- package/dist/workstation/keepers/terminal/generations.js +5 -8
- package/dist/workstation/keepers/terminal/gridProtocol.js +16 -0
- package/dist/workstation/keepers/terminal/input.js +146 -0
- package/dist/workstation/keepers/terminal/keeper.js +22 -8
- package/dist/workstation/keepers/terminal/main.js +1 -1
- package/dist/workstation/keepers/terminal/metadata.js +138 -0
- package/dist/workstation/keepers/terminal/protocol.js +4 -28
- package/dist/workstation/keepers/terminal/pty.js +1 -330
- package/dist/workstation/keepers/terminal/screen.js +246 -0
- package/dist/workstation/keepers/terminal/sessions.js +526 -0
- package/dist/workstation/oauth/deviceAuthorization.js +31 -17
- package/dist/workstation/protocol/management.js +23 -4
- package/dist/workstation/rd/artifact.js +4 -3
- package/dist/workstation/rd/control.js +3 -5
- package/dist/workstation/rd/host.js +213 -0
- package/dist/workstation/rd/migrationReadiness.js +46 -0
- package/dist/workstation/rd/provider.js +44 -10
- package/dist/workstation/rd/state.js +14 -2
- package/dist/workstation/rd/update.js +5 -8
- package/dist/workstation/rd/upkeep.js +44 -2
- package/dist/workstation/registrations/enrollment.js +250 -0
- package/dist/workstation/registrations/enrollmentPending.js +361 -0
- package/dist/workstation/registrations/migration.js +356 -0
- package/dist/workstation/registrations/model.js +34 -0
- package/dist/workstation/registrations/removal.js +222 -0
- package/dist/workstation/registrations/store.js +737 -0
- package/dist/workstation/runtime/desktopBinding.js +20 -0
- package/dist/workstation/runtime/deviceDesktop.js +193 -0
- package/dist/workstation/runtime/deviceRuntime.js +568 -0
- package/dist/workstation/runtime/deviceServices.js +117 -0
- package/dist/workstation/runtime/events.js +20 -0
- package/dist/workstation/runtime/ownership.js +100 -0
- package/dist/workstation/runtime/registrationRuntime.js +575 -0
- package/dist/workstation/runtime/remoteDesktopAdapter.js +186 -0
- package/dist/workstation/runtime/removalActivity.js +184 -0
- package/dist/workstation/service/installer.js +93 -1
- package/dist/workstation/service/launchd.js +1 -0
- package/dist/workstation/service/systemd.js +1 -0
- package/dist/workstation/systemMetrics.js +3 -0
- package/dist/workstation/tools/client.js +8 -27
- package/dist/workstation/tools/info.js +6 -13
- package/dist/workstation/tools/terminalRouter.js +17 -172
- package/dist/workstation/tools/validation.js +55 -1
- package/dist/workstation/update/archiveEvidence.js +206 -0
- package/dist/workstation/update/coordinator.js +34 -13
- package/dist/workstation/update/deviceCompatibility.js +119 -0
- package/dist/workstation/update/deviceCoordinator.js +369 -0
- package/dist/workstation/update/deviceHealth.js +104 -0
- package/dist/workstation/update/deviceHealthProtocol.js +26 -0
- package/dist/workstation/update/deviceRecoveryLifecycle.js +46 -0
- package/dist/workstation/update/deviceRollback.js +78 -0
- package/dist/workstation/update/globalInstall.js +80 -10
- package/dist/workstation/update/legacyBridge.js +414 -0
- package/dist/workstation/update/legacyOwner.js +39 -0
- package/dist/workstation/update/npmInstaller.js +2 -2
- package/dist/workstation/update/privateDurability.js +61 -0
- package/dist/workstation/update/recoveryPlan.js +124 -0
- package/dist/workstation/update/runUpdate.js +7 -1
- package/dist/workstation/update/taskRegistry.js +161 -3
- package/dist/workstation/update/watchdog.js +27427 -14410
- package/dist/workstation/update/watchdogProcess.js +72 -0
- package/package.json +7 -3
- package/dist/native/darwin-arm64/axom-quic +0 -0
|
@@ -5072,375 +5072,10 @@ ${i3.join("\n")}
|
|
|
5072
5072
|
}
|
|
5073
5073
|
});
|
|
5074
5074
|
|
|
5075
|
-
// node_modules/@xterm/addon-serialize/lib/addon-serialize.js
|
|
5076
|
-
var require_addon_serialize = __commonJS({
|
|
5077
|
-
"node_modules/@xterm/addon-serialize/lib/addon-serialize.js"(exports, module) {
|
|
5078
|
-
!(function(t, e) {
|
|
5079
|
-
"object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.SerializeAddon = e() : t.SerializeAddon = e();
|
|
5080
|
-
})(globalThis, (() => (() => {
|
|
5081
|
-
"use strict";
|
|
5082
|
-
var t = { 992: (t2, e2, s2) => {
|
|
5083
|
-
Object.defineProperty(e2, "__esModule", { value: true }), e2.DEFAULT_ANSI_COLORS = void 0;
|
|
5084
|
-
const r2 = s2(993);
|
|
5085
|
-
e2.DEFAULT_ANSI_COLORS = Object.freeze((() => {
|
|
5086
|
-
const t3 = [r2.css.toColor("#2e3436"), r2.css.toColor("#cc0000"), r2.css.toColor("#4e9a06"), r2.css.toColor("#c4a000"), r2.css.toColor("#3465a4"), r2.css.toColor("#75507b"), r2.css.toColor("#06989a"), r2.css.toColor("#d3d7cf"), r2.css.toColor("#555753"), r2.css.toColor("#ef2929"), r2.css.toColor("#8ae234"), r2.css.toColor("#fce94f"), r2.css.toColor("#729fcf"), r2.css.toColor("#ad7fa8"), r2.css.toColor("#34e2e2"), r2.css.toColor("#eeeeec")], e3 = [0, 95, 135, 175, 215, 255];
|
|
5087
|
-
for (let s3 = 0; s3 < 216; s3++) {
|
|
5088
|
-
const i = e3[s3 / 36 % 6 | 0], o = e3[s3 / 6 % 6 | 0], n = e3[s3 % 6];
|
|
5089
|
-
t3.push({ css: r2.channels.toCss(i, o, n), rgba: r2.channels.toRgba(i, o, n) });
|
|
5090
|
-
}
|
|
5091
|
-
for (let e4 = 0; e4 < 24; e4++) {
|
|
5092
|
-
const s3 = 8 + 10 * e4;
|
|
5093
|
-
t3.push({ css: r2.channels.toCss(s3, s3, s3), rgba: r2.channels.toRgba(s3, s3, s3) });
|
|
5094
|
-
}
|
|
5095
|
-
return t3;
|
|
5096
|
-
})());
|
|
5097
|
-
}, 993: (t2, e2) => {
|
|
5098
|
-
Object.defineProperty(e2, "__esModule", { value: true }), e2.rgba = e2.rgb = e2.css = e2.color = e2.channels = e2.NULL_COLOR = void 0, e2.toPaddedHex = c, e2.contrastRatio = _;
|
|
5099
|
-
let s2 = 0, r2 = 0, i = 0, o = 0;
|
|
5100
|
-
var n, l, a, u, h;
|
|
5101
|
-
function c(t3) {
|
|
5102
|
-
const e3 = t3.toString(16);
|
|
5103
|
-
return e3.length < 2 ? "0" + e3 : e3;
|
|
5104
|
-
}
|
|
5105
|
-
function _(t3, e3) {
|
|
5106
|
-
return t3 < e3 ? (e3 + 0.05) / (t3 + 0.05) : (t3 + 0.05) / (e3 + 0.05);
|
|
5107
|
-
}
|
|
5108
|
-
e2.NULL_COLOR = { css: "#00000000", rgba: 0 }, (function(t3) {
|
|
5109
|
-
t3.toCss = function(t4, e3, s3, r3) {
|
|
5110
|
-
return void 0 !== r3 ? `#${c(t4)}${c(e3)}${c(s3)}${c(r3)}` : `#${c(t4)}${c(e3)}${c(s3)}`;
|
|
5111
|
-
}, t3.toRgba = function(t4, e3, s3, r3 = 255) {
|
|
5112
|
-
return (t4 << 24 | e3 << 16 | s3 << 8 | r3) >>> 0;
|
|
5113
|
-
}, t3.toColor = function(e3, s3, r3, i2) {
|
|
5114
|
-
return { css: t3.toCss(e3, s3, r3, i2), rgba: t3.toRgba(e3, s3, r3, i2) };
|
|
5115
|
-
};
|
|
5116
|
-
})(n || (e2.channels = n = {})), (function(t3) {
|
|
5117
|
-
function e3(t4, e4) {
|
|
5118
|
-
return o = Math.round(255 * e4), [s2, r2, i] = h.toChannels(t4.rgba), { css: n.toCss(s2, r2, i, o), rgba: n.toRgba(s2, r2, i, o) };
|
|
5119
|
-
}
|
|
5120
|
-
t3.blend = function(t4, e4) {
|
|
5121
|
-
if (o = (255 & e4.rgba) / 255, 1 === o) return { css: e4.css, rgba: e4.rgba };
|
|
5122
|
-
const l2 = e4.rgba >> 24 & 255, a2 = e4.rgba >> 16 & 255, u2 = e4.rgba >> 8 & 255, h2 = t4.rgba >> 24 & 255, c2 = t4.rgba >> 16 & 255, _2 = t4.rgba >> 8 & 255;
|
|
5123
|
-
return s2 = h2 + Math.round((l2 - h2) * o), r2 = c2 + Math.round((a2 - c2) * o), i = _2 + Math.round((u2 - _2) * o), { css: n.toCss(s2, r2, i), rgba: n.toRgba(s2, r2, i) };
|
|
5124
|
-
}, t3.isOpaque = function(t4) {
|
|
5125
|
-
return !(255 & ~t4.rgba);
|
|
5126
|
-
}, t3.ensureContrastRatio = function(t4, e4, s3) {
|
|
5127
|
-
const r3 = h.ensureContrastRatio(t4.rgba, e4.rgba, s3);
|
|
5128
|
-
if (r3) return n.toColor(r3 >> 24 & 255, r3 >> 16 & 255, r3 >> 8 & 255);
|
|
5129
|
-
}, t3.opaque = function(t4) {
|
|
5130
|
-
const e4 = (255 | t4.rgba) >>> 0;
|
|
5131
|
-
return [s2, r2, i] = h.toChannels(e4), { css: n.toCss(s2, r2, i), rgba: e4 };
|
|
5132
|
-
}, t3.opacity = e3, t3.multiplyOpacity = function(t4, s3) {
|
|
5133
|
-
return o = 255 & t4.rgba, e3(t4, o * s3 / 255);
|
|
5134
|
-
}, t3.toColorRGB = function(t4) {
|
|
5135
|
-
return [t4.rgba >> 24 & 255, t4.rgba >> 16 & 255, t4.rgba >> 8 & 255];
|
|
5136
|
-
};
|
|
5137
|
-
})(l || (e2.color = l = {})), (function(t3) {
|
|
5138
|
-
let e3, l2;
|
|
5139
|
-
try {
|
|
5140
|
-
const t4 = document.createElement("canvas");
|
|
5141
|
-
t4.width = 1, t4.height = 1;
|
|
5142
|
-
const s3 = t4.getContext("2d", { willReadFrequently: true });
|
|
5143
|
-
s3 && (e3 = s3, e3.globalCompositeOperation = "copy", l2 = e3.createLinearGradient(0, 0, 1, 1));
|
|
5144
|
-
} catch {
|
|
5145
|
-
}
|
|
5146
|
-
t3.toColor = function(t4) {
|
|
5147
|
-
if (t4.match(/#[\da-f]{3,8}/i)) switch (t4.length) {
|
|
5148
|
-
case 4:
|
|
5149
|
-
return s2 = parseInt(t4.slice(1, 2).repeat(2), 16), r2 = parseInt(t4.slice(2, 3).repeat(2), 16), i = parseInt(t4.slice(3, 4).repeat(2), 16), n.toColor(s2, r2, i);
|
|
5150
|
-
case 5:
|
|
5151
|
-
return s2 = parseInt(t4.slice(1, 2).repeat(2), 16), r2 = parseInt(t4.slice(2, 3).repeat(2), 16), i = parseInt(t4.slice(3, 4).repeat(2), 16), o = parseInt(t4.slice(4, 5).repeat(2), 16), n.toColor(s2, r2, i, o);
|
|
5152
|
-
case 7:
|
|
5153
|
-
return { css: t4, rgba: (parseInt(t4.slice(1), 16) << 8 | 255) >>> 0 };
|
|
5154
|
-
case 9:
|
|
5155
|
-
return { css: t4, rgba: parseInt(t4.slice(1), 16) >>> 0 };
|
|
5156
|
-
}
|
|
5157
|
-
const a2 = t4.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);
|
|
5158
|
-
if (a2) return s2 = parseInt(a2[1]), r2 = parseInt(a2[2]), i = parseInt(a2[3]), o = Math.round(255 * (void 0 === a2[5] ? 1 : parseFloat(a2[5]))), n.toColor(s2, r2, i, o);
|
|
5159
|
-
if (!e3 || !l2) throw new Error("css.toColor: Unsupported css format");
|
|
5160
|
-
if (e3.fillStyle = l2, e3.fillStyle = t4, "string" != typeof e3.fillStyle) throw new Error("css.toColor: Unsupported css format");
|
|
5161
|
-
if (e3.fillRect(0, 0, 1, 1), [s2, r2, i, o] = e3.getImageData(0, 0, 1, 1).data, 255 !== o) throw new Error("css.toColor: Unsupported css format");
|
|
5162
|
-
return { rgba: n.toRgba(s2, r2, i, o), css: t4 };
|
|
5163
|
-
};
|
|
5164
|
-
})(a || (e2.css = a = {})), (function(t3) {
|
|
5165
|
-
function e3(t4, e4, s3) {
|
|
5166
|
-
const r3 = t4 / 255, i2 = e4 / 255, o2 = s3 / 255;
|
|
5167
|
-
return 0.2126 * (r3 <= 0.03928 ? r3 / 12.92 : Math.pow((r3 + 0.055) / 1.055, 2.4)) + 0.7152 * (i2 <= 0.03928 ? i2 / 12.92 : Math.pow((i2 + 0.055) / 1.055, 2.4)) + 0.0722 * (o2 <= 0.03928 ? o2 / 12.92 : Math.pow((o2 + 0.055) / 1.055, 2.4));
|
|
5168
|
-
}
|
|
5169
|
-
t3.relativeLuminance = function(t4) {
|
|
5170
|
-
return e3(t4 >> 16 & 255, t4 >> 8 & 255, 255 & t4);
|
|
5171
|
-
}, t3.relativeLuminance2 = e3;
|
|
5172
|
-
})(u || (e2.rgb = u = {})), (function(t3) {
|
|
5173
|
-
function e3(t4, e4, s3) {
|
|
5174
|
-
const r3 = t4 >> 24 & 255, i2 = t4 >> 16 & 255, o2 = t4 >> 8 & 255;
|
|
5175
|
-
let n2 = e4 >> 24 & 255, l3 = e4 >> 16 & 255, a2 = e4 >> 8 & 255, h2 = _(u.relativeLuminance2(n2, l3, a2), u.relativeLuminance2(r3, i2, o2));
|
|
5176
|
-
for (; h2 < s3 && (n2 > 0 || l3 > 0 || a2 > 0); ) n2 -= Math.max(0, Math.ceil(0.1 * n2)), l3 -= Math.max(0, Math.ceil(0.1 * l3)), a2 -= Math.max(0, Math.ceil(0.1 * a2)), h2 = _(u.relativeLuminance2(n2, l3, a2), u.relativeLuminance2(r3, i2, o2));
|
|
5177
|
-
return (n2 << 24 | l3 << 16 | a2 << 8 | 255) >>> 0;
|
|
5178
|
-
}
|
|
5179
|
-
function l2(t4, e4, s3) {
|
|
5180
|
-
const r3 = t4 >> 24 & 255, i2 = t4 >> 16 & 255, o2 = t4 >> 8 & 255;
|
|
5181
|
-
let n2 = e4 >> 24 & 255, l3 = e4 >> 16 & 255, a2 = e4 >> 8 & 255, h2 = _(u.relativeLuminance2(n2, l3, a2), u.relativeLuminance2(r3, i2, o2));
|
|
5182
|
-
for (; h2 < s3 && (n2 < 255 || l3 < 255 || a2 < 255); ) n2 = Math.min(255, n2 + Math.ceil(0.1 * (255 - n2))), l3 = Math.min(255, l3 + Math.ceil(0.1 * (255 - l3))), a2 = Math.min(255, a2 + Math.ceil(0.1 * (255 - a2))), h2 = _(u.relativeLuminance2(n2, l3, a2), u.relativeLuminance2(r3, i2, o2));
|
|
5183
|
-
return (n2 << 24 | l3 << 16 | a2 << 8 | 255) >>> 0;
|
|
5184
|
-
}
|
|
5185
|
-
t3.blend = function(t4, e4) {
|
|
5186
|
-
if (o = (255 & e4) / 255, 1 === o) return e4;
|
|
5187
|
-
const l3 = e4 >> 24 & 255, a2 = e4 >> 16 & 255, u2 = e4 >> 8 & 255, h2 = t4 >> 24 & 255, c2 = t4 >> 16 & 255, _2 = t4 >> 8 & 255;
|
|
5188
|
-
return s2 = h2 + Math.round((l3 - h2) * o), r2 = c2 + Math.round((a2 - c2) * o), i = _2 + Math.round((u2 - _2) * o), n.toRgba(s2, r2, i);
|
|
5189
|
-
}, t3.ensureContrastRatio = function(t4, s3, r3) {
|
|
5190
|
-
const i2 = u.relativeLuminance(t4 >> 8), o2 = u.relativeLuminance(s3 >> 8);
|
|
5191
|
-
if (_(i2, o2) < r3) {
|
|
5192
|
-
if (o2 < i2) {
|
|
5193
|
-
const o3 = e3(t4, s3, r3), n3 = _(i2, u.relativeLuminance(o3 >> 8));
|
|
5194
|
-
if (n3 < r3) {
|
|
5195
|
-
const e4 = l2(t4, s3, r3);
|
|
5196
|
-
return n3 > _(i2, u.relativeLuminance(e4 >> 8)) ? o3 : e4;
|
|
5197
|
-
}
|
|
5198
|
-
return o3;
|
|
5199
|
-
}
|
|
5200
|
-
const n2 = l2(t4, s3, r3), a2 = _(i2, u.relativeLuminance(n2 >> 8));
|
|
5201
|
-
if (a2 < r3) {
|
|
5202
|
-
const o3 = e3(t4, s3, r3);
|
|
5203
|
-
return a2 > _(i2, u.relativeLuminance(o3 >> 8)) ? n2 : o3;
|
|
5204
|
-
}
|
|
5205
|
-
return n2;
|
|
5206
|
-
}
|
|
5207
|
-
}, t3.reduceLuminance = e3, t3.increaseLuminance = l2, t3.toChannels = function(t4) {
|
|
5208
|
-
return [t4 >> 24 & 255, t4 >> 16 & 255, t4 >> 8 & 255, 255 & t4];
|
|
5209
|
-
};
|
|
5210
|
-
})(h || (e2.rgba = h = {}));
|
|
5211
|
-
} }, e = {};
|
|
5212
|
-
function s(r2) {
|
|
5213
|
-
var i = e[r2];
|
|
5214
|
-
if (void 0 !== i) return i.exports;
|
|
5215
|
-
var o = e[r2] = { exports: {} };
|
|
5216
|
-
return t[r2](o, o.exports, s), o.exports;
|
|
5217
|
-
}
|
|
5218
|
-
var r = {};
|
|
5219
|
-
return (() => {
|
|
5220
|
-
var t2 = r;
|
|
5221
|
-
Object.defineProperty(t2, "__esModule", { value: true }), t2.HTMLSerializeHandler = t2.SerializeAddon = void 0;
|
|
5222
|
-
const e2 = s(992);
|
|
5223
|
-
function i(t3, e3, s2) {
|
|
5224
|
-
return Math.max(e3, Math.min(t3, s2));
|
|
5225
|
-
}
|
|
5226
|
-
class o {
|
|
5227
|
-
constructor(t3) {
|
|
5228
|
-
this._buffer = t3;
|
|
5229
|
-
}
|
|
5230
|
-
serialize(t3, e3) {
|
|
5231
|
-
const s2 = this._buffer.getNullCell(), r2 = this._buffer.getNullCell();
|
|
5232
|
-
let i2 = s2;
|
|
5233
|
-
const o2 = t3.start.y, n2 = t3.end.y, l2 = t3.start.x, a2 = t3.end.x;
|
|
5234
|
-
this._beforeSerialize(n2 - o2, o2, n2);
|
|
5235
|
-
for (let e4 = o2; e4 <= n2; e4++) {
|
|
5236
|
-
const o3 = this._buffer.getLine(e4);
|
|
5237
|
-
if (o3) {
|
|
5238
|
-
const n3 = e4 === t3.start.y ? l2 : 0, u2 = e4 === t3.end.y ? a2 : o3.length;
|
|
5239
|
-
for (let t4 = n3; t4 < u2; t4++) {
|
|
5240
|
-
const n4 = o3.getCell(t4, i2 === s2 ? r2 : s2);
|
|
5241
|
-
n4 ? (this._nextCell(n4, i2, e4, t4), i2 = n4) : console.warn(`Can't get cell at row=${e4}, col=${t4}`);
|
|
5242
|
-
}
|
|
5243
|
-
}
|
|
5244
|
-
this._rowEnd(e4, e4 === n2);
|
|
5245
|
-
}
|
|
5246
|
-
return this._afterSerialize(), this._serializeString(e3);
|
|
5247
|
-
}
|
|
5248
|
-
_nextCell(t3, e3, s2, r2) {
|
|
5249
|
-
}
|
|
5250
|
-
_rowEnd(t3, e3) {
|
|
5251
|
-
}
|
|
5252
|
-
_beforeSerialize(t3, e3, s2) {
|
|
5253
|
-
}
|
|
5254
|
-
_afterSerialize() {
|
|
5255
|
-
}
|
|
5256
|
-
_serializeString(t3) {
|
|
5257
|
-
return "";
|
|
5258
|
-
}
|
|
5259
|
-
}
|
|
5260
|
-
function n(t3, e3) {
|
|
5261
|
-
return t3.getFgColorMode() === e3.getFgColorMode() && t3.getFgColor() === e3.getFgColor();
|
|
5262
|
-
}
|
|
5263
|
-
function l(t3, e3) {
|
|
5264
|
-
return t3.getBgColorMode() === e3.getBgColorMode() && t3.getBgColor() === e3.getBgColor();
|
|
5265
|
-
}
|
|
5266
|
-
function a(t3, e3) {
|
|
5267
|
-
return t3.isInverse() === e3.isInverse() && t3.isBold() === e3.isBold() && t3.isUnderline() === e3.isUnderline() && t3.isOverline() === e3.isOverline() && t3.isBlink() === e3.isBlink() && t3.isInvisible() === e3.isInvisible() && t3.isItalic() === e3.isItalic() && t3.isDim() === e3.isDim() && t3.isStrikethrough() === e3.isStrikethrough();
|
|
5268
|
-
}
|
|
5269
|
-
class u extends o {
|
|
5270
|
-
constructor(t3, e3) {
|
|
5271
|
-
super(t3), this._terminal = e3, this._rowIndex = 0, this._allRows = new Array(), this._allRowSeparators = new Array(), this._currentRow = "", this._nullCellCount = 0, this._cursorStyle = this._buffer.getNullCell(), this._cursorStyleRow = 0, this._cursorStyleCol = 0, this._backgroundCell = this._buffer.getNullCell(), this._firstRow = 0, this._lastCursorRow = 0, this._lastCursorCol = 0, this._lastContentCursorRow = 0, this._lastContentCursorCol = 0, this._thisRowLastChar = this._buffer.getNullCell(), this._thisRowLastSecondChar = this._buffer.getNullCell(), this._nextRowFirstChar = this._buffer.getNullCell();
|
|
5272
|
-
}
|
|
5273
|
-
_beforeSerialize(t3, e3, s2) {
|
|
5274
|
-
this._allRows = new Array(t3), this._lastContentCursorRow = e3, this._lastCursorRow = e3, this._firstRow = e3;
|
|
5275
|
-
}
|
|
5276
|
-
_rowEnd(t3, e3) {
|
|
5277
|
-
this._nullCellCount > 0 && !l(this._cursorStyle, this._backgroundCell) && (this._currentRow += `\x1B[${this._nullCellCount}X`);
|
|
5278
|
-
let s2 = "";
|
|
5279
|
-
if (!e3) {
|
|
5280
|
-
t3 - this._firstRow >= this._terminal.rows && this._buffer.getLine(this._cursorStyleRow)?.getCell(this._cursorStyleCol, this._backgroundCell);
|
|
5281
|
-
const e4 = this._buffer.getLine(t3), r2 = this._buffer.getLine(t3 + 1);
|
|
5282
|
-
if (r2.isWrapped) {
|
|
5283
|
-
s2 = "";
|
|
5284
|
-
const i2 = e4.getCell(e4.length - 1, this._thisRowLastChar), o2 = e4.getCell(e4.length - 2, this._thisRowLastSecondChar), n2 = r2.getCell(0, this._nextRowFirstChar), a2 = n2.getWidth() > 1;
|
|
5285
|
-
let u2 = false;
|
|
5286
|
-
(n2.getChars() && a2 ? this._nullCellCount <= 1 : this._nullCellCount <= 0) && ((i2.getChars() || 0 === i2.getWidth()) && l(i2, n2) && (u2 = true), a2 && (o2.getChars() || 0 === o2.getWidth()) && l(i2, n2) && l(o2, n2) && (u2 = true)), u2 || (s2 = "-".repeat(this._nullCellCount + 1), s2 += "\x1B[1D\x1B[1X", this._nullCellCount > 0 && (s2 += "\x1B[A", s2 += `\x1B[${e4.length - this._nullCellCount}C`, s2 += `\x1B[${this._nullCellCount}X`, s2 += `\x1B[${e4.length - this._nullCellCount}D`, s2 += "\x1B[B"), this._lastContentCursorRow = t3 + 1, this._lastContentCursorCol = 0, this._lastCursorRow = t3 + 1, this._lastCursorCol = 0);
|
|
5287
|
-
} else s2 = "\r\n", this._lastCursorRow = t3 + 1, this._lastCursorCol = 0;
|
|
5288
|
-
}
|
|
5289
|
-
this._allRows[this._rowIndex] = this._currentRow, this._allRowSeparators[this._rowIndex++] = s2, this._currentRow = "", this._nullCellCount = 0;
|
|
5290
|
-
}
|
|
5291
|
-
_diffStyle(t3, e3) {
|
|
5292
|
-
const s2 = [], r2 = !n(t3, e3), i2 = !l(t3, e3), o2 = !a(t3, e3);
|
|
5293
|
-
if (r2 || i2 || o2) if (t3.isAttributeDefault()) e3.isAttributeDefault() || s2.push(0);
|
|
5294
|
-
else {
|
|
5295
|
-
if (r2) {
|
|
5296
|
-
const e4 = t3.getFgColor();
|
|
5297
|
-
t3.isFgRGB() ? s2.push(38, 2, e4 >>> 16 & 255, e4 >>> 8 & 255, 255 & e4) : t3.isFgPalette() ? e4 >= 16 ? s2.push(38, 5, e4) : s2.push(8 & e4 ? 90 + (7 & e4) : 30 + (7 & e4)) : s2.push(39);
|
|
5298
|
-
}
|
|
5299
|
-
if (i2) {
|
|
5300
|
-
const e4 = t3.getBgColor();
|
|
5301
|
-
t3.isBgRGB() ? s2.push(48, 2, e4 >>> 16 & 255, e4 >>> 8 & 255, 255 & e4) : t3.isBgPalette() ? e4 >= 16 ? s2.push(48, 5, e4) : s2.push(8 & e4 ? 100 + (7 & e4) : 40 + (7 & e4)) : s2.push(49);
|
|
5302
|
-
}
|
|
5303
|
-
o2 && (t3.isInverse() !== e3.isInverse() && s2.push(t3.isInverse() ? 7 : 27), t3.isBold() !== e3.isBold() && s2.push(t3.isBold() ? 1 : 22), t3.isUnderline() !== e3.isUnderline() && s2.push(t3.isUnderline() ? 4 : 24), t3.isOverline() !== e3.isOverline() && s2.push(t3.isOverline() ? 53 : 55), t3.isBlink() !== e3.isBlink() && s2.push(t3.isBlink() ? 5 : 25), t3.isInvisible() !== e3.isInvisible() && s2.push(t3.isInvisible() ? 8 : 28), t3.isItalic() !== e3.isItalic() && s2.push(t3.isItalic() ? 3 : 23), t3.isDim() !== e3.isDim() && s2.push(t3.isDim() ? 2 : 22), t3.isStrikethrough() !== e3.isStrikethrough() && s2.push(t3.isStrikethrough() ? 9 : 29));
|
|
5304
|
-
}
|
|
5305
|
-
return s2;
|
|
5306
|
-
}
|
|
5307
|
-
_nextCell(t3, e3, s2, r2) {
|
|
5308
|
-
if (0 === t3.getWidth()) return;
|
|
5309
|
-
const i2 = "" === t3.getChars(), o2 = this._diffStyle(t3, this._cursorStyle);
|
|
5310
|
-
if (i2 ? !l(this._cursorStyle, t3) : o2.length > 0) {
|
|
5311
|
-
this._nullCellCount > 0 && (l(this._cursorStyle, this._backgroundCell) || (this._currentRow += `\x1B[${this._nullCellCount}X`), this._currentRow += `\x1B[${this._nullCellCount}C`, this._nullCellCount = 0), this._lastContentCursorRow = this._lastCursorRow = s2, this._lastContentCursorCol = this._lastCursorCol = r2, this._currentRow += `\x1B[${o2.join(";")}m`;
|
|
5312
|
-
const t4 = this._buffer.getLine(s2);
|
|
5313
|
-
void 0 !== t4 && (t4.getCell(r2, this._cursorStyle), this._cursorStyleRow = s2, this._cursorStyleCol = r2);
|
|
5314
|
-
}
|
|
5315
|
-
i2 ? this._nullCellCount += t3.getWidth() : (this._nullCellCount > 0 && (l(this._cursorStyle, this._backgroundCell) || (this._currentRow += `\x1B[${this._nullCellCount}X`), this._currentRow += `\x1B[${this._nullCellCount}C`, this._nullCellCount = 0), this._currentRow += t3.getChars(), this._lastContentCursorRow = this._lastCursorRow = s2, this._lastContentCursorCol = this._lastCursorCol = r2 + t3.getWidth());
|
|
5316
|
-
}
|
|
5317
|
-
_serializeString(t3) {
|
|
5318
|
-
let e3 = this._allRows.length;
|
|
5319
|
-
this._buffer.length - this._firstRow <= this._terminal.rows && (e3 = this._lastContentCursorRow + 1 - this._firstRow, this._lastCursorCol = this._lastContentCursorCol, this._lastCursorRow = this._lastContentCursorRow);
|
|
5320
|
-
let s2 = "";
|
|
5321
|
-
for (let t4 = 0; t4 < e3; t4++) s2 += this._allRows[t4], t4 + 1 < e3 && (s2 += this._allRowSeparators[t4]);
|
|
5322
|
-
if (!t3) {
|
|
5323
|
-
const t4 = this._buffer.baseY + this._buffer.cursorY, e4 = this._buffer.cursorX, i3 = (t5) => {
|
|
5324
|
-
t5 > 0 ? s2 += `\x1B[${t5}C` : t5 < 0 && (s2 += `\x1B[${-t5}D`);
|
|
5325
|
-
};
|
|
5326
|
-
(t4 !== this._lastCursorRow || e4 !== this._lastCursorCol) && ((r2 = t4 - this._lastCursorRow) > 0 ? s2 += `\x1B[${r2}B` : r2 < 0 && (s2 += `\x1B[${-r2}A`), i3(e4 - this._lastCursorCol));
|
|
5327
|
-
}
|
|
5328
|
-
var r2;
|
|
5329
|
-
const i2 = this._terminal._core._inputHandler._curAttrData, o2 = this._diffStyle(i2, this._cursorStyle);
|
|
5330
|
-
return o2.length > 0 && (s2 += `\x1B[${o2.join(";")}m`), s2;
|
|
5331
|
-
}
|
|
5332
|
-
}
|
|
5333
|
-
t2.SerializeAddon = class {
|
|
5334
|
-
activate(t3) {
|
|
5335
|
-
this._terminal = t3;
|
|
5336
|
-
}
|
|
5337
|
-
_serializeBufferByScrollback(t3, e3, s2) {
|
|
5338
|
-
const r2 = e3.length, o2 = void 0 === s2 ? r2 : i(s2 + t3.rows, 0, r2);
|
|
5339
|
-
return this._serializeBufferByRange(t3, e3, { start: r2 - o2, end: r2 - 1 }, false);
|
|
5340
|
-
}
|
|
5341
|
-
_serializeBufferByRange(t3, e3, s2, r2) {
|
|
5342
|
-
return new u(e3, t3).serialize({ start: { x: 0, y: "number" == typeof s2.start ? s2.start : s2.start.line }, end: { x: t3.cols, y: "number" == typeof s2.end ? s2.end : s2.end.line } }, r2);
|
|
5343
|
-
}
|
|
5344
|
-
_serializeBufferAsHTML(t3, e3) {
|
|
5345
|
-
const s2 = t3.buffer.active, r2 = new h(s2, t3, e3), o2 = e3.onlySelection ?? false, n2 = e3.range;
|
|
5346
|
-
if (n2) return r2.serialize({ start: { x: n2.startCol, y: (n2.startLine, n2.startLine) }, end: { x: t3.cols, y: (n2.endLine, n2.endLine) } });
|
|
5347
|
-
if (!o2) {
|
|
5348
|
-
const o3 = s2.length, n3 = e3.scrollback, l3 = void 0 === n3 ? o3 : i(n3 + t3.rows, 0, o3);
|
|
5349
|
-
return r2.serialize({ start: { x: 0, y: o3 - l3 }, end: { x: t3.cols, y: o3 - 1 } });
|
|
5350
|
-
}
|
|
5351
|
-
const l2 = this._terminal?.getSelectionPosition();
|
|
5352
|
-
return void 0 !== l2 ? r2.serialize({ start: { x: l2.start.x, y: l2.start.y }, end: { x: l2.end.x, y: l2.end.y } }) : "";
|
|
5353
|
-
}
|
|
5354
|
-
_serializeModes(t3) {
|
|
5355
|
-
let e3 = "";
|
|
5356
|
-
const s2 = t3.modes;
|
|
5357
|
-
if (s2.applicationCursorKeysMode && (e3 += "\x1B[?1h"), s2.applicationKeypadMode && (e3 += "\x1B[?66h"), s2.bracketedPasteMode && (e3 += "\x1B[?2004h"), s2.insertMode && (e3 += "\x1B[4h"), s2.originMode && (e3 += "\x1B[?6h"), s2.reverseWraparoundMode && (e3 += "\x1B[?45h"), s2.sendFocusMode && (e3 += "\x1B[?1004h"), false === s2.wraparoundMode && (e3 += "\x1B[?7l"), "none" !== s2.mouseTrackingMode) switch (s2.mouseTrackingMode) {
|
|
5358
|
-
case "x10":
|
|
5359
|
-
e3 += "\x1B[?9h";
|
|
5360
|
-
break;
|
|
5361
|
-
case "vt200":
|
|
5362
|
-
e3 += "\x1B[?1000h";
|
|
5363
|
-
break;
|
|
5364
|
-
case "drag":
|
|
5365
|
-
e3 += "\x1B[?1002h";
|
|
5366
|
-
break;
|
|
5367
|
-
case "any":
|
|
5368
|
-
e3 += "\x1B[?1003h";
|
|
5369
|
-
}
|
|
5370
|
-
return e3;
|
|
5371
|
-
}
|
|
5372
|
-
serialize(t3) {
|
|
5373
|
-
if (!this._terminal) throw new Error("Cannot use addon until it has been loaded");
|
|
5374
|
-
let e3 = t3?.range ? this._serializeBufferByRange(this._terminal, this._terminal.buffer.normal, t3.range, true) : this._serializeBufferByScrollback(this._terminal, this._terminal.buffer.normal, t3?.scrollback);
|
|
5375
|
-
return t3?.excludeAltBuffer || "alternate" !== this._terminal.buffer.active.type || (e3 += `\x1B[?1049h\x1B[H${this._serializeBufferByScrollback(this._terminal, this._terminal.buffer.alternate, void 0)}`), t3?.excludeModes || (e3 += this._serializeModes(this._terminal)), e3;
|
|
5376
|
-
}
|
|
5377
|
-
serializeAsHTML(t3) {
|
|
5378
|
-
if (!this._terminal) throw new Error("Cannot use addon until it has been loaded");
|
|
5379
|
-
return this._serializeBufferAsHTML(this._terminal, t3 || {});
|
|
5380
|
-
}
|
|
5381
|
-
dispose() {
|
|
5382
|
-
}
|
|
5383
|
-
};
|
|
5384
|
-
class h extends o {
|
|
5385
|
-
constructor(t3, s2, r2) {
|
|
5386
|
-
super(t3), this._terminal = s2, this._options = r2, this._currentRow = "", this._htmlContent = "", s2._core._themeService ? this._ansiColors = s2._core._themeService.colors.ansi : this._ansiColors = e2.DEFAULT_ANSI_COLORS;
|
|
5387
|
-
}
|
|
5388
|
-
_padStart(t3, e3, s2) {
|
|
5389
|
-
return e3 |= 0, s2 = s2 ?? " ", t3.length > e3 ? t3 : ((e3 -= t3.length) > s2.length && (s2 += s2.repeat(e3 / s2.length)), s2.slice(0, e3) + t3);
|
|
5390
|
-
}
|
|
5391
|
-
_beforeSerialize(t3, e3, s2) {
|
|
5392
|
-
this._htmlContent += "<html><body><!--StartFragment--><pre>";
|
|
5393
|
-
let r2 = "#000000", i2 = "#ffffff";
|
|
5394
|
-
this._options.includeGlobalBackground && (r2 = this._terminal.options.theme?.foreground ?? "#ffffff", i2 = this._terminal.options.theme?.background ?? "#000000");
|
|
5395
|
-
const o2 = [];
|
|
5396
|
-
o2.push("color: " + r2 + ";"), o2.push("background-color: " + i2 + ";"), o2.push("font-family: " + this._terminal.options.fontFamily + ";"), o2.push("font-size: " + this._terminal.options.fontSize + "px;"), this._htmlContent += "<div style='" + o2.join(" ") + "'>";
|
|
5397
|
-
}
|
|
5398
|
-
_afterSerialize() {
|
|
5399
|
-
this._htmlContent += "</div>", this._htmlContent += "</pre><!--EndFragment--></body></html>";
|
|
5400
|
-
}
|
|
5401
|
-
_rowEnd(t3, e3) {
|
|
5402
|
-
this._htmlContent += "<div><span>" + this._currentRow + "</span></div>", this._currentRow = "";
|
|
5403
|
-
}
|
|
5404
|
-
_getHexColor(t3, e3) {
|
|
5405
|
-
const s2 = e3 ? t3.getFgColor() : t3.getBgColor();
|
|
5406
|
-
return (e3 ? t3.isFgRGB() : t3.isBgRGB()) ? "#" + [s2 >> 16 & 255, s2 >> 8 & 255, 255 & s2].map(((t4) => this._padStart(t4.toString(16), 2, "0"))).join("") : (e3 ? t3.isFgPalette() : t3.isBgPalette()) ? this._ansiColors[s2].css : void 0;
|
|
5407
|
-
}
|
|
5408
|
-
_diffStyle(t3, e3) {
|
|
5409
|
-
const s2 = [], r2 = !n(t3, e3), i2 = !l(t3, e3), o2 = !a(t3, e3);
|
|
5410
|
-
if (r2 || i2 || o2) {
|
|
5411
|
-
const e4 = this._getHexColor(t3, true);
|
|
5412
|
-
e4 && s2.push("color: " + e4 + ";");
|
|
5413
|
-
const r3 = this._getHexColor(t3, false);
|
|
5414
|
-
return r3 && s2.push("background-color: " + r3 + ";"), t3.isInverse() && s2.push("color: #000000; background-color: #BFBFBF;"), t3.isBold() && s2.push("font-weight: bold;"), t3.isUnderline() && t3.isOverline() ? s2.push("text-decoration: overline underline;") : t3.isUnderline() ? s2.push("text-decoration: underline;") : t3.isOverline() && s2.push("text-decoration: overline;"), t3.isBlink() && s2.push("text-decoration: blink;"), t3.isInvisible() && s2.push("visibility: hidden;"), t3.isItalic() && s2.push("font-style: italic;"), t3.isDim() && s2.push("opacity: 0.5;"), t3.isStrikethrough() && s2.push("text-decoration: line-through;"), s2;
|
|
5415
|
-
}
|
|
5416
|
-
}
|
|
5417
|
-
_nextCell(t3, e3, s2, r2) {
|
|
5418
|
-
if (0 === t3.getWidth()) return;
|
|
5419
|
-
const i2 = "" === t3.getChars(), o2 = this._diffStyle(t3, e3);
|
|
5420
|
-
o2 && (this._currentRow += 0 === o2.length ? "</span><span>" : "</span><span style='" + o2.join(" ") + "'>"), this._currentRow += i2 ? " " : (function(t4) {
|
|
5421
|
-
switch (t4) {
|
|
5422
|
-
case "&":
|
|
5423
|
-
return "&";
|
|
5424
|
-
case "<":
|
|
5425
|
-
return "<";
|
|
5426
|
-
}
|
|
5427
|
-
return t4;
|
|
5428
|
-
})(t3.getChars());
|
|
5429
|
-
}
|
|
5430
|
-
_serializeString() {
|
|
5431
|
-
return this._htmlContent;
|
|
5432
|
-
}
|
|
5433
|
-
}
|
|
5434
|
-
t2.HTMLSerializeHandler = h;
|
|
5435
|
-
})(), r;
|
|
5436
|
-
})()));
|
|
5437
|
-
}
|
|
5438
|
-
});
|
|
5439
|
-
|
|
5440
5075
|
// src/workstation/keepers/terminal/main.ts
|
|
5441
5076
|
import { realpathSync } from "node:fs";
|
|
5442
|
-
import { createRequire as
|
|
5443
|
-
import
|
|
5077
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
5078
|
+
import path6, { sep } from "node:path";
|
|
5444
5079
|
|
|
5445
5080
|
// src/workstation/keepers/kit/bootstrap.ts
|
|
5446
5081
|
import { readFileSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
@@ -5954,19 +5589,19 @@ var Connection = class {
|
|
|
5954
5589
|
this.subscriptions.get(frame.stream)?.grant(frame.n, frame.bytes);
|
|
5955
5590
|
return;
|
|
5956
5591
|
}
|
|
5957
|
-
const reply = (
|
|
5958
|
-
const
|
|
5592
|
+
const reply = (ok2, payload, then) => this.send(ok2 ? { t: "res", id: frame.id, ok: true, result: payload } : { t: "res", id: frame.id, ok: false, error: payload }, then);
|
|
5593
|
+
const fail2 = (code, message, then) => reply(false, wireError(code, message), then);
|
|
5959
5594
|
const { method } = frame;
|
|
5960
5595
|
const params = frame.params ?? {};
|
|
5961
5596
|
if (method === "keeper.hello") {
|
|
5962
5597
|
const token = typeof params.token === "string" ? Buffer.from(params.token) : Buffer.alloc(0);
|
|
5963
5598
|
const expected = Buffer.from(this.server.token);
|
|
5964
5599
|
if (token.length !== expected.length || !timingSafeEqual(token, expected)) {
|
|
5965
|
-
|
|
5600
|
+
fail2(ErrorCode.badToken, "Invalid keeper token", () => this.destroy());
|
|
5966
5601
|
return;
|
|
5967
5602
|
}
|
|
5968
5603
|
if (!isProtocolWindow(params.daemonProtocol)) {
|
|
5969
|
-
|
|
5604
|
+
fail2(ErrorCode.badRequest, "daemonProtocol must be [min, max]");
|
|
5970
5605
|
return;
|
|
5971
5606
|
}
|
|
5972
5607
|
this.authenticated = true;
|
|
@@ -5976,7 +5611,7 @@ var Connection = class {
|
|
|
5976
5611
|
return;
|
|
5977
5612
|
}
|
|
5978
5613
|
if (!this.authenticated && method !== "keeper.ping") {
|
|
5979
|
-
|
|
5614
|
+
fail2(ErrorCode.unauthenticated, "keeper.hello required");
|
|
5980
5615
|
return;
|
|
5981
5616
|
}
|
|
5982
5617
|
const context = {
|
|
@@ -5993,8 +5628,8 @@ var Connection = class {
|
|
|
5993
5628
|
this.startSubscriptions();
|
|
5994
5629
|
} catch (error) {
|
|
5995
5630
|
this.discardStarts();
|
|
5996
|
-
if (error instanceof KeeperMethodError)
|
|
5997
|
-
else
|
|
5631
|
+
if (error instanceof KeeperMethodError) fail2(error.code, error.message);
|
|
5632
|
+
else fail2(ErrorCode.internal, error instanceof Error ? error.message : String(error));
|
|
5998
5633
|
}
|
|
5999
5634
|
})();
|
|
6000
5635
|
}
|
|
@@ -6675,11 +6310,11 @@ var StreamLog = class _StreamLog {
|
|
|
6675
6310
|
* (a retry would duplicate it), so the error is reported through `onError` and `stats().syncErrors`/`lastSyncError`
|
|
6676
6311
|
* instead of being thrown, and the record stays counted as unsynced. Only a failure to write the line itself throws.
|
|
6677
6312
|
*/
|
|
6678
|
-
append(
|
|
6313
|
+
append(input2, options = {}) {
|
|
6679
6314
|
this.assertOpen();
|
|
6680
|
-
if (typeof
|
|
6681
|
-
if ("o" in
|
|
6682
|
-
const { k, ...rest } =
|
|
6315
|
+
if (typeof input2.k !== "string" || input2.k === "") throw new TypeError("A stream record needs a non-empty kind `k`");
|
|
6316
|
+
if ("o" in input2 || "t" in input2) throw new TypeError("`o` and `t` are stamped by the stream log");
|
|
6317
|
+
const { k, ...rest } = input2;
|
|
6683
6318
|
const record = { o: this.nextOffset, t: this.now(), k, ...rest };
|
|
6684
6319
|
const line = Buffer.from(`${JSON.stringify(record)}
|
|
6685
6320
|
`);
|
|
@@ -7148,24 +6783,7 @@ function environment(value) {
|
|
|
7148
6783
|
}
|
|
7149
6784
|
|
|
7150
6785
|
// src/workstation/keepers/terminal/protocol.ts
|
|
7151
|
-
var PTY_CAPABILITY = "pty";
|
|
7152
|
-
var PTY_UNAVAILABLE_ERROR = "Terminal native dependency unavailable; reinstall CLI with optional node-pty support";
|
|
7153
|
-
var PTY_HISTORY_BYTES = 1024 * 1024;
|
|
7154
|
-
var PTY_MAX_POLL_BYTES = 64 * 1024;
|
|
7155
|
-
var PTY_SCROLLBACK = 1e3;
|
|
7156
|
-
var PTY_RESULT_BYTES = 2 * 1024 * 1024;
|
|
7157
|
-
var PTY_SESSION_LIMIT = 8;
|
|
7158
|
-
var PTY_INPUT_BYTES = 64 * 1024;
|
|
7159
|
-
var PTY_LABEL_CHARS = 64;
|
|
7160
|
-
var PtyErrorCode = {
|
|
7161
|
-
unavailable: "pty_unavailable",
|
|
7162
|
-
badRequest: "bad_request",
|
|
7163
|
-
notFound: "pty_not_found",
|
|
7164
|
-
notController: "pty_not_controller",
|
|
7165
|
-
limit: "pty_limit",
|
|
7166
|
-
exited: "pty_exited",
|
|
7167
|
-
snapshotTooLarge: "pty_snapshot_too_large"
|
|
7168
|
-
};
|
|
6786
|
+
var PTY_CAPABILITY = "pty-grid-v1";
|
|
7169
6787
|
var EXEC_CAPABILITY = "exec";
|
|
7170
6788
|
var execStream = (execId) => `exec/${execId}`;
|
|
7171
6789
|
var EXEC_RUNNING_LIMIT = 128;
|
|
@@ -7199,7 +6817,7 @@ var MAX_READ_RECORDS = 1024;
|
|
|
7199
6817
|
var MAX_READ_BYTES = 1536 * 1024;
|
|
7200
6818
|
var MAX_GRACE_MS = 10 * 60 * 1e3;
|
|
7201
6819
|
var EXEC_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
7202
|
-
var START_KEYS = ["execId", "argv", "cwd", "env", "deadlineEpochMs", "killGraceMs", "retainHeadBytes", "maxUncommittedBytes", "onKeeperLoss", "label", "jobId"];
|
|
6820
|
+
var START_KEYS = ["execId", "argv", "cwd", "env", "deadlineEpochMs", "killGraceMs", "retainHeadBytes", "maxUncommittedBytes", "onKeeperLoss", "label", "jobId", "registrationId"];
|
|
7203
6821
|
function survivesCommit(record, committed) {
|
|
7204
6822
|
return record.o > committed || record.k === "spawn" || record.k === "out" || record.k === "err";
|
|
7205
6823
|
}
|
|
@@ -7441,6 +7059,8 @@ var ExecHost = class {
|
|
|
7441
7059
|
const jobId = params.jobId;
|
|
7442
7060
|
if (jobId !== void 0 && (typeof jobId !== "string" || !jobId || jobId.length > 256)) badRequest("Invalid jobId");
|
|
7443
7061
|
if (this.runningCount() >= (this.options.runningLimit ?? EXEC_RUNNING_LIMIT)) throw new KeeperMethodError(ExecErrorCode.limit, "Too many running commands in keeper-terminal");
|
|
7062
|
+
const registrationId = params.registrationId;
|
|
7063
|
+
if (registrationId !== void 0 && (typeof registrationId !== "string" || !registrationId || registrationId.length > 128 || /[\x00-\x1f]/.test(registrationId))) badRequest("Invalid registrationId");
|
|
7444
7064
|
const meta = {
|
|
7445
7065
|
v: 1,
|
|
7446
7066
|
execId,
|
|
@@ -7456,6 +7076,7 @@ var ExecHost = class {
|
|
|
7456
7076
|
onKeeperLoss,
|
|
7457
7077
|
createdAtMs: this.now(),
|
|
7458
7078
|
owner: this.options.owner,
|
|
7079
|
+
...typeof registrationId === "string" ? { registrationId } : {},
|
|
7459
7080
|
spawn: null,
|
|
7460
7081
|
exit: null,
|
|
7461
7082
|
logReclaimed: null
|
|
@@ -7666,14 +7287,14 @@ var ExecHost = class {
|
|
|
7666
7287
|
}
|
|
7667
7288
|
}
|
|
7668
7289
|
appendOutput(entry, stream, bytes, head) {
|
|
7669
|
-
const
|
|
7290
|
+
const input2 = { k: stream, so: entry.streamBytes[stream], b: bytes.toString("base64") };
|
|
7670
7291
|
entry.streamBytes[stream] += bytes.length;
|
|
7671
7292
|
if (head) {
|
|
7672
7293
|
entry.headBytes[stream] += bytes.length;
|
|
7673
|
-
this.appendKept(entry,
|
|
7294
|
+
this.appendKept(entry, input2);
|
|
7674
7295
|
return;
|
|
7675
7296
|
}
|
|
7676
|
-
const record = entry.log.append(
|
|
7297
|
+
const record = entry.log.append(input2);
|
|
7677
7298
|
const cost = bytes.length + RECORD_OVERHEAD;
|
|
7678
7299
|
const last = entry.runs[entry.runs.length - 1];
|
|
7679
7300
|
if (last && last.cost < RUN_COST) {
|
|
@@ -7720,8 +7341,8 @@ var ExecHost = class {
|
|
|
7720
7341
|
}
|
|
7721
7342
|
}
|
|
7722
7343
|
/** Appends to the log AND to keep.jsonl (spawn, gap, exit, head output): records the quota never drops. */
|
|
7723
|
-
appendKept(entry,
|
|
7724
|
-
const record = entry.log.append(
|
|
7344
|
+
appendKept(entry, input2) {
|
|
7345
|
+
const record = entry.log.append(input2);
|
|
7725
7346
|
if (entry.keepFd === void 0) entry.keepFd = openSync2(path3.join(entry.dir, KEEP_FILE), "a", 384);
|
|
7726
7347
|
writeAllSync(entry.keepFd, Buffer.from(`${JSON.stringify(record)}
|
|
7727
7348
|
`));
|
|
@@ -7911,6 +7532,7 @@ var ExecHost = class {
|
|
|
7911
7532
|
return {
|
|
7912
7533
|
execId: meta.execId,
|
|
7913
7534
|
label: meta.label,
|
|
7535
|
+
...meta.registrationId ? { registrationId: meta.registrationId } : {},
|
|
7914
7536
|
...meta.jobId ? { jobId: meta.jobId } : {},
|
|
7915
7537
|
state: this.stateOf(entry),
|
|
7916
7538
|
pid: meta.spawn?.pid ?? null,
|
|
@@ -8077,314 +7699,1097 @@ function messageOf(error) {
|
|
|
8077
7699
|
|
|
8078
7700
|
// src/workstation/keepers/terminal/keeper.ts
|
|
8079
7701
|
import { constants, promises as fs3 } from "node:fs";
|
|
7702
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
8080
7703
|
|
|
8081
|
-
// src/workstation/keepers/terminal/
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
import { execFile as execFile3 } from "node:child_process";
|
|
7704
|
+
// src/workstation/keepers/terminal/sessions.ts
|
|
7705
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
7706
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
8085
7707
|
import { createRequire } from "node:module";
|
|
8086
|
-
import
|
|
7708
|
+
import path5 from "node:path";
|
|
7709
|
+
|
|
7710
|
+
// src/workstation/keepers/terminal/gridProtocol.ts
|
|
7711
|
+
var TERMINAL_GRID_LIMITS = {
|
|
7712
|
+
minCols: 20,
|
|
7713
|
+
maxCols: 300,
|
|
7714
|
+
minRows: 5,
|
|
7715
|
+
maxRows: 100,
|
|
7716
|
+
maxSessions: 8,
|
|
7717
|
+
maxAttachments: 16,
|
|
7718
|
+
leaseMs: 15e3,
|
|
7719
|
+
scrollbackLines: 1e4,
|
|
7720
|
+
maxInputBytes: 64 * 1024,
|
|
7721
|
+
maxRequestBytes: 128 * 1024,
|
|
7722
|
+
maxResultBytes: 2 * 1024 * 1024,
|
|
7723
|
+
maxCachedFrames: 8,
|
|
7724
|
+
maxFrameCacheBytes: 8 * 1024 * 1024
|
|
7725
|
+
};
|
|
7726
|
+
var TERMINAL_STYLE_FLAGS = {
|
|
7727
|
+
bold: 1,
|
|
7728
|
+
dim: 2,
|
|
7729
|
+
italic: 4,
|
|
7730
|
+
underline: 8,
|
|
7731
|
+
blink: 16,
|
|
7732
|
+
inverse: 32,
|
|
7733
|
+
invisible: 64,
|
|
7734
|
+
strike: 128
|
|
7735
|
+
};
|
|
7736
|
+
var TERMINAL_RGB_COLOR_BASE = 16777216;
|
|
7737
|
+
|
|
7738
|
+
// src/workstation/keepers/terminal/frames.ts
|
|
7739
|
+
var TerminalFrames = class {
|
|
7740
|
+
cache = [];
|
|
7741
|
+
bytes = 0;
|
|
7742
|
+
/** A failed/oversized capture leaves both the revision and recovery cache untouched. */
|
|
7743
|
+
publish(snapshot, session, geometry) {
|
|
7744
|
+
validate(snapshot, session);
|
|
7745
|
+
const previous = this.cache.at(-1)?.frame;
|
|
7746
|
+
const sameSession = previous?.incarnation === session.incarnation && previous.id === session.id;
|
|
7747
|
+
const nextGeometry = geometry ?? (sameSession ? previous.geometry + Number(previous.cols !== snapshot.cols || previous.rows !== snapshot.rows) : 1);
|
|
7748
|
+
if (!Number.isSafeInteger(nextGeometry) || nextGeometry < 1 || sameSession && nextGeometry < previous.geometry) throw new Error("Invalid terminal geometry");
|
|
7749
|
+
const next = structuredClone({
|
|
7750
|
+
...snapshot,
|
|
7751
|
+
schema: 1,
|
|
7752
|
+
id: session.id,
|
|
7753
|
+
incarnation: session.incarnation,
|
|
7754
|
+
revision: sameSession ? previous.revision + 1 : 1,
|
|
7755
|
+
baseRevision: 0,
|
|
7756
|
+
geometry: nextGeometry,
|
|
7757
|
+
full: true,
|
|
7758
|
+
session
|
|
7759
|
+
});
|
|
7760
|
+
if (sameSession && equalContent(previous, next)) return;
|
|
7761
|
+
const bytes = resultBytes(next);
|
|
7762
|
+
if (!sameSession) {
|
|
7763
|
+
this.cache = [];
|
|
7764
|
+
this.bytes = 0;
|
|
7765
|
+
}
|
|
7766
|
+
this.cache.push({ frame: next, bytes });
|
|
7767
|
+
this.bytes += bytes;
|
|
7768
|
+
while (this.cache.length > TERMINAL_GRID_LIMITS.maxCachedFrames || this.bytes > TERMINAL_GRID_LIMITS.maxFrameCacheBytes) this.bytes -= this.cache.shift().bytes;
|
|
7769
|
+
}
|
|
7770
|
+
poll(after) {
|
|
7771
|
+
const current = this.cache.at(-1)?.frame;
|
|
7772
|
+
if (!current) throw new Error("Terminal frame has not been captured");
|
|
7773
|
+
if (after === current.revision) return structuredClone({ ...current, full: false, baseRevision: after, styles: [], changedRows: [] });
|
|
7774
|
+
const base = after === 0 ? void 0 : this.cache.find((entry) => entry.frame.revision === after)?.frame;
|
|
7775
|
+
if (!base || base.geometry !== current.geometry || base.buffer !== current.buffer || base.incarnation !== current.incarnation) return structuredClone(current);
|
|
7776
|
+
const changedRows = current.changedRows.filter((row, index) => semanticRow(row, current) !== semanticRow(base.changedRows[index], base));
|
|
7777
|
+
const delta = { ...current, full: false, baseRevision: after, changedRows };
|
|
7778
|
+
resultBytes(delta);
|
|
7779
|
+
return structuredClone(delta);
|
|
7780
|
+
}
|
|
7781
|
+
cacheStats() {
|
|
7782
|
+
return { frames: this.cache.length, bytes: this.bytes };
|
|
7783
|
+
}
|
|
7784
|
+
};
|
|
7785
|
+
function semanticRow(row, frame) {
|
|
7786
|
+
return JSON.stringify([row.wrapped ?? false, row.runs.flatMap((run) => run.cells.map((cell) => [cell.text, cell.width, frame.styles[run.style]]))]);
|
|
7787
|
+
}
|
|
7788
|
+
function equalContent(a, b) {
|
|
7789
|
+
const header = (frame) => JSON.stringify([
|
|
7790
|
+
frame.geometry,
|
|
7791
|
+
frame.cols,
|
|
7792
|
+
frame.rows,
|
|
7793
|
+
frame.buffer,
|
|
7794
|
+
frame.viewport,
|
|
7795
|
+
frame.cursor,
|
|
7796
|
+
frame.modes,
|
|
7797
|
+
frame.session
|
|
7798
|
+
]);
|
|
7799
|
+
return header(a) === header(b) && a.changedRows.every((row, index) => semanticRow(row, a) === semanticRow(b.changedRows[index], b));
|
|
7800
|
+
}
|
|
7801
|
+
function resultBytes(frame) {
|
|
7802
|
+
const bytes = Buffer.byteLength(JSON.stringify(frame));
|
|
7803
|
+
if (bytes > TERMINAL_GRID_LIMITS.maxResultBytes - 1024) throw new KeeperMethodError("pty_snapshot_too_large", "Terminal frame exceeds result limit; resize to a smaller viewport");
|
|
7804
|
+
return bytes;
|
|
7805
|
+
}
|
|
7806
|
+
function validate(snapshot, session) {
|
|
7807
|
+
if (snapshot.cols < TERMINAL_GRID_LIMITS.minCols || snapshot.cols > TERMINAL_GRID_LIMITS.maxCols || snapshot.rows < TERMINAL_GRID_LIMITS.minRows || snapshot.rows > TERMINAL_GRID_LIMITS.maxRows || snapshot.cols !== session.cols || snapshot.rows !== session.rows || snapshot.changedRows.length !== snapshot.rows) throw new Error("Terminal snapshot must contain a complete matching grid");
|
|
7808
|
+
for (const [index, row] of snapshot.changedRows.entries()) {
|
|
7809
|
+
if (row.index !== index || row.runs.reduce((count, run) => count + run.cells.length, 0) !== snapshot.cols || row.runs.some((run) => !snapshot.styles[run.style] || run.cells.some((cell) => typeof cell.text !== "string" || ![0, 1, 2].includes(cell.width)))) throw new Error("Terminal snapshot must contain complete rows and styles");
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7812
|
+
|
|
7813
|
+
// src/workstation/keepers/terminal/screen.ts
|
|
7814
|
+
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
8087
7815
|
var { Terminal } = import_headless.default;
|
|
8088
|
-
var {
|
|
8089
|
-
var
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
7816
|
+
var mouseEncodings = { 1005: "utf8", 1006: "sgr", 1015: "urxvt", 1016: "sgr-pixels" };
|
|
7817
|
+
var TerminalScreen = class {
|
|
7818
|
+
terminal;
|
|
7819
|
+
settled = Promise.resolve();
|
|
7820
|
+
resizeBarrier;
|
|
7821
|
+
pending = /* @__PURE__ */ new Set();
|
|
7822
|
+
closed = false;
|
|
7823
|
+
normalRestoreTop;
|
|
7824
|
+
alternateScroll = false;
|
|
7825
|
+
mouseEncoding = "default";
|
|
7826
|
+
constructor(cols, rows) {
|
|
7827
|
+
this.terminal = new Terminal({ cols, rows, scrollback: TERMINAL_GRID_LIMITS.scrollbackLines, allowProposedApi: true });
|
|
7828
|
+
for (const final of ["h", "l"]) this.terminal.parser.registerCsiHandler({ prefix: "?", final }, (params) => {
|
|
7829
|
+
for (const param of params) {
|
|
7830
|
+
if (param === 1007) this.alternateScroll = final === "h";
|
|
7831
|
+
const encoding = typeof param === "number" ? mouseEncodings[param] : void 0;
|
|
7832
|
+
if (encoding) this.mouseEncoding = final === "h" ? encoding : "default";
|
|
7833
|
+
}
|
|
7834
|
+
return false;
|
|
7835
|
+
});
|
|
7836
|
+
this.terminal.parser.registerEscHandler({ final: "c" }, () => {
|
|
7837
|
+
this.alternateScroll = false;
|
|
7838
|
+
this.mouseEncoding = "default";
|
|
7839
|
+
return false;
|
|
7840
|
+
});
|
|
7841
|
+
this.terminal.buffer.onBufferChange((buffer) => {
|
|
7842
|
+
const top = buffer.type === "normal" ? this.normalRestoreTop ?? buffer.viewportY : buffer.viewportY;
|
|
7843
|
+
if (buffer.type === "normal") this.normalRestoreTop = void 0;
|
|
7844
|
+
this.terminal.scrollToBottom();
|
|
7845
|
+
this.terminal.scrollToLine(top);
|
|
7846
|
+
});
|
|
7847
|
+
}
|
|
7848
|
+
write(data) {
|
|
7849
|
+
if (this.closed) return Promise.reject(new Error("Terminal screen is disposed"));
|
|
7850
|
+
const barrier = this.resizeBarrier;
|
|
7851
|
+
const operation = new Promise((resolve, reject) => {
|
|
7852
|
+
this.pending.add(reject);
|
|
7853
|
+
const write = () => {
|
|
7854
|
+
if (this.closed) return;
|
|
7855
|
+
try {
|
|
7856
|
+
this.terminal.write(data, () => {
|
|
7857
|
+
this.pending.delete(reject);
|
|
7858
|
+
resolve();
|
|
7859
|
+
});
|
|
7860
|
+
} catch (error) {
|
|
7861
|
+
this.pending.delete(reject);
|
|
7862
|
+
reject(error);
|
|
7863
|
+
}
|
|
7864
|
+
};
|
|
7865
|
+
if (barrier) void barrier.then(write, (error) => {
|
|
7866
|
+
this.pending.delete(reject);
|
|
7867
|
+
reject(error);
|
|
7868
|
+
});
|
|
7869
|
+
else write();
|
|
7870
|
+
});
|
|
7871
|
+
this.settled = operation;
|
|
7872
|
+
return operation;
|
|
7873
|
+
}
|
|
7874
|
+
resize(cols, rows) {
|
|
7875
|
+
if (this.closed) return Promise.reject(new Error("Terminal screen is disposed"));
|
|
7876
|
+
const previous = this.settled;
|
|
7877
|
+
const operation = previous.then(() => {
|
|
7878
|
+
if (this.closed) throw new Error("Terminal screen is disposed");
|
|
7879
|
+
const normal = this.terminal.buffer.normal;
|
|
7880
|
+
const anchor = this.anchor(normal);
|
|
7881
|
+
const live = (this.normalRestoreTop ?? normal.viewportY) === normal.baseY;
|
|
7882
|
+
this.terminal.resize(cols, rows);
|
|
7883
|
+
const top = live ? normal.baseY : anchor ? this.anchorLine(anchor, normal) : 0;
|
|
7884
|
+
if (this.terminal.buffer.active.type === "normal") {
|
|
7885
|
+
this.terminal.scrollToBottom();
|
|
7886
|
+
this.terminal.scrollToLine(top);
|
|
7887
|
+
} else {
|
|
7888
|
+
this.normalRestoreTop = Math.min(top, normal.baseY);
|
|
7889
|
+
}
|
|
7890
|
+
anchor?.marker.dispose();
|
|
7891
|
+
});
|
|
7892
|
+
this.resizeBarrier = operation;
|
|
7893
|
+
this.settled = operation;
|
|
7894
|
+
void operation.then(() => {
|
|
7895
|
+
if (this.resizeBarrier === operation) this.resizeBarrier = void 0;
|
|
7896
|
+
}, () => {
|
|
7897
|
+
if (this.resizeBarrier === operation) this.resizeBarrier = void 0;
|
|
7898
|
+
});
|
|
7899
|
+
return operation;
|
|
7900
|
+
}
|
|
7901
|
+
scroll(lines) {
|
|
7902
|
+
this.assertOpen();
|
|
7903
|
+
this.terminal.scrollLines(lines);
|
|
7904
|
+
}
|
|
7905
|
+
/** Only settled state may be published; callers await write/resize before capture. */
|
|
7906
|
+
capture() {
|
|
7907
|
+
this.assertOpen();
|
|
7908
|
+
if (this.pending.size || this.resizeBarrier) throw new Error("Terminal screen has pending writes or resize");
|
|
7909
|
+
const terminal = this.terminal;
|
|
7910
|
+
const buffer = terminal.buffer.active;
|
|
7911
|
+
const core = terminal._core;
|
|
7912
|
+
const styles = [];
|
|
7913
|
+
const styleIndices = /* @__PURE__ */ new Map();
|
|
7914
|
+
const changedRows = Array.from({ length: terminal.rows }, (_, index) => {
|
|
7915
|
+
const line = buffer.getLine(buffer.viewportY + index);
|
|
7916
|
+
const runs = [];
|
|
7917
|
+
for (let x = 0; x < terminal.cols; x++) {
|
|
7918
|
+
const cell = line.getCell(x);
|
|
7919
|
+
const style = cellStyle(cell);
|
|
7920
|
+
const key = `${style.fg},${style.bg},${style.flags}`;
|
|
7921
|
+
let styleIndex = styleIndices.get(key);
|
|
7922
|
+
if (styleIndex === void 0) {
|
|
7923
|
+
styleIndex = styles.length;
|
|
7924
|
+
styles.push(style);
|
|
7925
|
+
styleIndices.set(key, styleIndex);
|
|
7926
|
+
}
|
|
7927
|
+
let run = runs[runs.length - 1];
|
|
7928
|
+
if (!run || run.style !== styleIndex) {
|
|
7929
|
+
run = { style: styleIndex, cells: [] };
|
|
7930
|
+
runs.push(run);
|
|
7931
|
+
}
|
|
7932
|
+
run.cells.push({ text: cell.getChars(), width: cell.getWidth() });
|
|
7933
|
+
}
|
|
7934
|
+
return { index, runs, wrapped: line.isWrapped };
|
|
7935
|
+
});
|
|
7936
|
+
const y = buffer.baseY + buffer.cursorY - buffer.viewportY;
|
|
7937
|
+
return {
|
|
7938
|
+
cols: terminal.cols,
|
|
7939
|
+
rows: terminal.rows,
|
|
7940
|
+
buffer: buffer.type,
|
|
7941
|
+
viewport: { top: buffer.viewportY, totalLines: buffer.length, live: buffer.viewportY === buffer.baseY },
|
|
7942
|
+
cursor: {
|
|
7943
|
+
x: Math.min(buffer.cursorX, terminal.cols - 1),
|
|
7944
|
+
y,
|
|
7945
|
+
visible: !core.coreService.isCursorHidden && y >= 0 && y < terminal.rows,
|
|
7946
|
+
shape: core.coreService.decPrivateModes.cursorStyle ?? terminal.options.cursorStyle ?? "block",
|
|
7947
|
+
blink: core.coreService.decPrivateModes.cursorBlink ?? terminal.options.cursorBlink ?? false
|
|
7948
|
+
},
|
|
7949
|
+
modes: this.state().modes,
|
|
7950
|
+
styles,
|
|
7951
|
+
changedRows
|
|
7952
|
+
};
|
|
7953
|
+
}
|
|
7954
|
+
/** Cheap parsed state for input routing; never extracts viewport cells. */
|
|
7955
|
+
state() {
|
|
7956
|
+
this.assertOpen();
|
|
7957
|
+
if (this.pending.size || this.resizeBarrier) throw new Error("Terminal screen has pending writes or resize");
|
|
7958
|
+
const terminal = this.terminal;
|
|
7959
|
+
const modes = terminal.modes;
|
|
7960
|
+
return {
|
|
7961
|
+
buffer: terminal.buffer.active.type,
|
|
7962
|
+
modes: {
|
|
7963
|
+
applicationCursor: modes.applicationCursorKeysMode,
|
|
7964
|
+
applicationKeypad: modes.applicationKeypadMode,
|
|
7965
|
+
bracketedPaste: modes.bracketedPasteMode,
|
|
7966
|
+
alternateScroll: this.alternateScroll,
|
|
7967
|
+
focusReporting: modes.sendFocusMode,
|
|
7968
|
+
mouseTracking: modes.mouseTrackingMode,
|
|
7969
|
+
mouseEncoding: this.mouseEncoding
|
|
7970
|
+
}
|
|
7971
|
+
};
|
|
7972
|
+
}
|
|
7973
|
+
onTitleChange(listener) {
|
|
7974
|
+
return this.terminal.onTitleChange(listener);
|
|
7975
|
+
}
|
|
7976
|
+
onCwdChange(listener) {
|
|
7977
|
+
return this.terminal.parser.registerOscHandler(7, (uri) => {
|
|
7978
|
+
listener(uri);
|
|
7979
|
+
return true;
|
|
7980
|
+
});
|
|
7981
|
+
}
|
|
7982
|
+
onReply(listener) {
|
|
7983
|
+
return this.terminal.onData(listener);
|
|
7984
|
+
}
|
|
7985
|
+
dispose() {
|
|
7986
|
+
if (this.closed) return;
|
|
7987
|
+
this.closed = true;
|
|
7988
|
+
for (const reject of this.pending) reject(new Error("Terminal screen is disposed"));
|
|
7989
|
+
this.pending.clear();
|
|
7990
|
+
this.terminal.dispose();
|
|
7991
|
+
}
|
|
7992
|
+
assertOpen() {
|
|
7993
|
+
if (this.closed) throw new Error("Terminal screen is disposed");
|
|
7994
|
+
}
|
|
7995
|
+
anchor(buffer) {
|
|
7996
|
+
const top = this.normalRestoreTop ?? buffer.viewportY;
|
|
7997
|
+
if (top === buffer.baseY) return void 0;
|
|
7998
|
+
let end = top + 1;
|
|
7999
|
+
while (buffer.getLine(end)?.isWrapped) end++;
|
|
8000
|
+
let cellsFromEnd = this.trimmedLength(buffer, end - 1);
|
|
8001
|
+
for (let line = top; line < end - 1; line++) cellsFromEnd += this.wrappedLength(buffer, line);
|
|
8002
|
+
const marker = this.terminal.buffer.active.type === "normal" ? this.terminal.registerMarker(end - buffer.baseY - buffer.cursorY) : this.terminal._core.buffers.normal.addMarker(end);
|
|
8003
|
+
return marker ? { marker, cellsFromEnd } : void 0;
|
|
8004
|
+
}
|
|
8005
|
+
anchorLine(anchor, buffer) {
|
|
8006
|
+
if (anchor.marker.isDisposed) return 0;
|
|
8007
|
+
let line = Math.min(anchor.marker.line, buffer.length) - 1;
|
|
8008
|
+
if (line < 0) return 0;
|
|
8009
|
+
let remaining = anchor.cellsFromEnd - this.trimmedLength(buffer, line);
|
|
8010
|
+
while (remaining > 0 && line > 0 && buffer.getLine(line)?.isWrapped) {
|
|
8011
|
+
line--;
|
|
8012
|
+
remaining -= this.wrappedLength(buffer, line);
|
|
8013
|
+
}
|
|
8014
|
+
return line;
|
|
8015
|
+
}
|
|
8016
|
+
trimmedLength(buffer, line) {
|
|
8017
|
+
const row = buffer.getLine(line);
|
|
8018
|
+
for (let x = this.terminal.cols - 1; x >= 0; x--) {
|
|
8019
|
+
const cell = row.getCell(x);
|
|
8020
|
+
if (cell.getChars()) return x + cell.getWidth();
|
|
8021
|
+
}
|
|
8022
|
+
return 0;
|
|
8023
|
+
}
|
|
8024
|
+
wrappedLength(buffer, line) {
|
|
8025
|
+
const last = buffer.getLine(line).getCell(this.terminal.cols - 1);
|
|
8026
|
+
return this.terminal.cols - (last.getChars() === "" && last.getWidth() === 1 && buffer.getLine(line + 1)?.getCell(0)?.getWidth() === 2 ? 1 : 0);
|
|
8027
|
+
}
|
|
8095
8028
|
};
|
|
8096
|
-
function
|
|
8097
|
-
|
|
8029
|
+
function cellStyle(cell) {
|
|
8030
|
+
const flags = TERMINAL_STYLE_FLAGS;
|
|
8031
|
+
return {
|
|
8032
|
+
fg: cell.isFgDefault() ? -1 : cell.getFgColor() + (cell.isFgRGB() ? TERMINAL_RGB_COLOR_BASE : 0),
|
|
8033
|
+
bg: cell.isBgDefault() ? -1 : cell.getBgColor() + (cell.isBgRGB() ? TERMINAL_RGB_COLOR_BASE : 0),
|
|
8034
|
+
flags: (cell.isBold() ? flags.bold : 0) | (cell.isDim() ? flags.dim : 0) | (cell.isItalic() ? flags.italic : 0) | (cell.isUnderline() ? flags.underline : 0) | (cell.isBlink() ? flags.blink : 0) | (cell.isInverse() ? flags.inverse : 0) | (cell.isInvisible() ? flags.invisible : 0) | (cell.isStrikethrough() ? flags.strike : 0)
|
|
8035
|
+
};
|
|
8098
8036
|
}
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8037
|
+
|
|
8038
|
+
// src/workstation/keepers/terminal/input.ts
|
|
8039
|
+
var esc = "\x1B";
|
|
8040
|
+
var modifiers = (mask) => 1 + (mask & 1) + (mask & 2) + (mask & 4) + (mask & 8);
|
|
8041
|
+
var arrows = { 79: "C", 80: "D", 81: "B", 82: "A", 74: "H", 77: "F" };
|
|
8042
|
+
var tilde = { 73: 2, 76: 3, 75: 5, 78: 6, 62: 15, 63: 17, 64: 18, 65: 19, 66: 20, 67: 21, 68: 23, 69: 24 };
|
|
8043
|
+
var keypad = {
|
|
8044
|
+
84: ["/", "o"],
|
|
8045
|
+
85: ["*", "j"],
|
|
8046
|
+
86: ["-", "m"],
|
|
8047
|
+
87: ["+", "k"],
|
|
8048
|
+
88: ["\r", "M"],
|
|
8049
|
+
89: ["1", "q"],
|
|
8050
|
+
90: ["2", "r"],
|
|
8051
|
+
91: ["3", "s"],
|
|
8052
|
+
92: ["4", "t"],
|
|
8053
|
+
93: ["5", "u"],
|
|
8054
|
+
94: ["6", "v"],
|
|
8055
|
+
95: ["7", "w"],
|
|
8056
|
+
96: ["8", "x"],
|
|
8057
|
+
97: ["9", "y"],
|
|
8058
|
+
98: ["0", "p"],
|
|
8059
|
+
99: [".", "n"],
|
|
8060
|
+
103: ["=", "X"]
|
|
8061
|
+
};
|
|
8062
|
+
var TerminalInputEncoder = class {
|
|
8063
|
+
buttons = /* @__PURE__ */ new Set();
|
|
8064
|
+
release() {
|
|
8065
|
+
this.buttons.clear();
|
|
8066
|
+
}
|
|
8067
|
+
encode(event, screen) {
|
|
8068
|
+
switch (event.kind) {
|
|
8069
|
+
case "release":
|
|
8070
|
+
this.release();
|
|
8071
|
+
return "";
|
|
8072
|
+
case "text":
|
|
8073
|
+
return event.text;
|
|
8074
|
+
case "paste":
|
|
8075
|
+
return screen.modes.bracketedPaste ? `${esc}[200~${event.text}${esc}[201~` : event.text;
|
|
8076
|
+
case "key":
|
|
8077
|
+
return event.down ? encodeKey(event.usage, event.modifiers, screen.modes) : "";
|
|
8078
|
+
case "button": {
|
|
8079
|
+
if (event.down) this.buttons.add(event.button);
|
|
8080
|
+
else this.buttons.delete(event.button);
|
|
8081
|
+
if (screen.modes.mouseTracking === "none" || !event.down && screen.modes.mouseTracking === "x10") return "";
|
|
8082
|
+
return mouse(event.button, event.x, event.y, event.modifiers, screen.modes, !event.down);
|
|
8083
|
+
}
|
|
8084
|
+
case "pointer": {
|
|
8085
|
+
const tracking = screen.modes.mouseTracking;
|
|
8086
|
+
if (tracking !== "any" && !(tracking === "drag" && this.buttons.size)) return "";
|
|
8087
|
+
return mouse(32 + (this.buttons.values().next().value ?? 3), event.x, event.y, event.modifiers, screen.modes);
|
|
8088
|
+
}
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
};
|
|
8092
|
+
function createTerminalInput(screen) {
|
|
8093
|
+
const clients = /* @__PURE__ */ new Map();
|
|
8094
|
+
const encoder = (id) => {
|
|
8095
|
+
let value = clients.get(id);
|
|
8096
|
+
if (!value) {
|
|
8097
|
+
value = new TerminalInputEncoder();
|
|
8098
|
+
clients.set(id, value);
|
|
8099
|
+
}
|
|
8100
|
+
return value;
|
|
8101
|
+
};
|
|
8102
|
+
return {
|
|
8103
|
+
input(event, clientId, context) {
|
|
8104
|
+
return encoder(clientId).encode(event, context);
|
|
8105
|
+
},
|
|
8106
|
+
scroll(gesture, _clientId, context) {
|
|
8107
|
+
if (!gesture.lines) return "";
|
|
8108
|
+
const state = screen.state();
|
|
8109
|
+
if (context.modes.mouseTracking === "x10") return "";
|
|
8110
|
+
if (context.modes.mouseTracking !== "none") return repeat(mouse(gesture.lines < 0 ? 64 : 65, gesture.x, gesture.y, gesture.modifiers, context.modes), Math.abs(gesture.lines));
|
|
8111
|
+
if (state.buffer === "normal") return void 0;
|
|
8112
|
+
if (!context.modes.alternateScroll) return "";
|
|
8113
|
+
return repeat(encodeKey(gesture.lines < 0 ? 82 : 81, gesture.modifiers, context.modes), Math.abs(gesture.lines));
|
|
8114
|
+
},
|
|
8115
|
+
release(clientId) {
|
|
8116
|
+
clients.get(clientId)?.release();
|
|
8117
|
+
clients.delete(clientId);
|
|
8118
|
+
},
|
|
8119
|
+
dispose() {
|
|
8120
|
+
clients.clear();
|
|
8121
|
+
}
|
|
8122
|
+
};
|
|
8103
8123
|
}
|
|
8104
|
-
function
|
|
8105
|
-
|
|
8106
|
-
if (
|
|
8107
|
-
return
|
|
8124
|
+
function repeat(bytes, count) {
|
|
8125
|
+
if (!bytes) return "";
|
|
8126
|
+
if (count > Math.floor(TERMINAL_GRID_LIMITS.maxInputBytes / Buffer.byteLength(bytes))) throw new KeeperMethodError("bad_request", "Terminal input exceeds limit");
|
|
8127
|
+
if (typeof bytes === "string") return bytes.repeat(count);
|
|
8128
|
+
return Buffer.concat(Array.from({ length: count }, () => bytes));
|
|
8108
8129
|
}
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8130
|
+
function mouse(button, x, y, mask, modes, release = false) {
|
|
8131
|
+
if (modes.mouseEncoding === "sgr-pixels") return "";
|
|
8132
|
+
const mods = modes.mouseTracking === "x10" ? 0 : (mask & 1 ? 4 : 0) + (mask & 2 ? 8 : 0) + (mask & 4 ? 16 : 0);
|
|
8133
|
+
if (modes.mouseEncoding === "sgr") return `${esc}[<${button + mods};${x + 1};${y + 1}${release ? "m" : "M"}`;
|
|
8134
|
+
const code = (release ? 3 : button) + mods + 32;
|
|
8135
|
+
if (modes.mouseEncoding === "urxvt") return `${esc}[${code};${x + 1};${y + 1}M`;
|
|
8136
|
+
if (modes.mouseEncoding === "default" && (x > 222 || y > 222)) return "";
|
|
8137
|
+
if (modes.mouseEncoding === "default") return Buffer.from([27, 91, 77, code, x + 33, y + 33]);
|
|
8138
|
+
return `${esc}[M${String.fromCharCode(code, x + 33, y + 33)}`;
|
|
8139
|
+
}
|
|
8140
|
+
function encodeKey(usage, mask, modes) {
|
|
8141
|
+
const mod = modifiers(mask);
|
|
8142
|
+
if (arrows[usage]) return mod > 1 ? `${esc}[1;${mod}${arrows[usage]}` : `${esc}${modes.applicationCursor ? "O" : "["}${arrows[usage]}`;
|
|
8143
|
+
if (tilde[usage]) return `${esc}[${tilde[usage]}${mod > 1 ? `;${mod}` : ""}~`;
|
|
8144
|
+
if (usage >= 58 && usage <= 61) return mod > 1 ? `${esc}[1;${mod}${String.fromCharCode(80 + usage - 58)}` : `${esc}O${String.fromCharCode(80 + usage - 58)}`;
|
|
8145
|
+
if (keypad[usage]) {
|
|
8146
|
+
if (mask & 8 && usage !== 88) return "";
|
|
8147
|
+
return modes.applicationKeypad ? mod > 1 ? `${esc}[1;${mod}${keypad[usage][1]}` : `${esc}O${keypad[usage][1]}` : prefixed(keypad[usage][0], mask);
|
|
8148
|
+
}
|
|
8149
|
+
if (usage === 40) return prefixed("\r", mask);
|
|
8150
|
+
if (usage === 41) return esc;
|
|
8151
|
+
if (usage === 42) return prefixed(mask & 4 ? "\b" : "\x7F", mask);
|
|
8152
|
+
if (usage === 43) return mask & 1 ? `${esc}[Z` : prefixed(" ", mask);
|
|
8153
|
+
if (mask & 8) return "";
|
|
8154
|
+
let text = "";
|
|
8155
|
+
if (usage >= 4 && usage <= 29) text = String.fromCharCode((mask & 1 ? 65 : 97) + usage - 4);
|
|
8156
|
+
else if (usage >= 30 && usage <= 39) text = (mask & 1 ? "!@#$%^&*()" : "1234567890")[usage - 30];
|
|
8157
|
+
else {
|
|
8158
|
+
const punctuation = { 44: [" ", " "], 45: ["-", "_"], 46: ["=", "+"], 47: ["[", "{"], 48: ["]", "}"], 49: ["\\", "|"], 50: ["#", "~"], 51: [";", ":"], 52: ["'", '"'], 53: ["`", "~"], 54: [",", "<"], 55: [".", ">"], 56: ["/", "?"] };
|
|
8159
|
+
text = punctuation[usage]?.[mask & 1 ? 1 : 0] ?? "";
|
|
8160
|
+
}
|
|
8161
|
+
if (mask & 4) {
|
|
8162
|
+
const upper = text.toUpperCase();
|
|
8163
|
+
if (upper >= "@" && upper <= "_") text = String.fromCharCode(upper.charCodeAt(0) - 64);
|
|
8164
|
+
else if (text === " " || text === "2" || text === "`") text = "\0";
|
|
8165
|
+
else if (text === "3") text = esc;
|
|
8166
|
+
else if (text === "4") text = "";
|
|
8167
|
+
else if (text === "5") text = "";
|
|
8168
|
+
else if (text === "6") text = "";
|
|
8169
|
+
else if (text === "7" || text === "/") text = "";
|
|
8170
|
+
else if (text === "8" || text === "?") text = "\x7F";
|
|
8171
|
+
}
|
|
8172
|
+
return prefixed(text, mask);
|
|
8173
|
+
}
|
|
8174
|
+
function prefixed(text, mask) {
|
|
8175
|
+
return text && mask & 2 ? esc + text : text;
|
|
8176
|
+
}
|
|
8177
|
+
|
|
8178
|
+
// src/workstation/keepers/terminal/metadata.ts
|
|
8179
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
8180
|
+
import { readlink } from "node:fs/promises";
|
|
8181
|
+
import { hostname as localHostname } from "node:os";
|
|
8182
|
+
import path4 from "node:path";
|
|
8183
|
+
var clean = (value) => [...value.replace(/[\x00-\x1f\x7f-\x9f]/g, "").trim()].slice(0, 256).join("");
|
|
8184
|
+
var validCwd = (value) => value.startsWith("/") && !/[\x00-\x1f\x7f-\x9f]/.test(value);
|
|
8185
|
+
var TerminalMetadata = class {
|
|
8186
|
+
constructor(options) {
|
|
8113
8187
|
this.options = options;
|
|
8188
|
+
this.cwd = options.cwd;
|
|
8114
8189
|
this.now = options.now ?? Date.now;
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8190
|
+
this.hostname = (options.hostname ?? localHostname()).toLowerCase();
|
|
8191
|
+
this.listeners = [options.screen.onTitleChange((title) => {
|
|
8192
|
+
if (this.closed) return;
|
|
8193
|
+
const previous = this.title;
|
|
8194
|
+
this.explicitTitle = clean(title);
|
|
8195
|
+
if (this.title !== previous) options.changed();
|
|
8196
|
+
}), options.screen.onCwdChange((uri) => this.osc7(uri))];
|
|
8120
8197
|
}
|
|
8121
8198
|
options;
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8199
|
+
cwd;
|
|
8200
|
+
cwdSource = "launch";
|
|
8201
|
+
explicitTitle = "";
|
|
8202
|
+
listeners;
|
|
8125
8203
|
now;
|
|
8126
|
-
|
|
8127
|
-
|
|
8204
|
+
hostname;
|
|
8205
|
+
lastLookup = -Infinity;
|
|
8206
|
+
oscRevision = 0;
|
|
8207
|
+
closed = false;
|
|
8208
|
+
pending;
|
|
8209
|
+
cancelLookup;
|
|
8210
|
+
timer;
|
|
8211
|
+
get title() {
|
|
8212
|
+
return this.explicitTitle || clean(path4.posix.basename(this.cwd) || this.cwd) || "Terminal";
|
|
8128
8213
|
}
|
|
8129
|
-
|
|
8130
|
-
return {
|
|
8131
|
-
}
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8214
|
+
read() {
|
|
8215
|
+
return { title: this.title, cwd: this.cwd, cwdSource: this.cwdSource };
|
|
8216
|
+
}
|
|
8217
|
+
/** Called once by the host factory, independently of output and attachments. */
|
|
8218
|
+
start() {
|
|
8219
|
+
if (this.closed || this.timer) return;
|
|
8220
|
+
void this.refresh();
|
|
8221
|
+
this.timer = setInterval(() => {
|
|
8222
|
+
void this.refresh();
|
|
8223
|
+
}, 2e3);
|
|
8224
|
+
this.timer.unref();
|
|
8225
|
+
}
|
|
8226
|
+
refresh() {
|
|
8227
|
+
if (this.closed || this.options.live?.() === false) return Promise.resolve();
|
|
8228
|
+
if (this.pending) return this.pending;
|
|
8229
|
+
if (this.now() - this.lastLookup < 2e3) return Promise.resolve();
|
|
8230
|
+
this.lastLookup = this.now();
|
|
8231
|
+
const revision = this.oscRevision;
|
|
8232
|
+
let timeout;
|
|
8233
|
+
const bounded = new Promise((resolve) => {
|
|
8234
|
+
timeout = setTimeout(() => resolve(null), 1e3);
|
|
8235
|
+
this.cancelLookup = () => resolve(null);
|
|
8236
|
+
try {
|
|
8237
|
+
void (this.options.lookup ?? lookupProcessCwd)(this.options.pid).then(resolve, () => resolve(null));
|
|
8238
|
+
} catch {
|
|
8239
|
+
resolve(null);
|
|
8240
|
+
}
|
|
8241
|
+
});
|
|
8242
|
+
this.pending = bounded.then((cwd) => {
|
|
8243
|
+
if (!this.closed && this.options.live?.() !== false && revision === this.oscRevision && cwd && validCwd(cwd)) this.updateCwd(cwd, "process");
|
|
8244
|
+
}).finally(() => {
|
|
8245
|
+
clearTimeout(timeout);
|
|
8246
|
+
this.cancelLookup = void 0;
|
|
8247
|
+
this.pending = void 0;
|
|
8248
|
+
});
|
|
8249
|
+
return this.pending;
|
|
8250
|
+
}
|
|
8251
|
+
dispose() {
|
|
8252
|
+
if (this.closed) return;
|
|
8253
|
+
this.closed = true;
|
|
8254
|
+
clearInterval(this.timer);
|
|
8255
|
+
this.timer = void 0;
|
|
8256
|
+
this.cancelLookup?.();
|
|
8257
|
+
for (const listener of this.listeners) listener.dispose();
|
|
8258
|
+
}
|
|
8259
|
+
osc7(uri) {
|
|
8260
|
+
if (this.closed) return;
|
|
8261
|
+
try {
|
|
8262
|
+
if (/[\x00-\x1f\x7f-\x9f]/.test(uri)) return;
|
|
8263
|
+
const url = new URL(uri);
|
|
8264
|
+
if (url.protocol !== "file:" || url.username || url.password || url.port || uri.includes("?") || uri.includes("#")) return;
|
|
8265
|
+
const host = url.hostname.toLowerCase();
|
|
8266
|
+
if (host && host !== "localhost" && host !== this.hostname) return;
|
|
8267
|
+
const cwd = decodeURIComponent(url.pathname);
|
|
8268
|
+
if (!validCwd(cwd)) return;
|
|
8269
|
+
this.oscRevision++;
|
|
8270
|
+
this.updateCwd(cwd, "osc7");
|
|
8271
|
+
} catch {
|
|
8143
8272
|
}
|
|
8144
8273
|
}
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8274
|
+
updateCwd(cwd, source) {
|
|
8275
|
+
if (cwd === this.cwd && source === this.cwdSource) return;
|
|
8276
|
+
this.cwd = cwd;
|
|
8277
|
+
this.cwdSource = source;
|
|
8278
|
+
this.options.changed();
|
|
8279
|
+
}
|
|
8280
|
+
};
|
|
8281
|
+
async function lookupProcessCwd(pid, platform = process.platform) {
|
|
8282
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return null;
|
|
8283
|
+
if (platform === "linux") {
|
|
8284
|
+
try {
|
|
8285
|
+
return await readlink(`/proc/${pid}/cwd`);
|
|
8286
|
+
} catch {
|
|
8287
|
+
return null;
|
|
8150
8288
|
}
|
|
8151
8289
|
}
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
if (s.pendingBytes > 256 * 1024) s.pty.pause();
|
|
8157
|
-
s.rendered = new Promise((resolve) => {
|
|
8158
|
-
s.terminal.write(data, () => {
|
|
8159
|
-
s.seq += 1;
|
|
8160
|
-
s.ring.push({ seq: s.seq, data, bytes });
|
|
8161
|
-
s.ringBytes += bytes;
|
|
8162
|
-
const limit = this.options.historyBytes ?? PTY_HISTORY_BYTES;
|
|
8163
|
-
while (s.ringBytes > limit && s.ring.length) s.ringBytes -= s.ring.shift().bytes;
|
|
8164
|
-
s.pendingBytes -= bytes;
|
|
8165
|
-
if (s.pendingBytes < 64 * 1024 && !s.exited) s.pty.resume();
|
|
8166
|
-
resolve();
|
|
8167
|
-
});
|
|
8290
|
+
if (platform !== "darwin") return null;
|
|
8291
|
+
return new Promise((resolve) => {
|
|
8292
|
+
execFile3("lsof", ["-a", "-p", String(pid), "-d", "cwd", "-Fn"], { timeout: 1e3, maxBuffer: 64 * 1024 }, (error, stdout) => {
|
|
8293
|
+
resolve(error ? null : stdout.split("\n").find((line) => line.startsWith("n/"))?.slice(1) ?? null);
|
|
8168
8294
|
});
|
|
8295
|
+
});
|
|
8296
|
+
}
|
|
8297
|
+
function createTerminalMetadata(context) {
|
|
8298
|
+
const initial = context.session();
|
|
8299
|
+
const metadata = new TerminalMetadata({
|
|
8300
|
+
screen: context.screen,
|
|
8301
|
+
cwd: initial.cwd,
|
|
8302
|
+
pid: context.pty.pid,
|
|
8303
|
+
changed: context.changed,
|
|
8304
|
+
live: () => !context.session().exited
|
|
8305
|
+
});
|
|
8306
|
+
metadata.start();
|
|
8307
|
+
return metadata;
|
|
8308
|
+
}
|
|
8309
|
+
|
|
8310
|
+
// src/workstation/keepers/terminal/sessions.ts
|
|
8311
|
+
var NATIVE_PTY_OPERATIONS = /* @__PURE__ */ new Set(["attach", "poll", "resize", "input", "scroll", "detach", "close"]);
|
|
8312
|
+
var bad = (message) => {
|
|
8313
|
+
throw new KeeperMethodError("bad_request", message);
|
|
8314
|
+
};
|
|
8315
|
+
var fail = (code, message) => {
|
|
8316
|
+
throw new KeeperMethodError(code, message);
|
|
8317
|
+
};
|
|
8318
|
+
var ok = { ok: true };
|
|
8319
|
+
var nativeScheduler = {
|
|
8320
|
+
schedule(callback, delay) {
|
|
8321
|
+
const timer = setTimeout(callback, delay);
|
|
8322
|
+
timer.unref();
|
|
8323
|
+
return { dispose: () => clearTimeout(timer) };
|
|
8169
8324
|
}
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8325
|
+
};
|
|
8326
|
+
var basename = (name) => path5.basename(name.trim()).replace(/^-/, "");
|
|
8327
|
+
var NativePtySessions = class {
|
|
8328
|
+
constructor(options = {}) {
|
|
8329
|
+
this.options = options;
|
|
8330
|
+
this.now = options.now ?? Date.now;
|
|
8331
|
+
this.scheduler = options.scheduler ?? nativeScheduler;
|
|
8332
|
+
try {
|
|
8333
|
+
this.module = (options.loadPty ?? (() => createRequire(import.meta.url)("node-pty")))();
|
|
8334
|
+
} catch {
|
|
8335
|
+
this.unavailable = "Terminal native dependency unavailable; reinstall CLI with optional node-pty support";
|
|
8336
|
+
}
|
|
8176
8337
|
}
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
const
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
const
|
|
8205
|
-
const serializer = new SerializeAddon();
|
|
8206
|
-
terminal.loadAddon(serializer);
|
|
8338
|
+
options;
|
|
8339
|
+
sessions = /* @__PURE__ */ new Map();
|
|
8340
|
+
now;
|
|
8341
|
+
scheduler;
|
|
8342
|
+
module;
|
|
8343
|
+
unavailable;
|
|
8344
|
+
disposed = false;
|
|
8345
|
+
list() {
|
|
8346
|
+
return { schema: 1, limits: { ...TERMINAL_GRID_LIMITS }, sessions: [...this.sessions.values()].map((s) => this.descriptor(s)) };
|
|
8347
|
+
}
|
|
8348
|
+
async create(params, launch) {
|
|
8349
|
+
this.available();
|
|
8350
|
+
request(params);
|
|
8351
|
+
keys2(params, ["id", "cwd", "registrationId"]);
|
|
8352
|
+
const id = identifier(params, "id");
|
|
8353
|
+
if (params.registrationId !== void 0) identifier(params, "registrationId");
|
|
8354
|
+
if (params.cwd !== void 0 && (typeof params.cwd !== "string" || params.cwd.includes("\0"))) bad("Invalid cwd");
|
|
8355
|
+
const existing = this.sessions.get(id);
|
|
8356
|
+
if (existing) return this.descriptor(existing);
|
|
8357
|
+
this.checkLimit();
|
|
8358
|
+
const resolved = await launch();
|
|
8359
|
+
this.available();
|
|
8360
|
+
const concurrent = this.sessions.get(id);
|
|
8361
|
+
if (concurrent) return this.descriptor(concurrent);
|
|
8362
|
+
this.checkLimit();
|
|
8363
|
+
const cols = 100;
|
|
8364
|
+
const rows = 30;
|
|
8365
|
+
const screen = new TerminalScreen(cols, rows);
|
|
8207
8366
|
let pty;
|
|
8208
8367
|
try {
|
|
8209
|
-
pty = this.
|
|
8368
|
+
pty = this.module.spawn(resolved.shell, ["-l"], { name: "xterm-256color", cwd: resolved.cwd, cols, rows, env: { ...resolved.env, TERM: "xterm-256color", COLORTERM: "truecolor" } });
|
|
8210
8369
|
} catch (error) {
|
|
8211
|
-
|
|
8370
|
+
screen.dispose();
|
|
8212
8371
|
throw error;
|
|
8213
8372
|
}
|
|
8214
|
-
const
|
|
8215
|
-
const
|
|
8216
|
-
const
|
|
8217
|
-
id,
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
rows,
|
|
8222
|
-
exited: false,
|
|
8223
|
-
exitCode: null,
|
|
8224
|
-
controllerId: clientId,
|
|
8373
|
+
const createdAt = this.now();
|
|
8374
|
+
const shell = basename(resolved.shell);
|
|
8375
|
+
const s = {
|
|
8376
|
+
value: { id, ...typeof params.registrationId === "string" ? { registrationId: params.registrationId } : {}, incarnation: randomUUID3(), title: "Terminal", cwd: resolved.cwd, cwdSource: "launch", cols, rows, createdAt, exited: false, exitCode: null },
|
|
8377
|
+
shell,
|
|
8378
|
+
shellNames: /* @__PURE__ */ new Set([shell]),
|
|
8379
|
+
shellNameStarted: false,
|
|
8225
8380
|
pty,
|
|
8381
|
+
screen,
|
|
8382
|
+
frames: new TerminalFrames(),
|
|
8383
|
+
attachments: /* @__PURE__ */ new Map(),
|
|
8384
|
+
geometry: 1,
|
|
8226
8385
|
closed: false,
|
|
8227
|
-
|
|
8228
|
-
serializer,
|
|
8229
|
-
seq: 0,
|
|
8230
|
-
ring: [],
|
|
8231
|
-
ringBytes: 0,
|
|
8232
|
-
pendingBytes: 0,
|
|
8386
|
+
queue: Promise.resolve(),
|
|
8233
8387
|
rendered: Promise.resolve(),
|
|
8234
|
-
|
|
8388
|
+
pendingBytes: 0,
|
|
8389
|
+
dirty: true,
|
|
8390
|
+
capturedAt: -Infinity,
|
|
8391
|
+
listeners: [],
|
|
8392
|
+
input: createTerminalInput(screen),
|
|
8235
8393
|
exitedAt: 0,
|
|
8236
|
-
|
|
8237
|
-
observed: { label: shellName, state: "idle", since: created }
|
|
8394
|
+
observed: { label: shell, state: "idle", since: createdAt }
|
|
8238
8395
|
};
|
|
8239
|
-
pty
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8396
|
+
const context = { pty, screen, session: () => this.descriptor(s), changed: () => this.dirty(s) };
|
|
8397
|
+
try {
|
|
8398
|
+
s.input = this.options.createInput?.(context) ?? s.input;
|
|
8399
|
+
s.metadata = (this.options.createMetadata ?? createTerminalMetadata)(context);
|
|
8400
|
+
this.capture(s, true);
|
|
8401
|
+
s.listeners.push(disposable(pty.onData((data) => this.output(s, data))), disposable(pty.onExit((event) => {
|
|
8402
|
+
if (s.closed) return;
|
|
8403
|
+
s.shellNameTimer?.dispose();
|
|
8404
|
+
s.shellNameTimer = void 0;
|
|
8405
|
+
s.value.exited = true;
|
|
8406
|
+
s.value.exitCode = event.exitCode;
|
|
8407
|
+
s.exitedAt = this.now();
|
|
8408
|
+
this.dirty(s);
|
|
8409
|
+
})), screen.onReply((data) => {
|
|
8410
|
+
if (!s.closed && !s.value.exited) {
|
|
8411
|
+
try {
|
|
8412
|
+
pty.write(data);
|
|
8413
|
+
} catch (error) {
|
|
8414
|
+
this.failed(s, error);
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8417
|
+
}));
|
|
8418
|
+
this.sessions.set(id, s);
|
|
8419
|
+
} catch (error) {
|
|
8420
|
+
await this.close(s);
|
|
8421
|
+
throw error;
|
|
8422
|
+
}
|
|
8423
|
+
return this.descriptor(s);
|
|
8424
|
+
}
|
|
8425
|
+
async operate(op, params) {
|
|
8426
|
+
request(params);
|
|
8427
|
+
const id = identifier(params, "id");
|
|
8428
|
+
const incarnation = identifier(params, "incarnation");
|
|
8260
8429
|
const s = this.sessions.get(id);
|
|
8261
|
-
if (!s)
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
if (
|
|
8269
|
-
|
|
8270
|
-
|
|
8430
|
+
if (!s) {
|
|
8431
|
+
if (op === "close" || op === "detach") return ok;
|
|
8432
|
+
return fail("pty_not_found", "Terminal session not found; keeper restart loses live PTYs");
|
|
8433
|
+
}
|
|
8434
|
+
if (s.value.incarnation !== incarnation) return fail("pty_incarnation_mismatch", "Terminal incarnation no longer matches");
|
|
8435
|
+
return this.ordered(s, async () => {
|
|
8436
|
+
if (s.closed) {
|
|
8437
|
+
if (op === "close" || op === "detach") return ok;
|
|
8438
|
+
return fail("pty_not_found", "Terminal session is closed");
|
|
8439
|
+
}
|
|
8440
|
+
if (op === "close") {
|
|
8441
|
+
keys2(params, ["id", "incarnation"]);
|
|
8442
|
+
await this.close(s);
|
|
8443
|
+
return ok;
|
|
8271
8444
|
}
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8445
|
+
await this.expire(s);
|
|
8446
|
+
const clientId = identifier(params, "clientId");
|
|
8447
|
+
const ref = ["id", "incarnation", "clientId"];
|
|
8448
|
+
if (op === "detach") {
|
|
8449
|
+
keys2(params, ref);
|
|
8450
|
+
this.release(s, clientId);
|
|
8451
|
+
await this.capacity(s);
|
|
8452
|
+
return ok;
|
|
8453
|
+
}
|
|
8454
|
+
if (op === "attach") {
|
|
8455
|
+
keys2(params, [...ref, "cols", "rows"]);
|
|
8456
|
+
const cols = integer2(params, "cols", TERMINAL_GRID_LIMITS.minCols, TERMINAL_GRID_LIMITS.maxCols);
|
|
8457
|
+
const rows = integer2(params, "rows", TERMINAL_GRID_LIMITS.minRows, TERMINAL_GRID_LIMITS.maxRows);
|
|
8458
|
+
if (!s.attachments.has(clientId) && s.attachments.size >= TERMINAL_GRID_LIMITS.maxAttachments) return fail("pty_limit", "Terminal attachment limit exceeded");
|
|
8459
|
+
const previous = s.attachments.get(clientId);
|
|
8460
|
+
s.attachments.set(clientId, { cols, rows, expires: this.now() + TERMINAL_GRID_LIMITS.leaseMs });
|
|
8461
|
+
try {
|
|
8462
|
+
await this.capacity(s);
|
|
8463
|
+
await this.settle(s);
|
|
8464
|
+
this.capture(s, true);
|
|
8465
|
+
} catch (error) {
|
|
8466
|
+
if (previous) s.attachments.set(clientId, previous);
|
|
8467
|
+
else this.release(s, clientId);
|
|
8468
|
+
try {
|
|
8469
|
+
await this.capacity(s);
|
|
8470
|
+
} catch (rollback) {
|
|
8471
|
+
this.failed(s, rollback);
|
|
8472
|
+
}
|
|
8473
|
+
throw error;
|
|
8290
8474
|
}
|
|
8291
|
-
|
|
8475
|
+
this.scheduleLease(s);
|
|
8476
|
+
return s.frames.poll(0);
|
|
8292
8477
|
}
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
this.
|
|
8319
|
-
this.
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8478
|
+
const attachment = s.attachments.get(clientId);
|
|
8479
|
+
if (!attachment) return fail("pty_attachment_expired", "Terminal attachment expired; attach again");
|
|
8480
|
+
if (op === "poll") {
|
|
8481
|
+
keys2(params, [...ref, "after"]);
|
|
8482
|
+
const after = integer2(params, "after", 0, Number.MAX_SAFE_INTEGER);
|
|
8483
|
+
attachment.expires = this.now() + TERMINAL_GRID_LIMITS.leaseMs;
|
|
8484
|
+
this.scheduleLease(s);
|
|
8485
|
+
await this.captureDue(s);
|
|
8486
|
+
return s.frames.poll(after);
|
|
8487
|
+
}
|
|
8488
|
+
if (op === "resize") {
|
|
8489
|
+
keys2(params, [...ref, "cols", "rows"]);
|
|
8490
|
+
const cols = integer2(params, "cols", TERMINAL_GRID_LIMITS.minCols, TERMINAL_GRID_LIMITS.maxCols);
|
|
8491
|
+
const rows = integer2(params, "rows", TERMINAL_GRID_LIMITS.minRows, TERMINAL_GRID_LIMITS.maxRows);
|
|
8492
|
+
const previous = { ...attachment };
|
|
8493
|
+
attachment.cols = cols;
|
|
8494
|
+
attachment.rows = rows;
|
|
8495
|
+
try {
|
|
8496
|
+
await this.capacity(s);
|
|
8497
|
+
} catch (error) {
|
|
8498
|
+
Object.assign(attachment, previous);
|
|
8499
|
+
throw error;
|
|
8500
|
+
}
|
|
8501
|
+
} else if (op === "input") {
|
|
8502
|
+
const event = input(params, ref);
|
|
8503
|
+
await this.settle(s);
|
|
8504
|
+
this.assertRunning(s);
|
|
8505
|
+
if (event.kind === "pointer" || event.kind === "button") this.coordinates(s, event);
|
|
8506
|
+
const data = s.input.input(event, clientId, this.inputContext(s));
|
|
8507
|
+
if (data) s.pty.write(data);
|
|
8508
|
+
} else if (op === "scroll") {
|
|
8509
|
+
keys2(params, [...ref, "lines", "x", "y", "modifiers", "geometry"]);
|
|
8510
|
+
const gesture = { lines: integer2(params, "lines", -Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER), ...position(params), modifiers: integer2(params, "modifiers", 0, 15) };
|
|
8511
|
+
await this.settle(s);
|
|
8512
|
+
this.coordinates(s, gesture);
|
|
8513
|
+
const data = s.input.scroll(gesture, clientId, this.inputContext(s));
|
|
8514
|
+
if (data) {
|
|
8515
|
+
this.assertRunning(s);
|
|
8516
|
+
s.pty.write(data);
|
|
8517
|
+
} else if (data === void 0 && s.screen.state().buffer === "normal") {
|
|
8518
|
+
s.screen.scroll(gesture.lines);
|
|
8519
|
+
this.dirty(s);
|
|
8520
|
+
}
|
|
8521
|
+
} else return bad("Unsupported terminal operation");
|
|
8522
|
+
attachment.expires = this.now() + TERMINAL_GRID_LIMITS.leaseMs;
|
|
8523
|
+
this.scheduleLease(s);
|
|
8524
|
+
return ok;
|
|
8525
|
+
});
|
|
8526
|
+
}
|
|
8527
|
+
activity() {
|
|
8528
|
+
const metrics = { ptyOpen: 0, ptyActive: 0, ptyExited: 0 };
|
|
8529
|
+
const items = [...this.sessions.values()].map((s) => {
|
|
8530
|
+
if (s.value.exited) {
|
|
8531
|
+
metrics.ptyExited++;
|
|
8532
|
+
return { type: "pty", id: s.value.id, label: s.shell.slice(0, 64), state: "exited", sinceEpochMs: s.exitedAt };
|
|
8533
|
+
}
|
|
8534
|
+
metrics.ptyOpen++;
|
|
8535
|
+
let foreground = "";
|
|
8536
|
+
try {
|
|
8537
|
+
foreground = basename(s.pty.process);
|
|
8538
|
+
} catch {
|
|
8539
|
+
}
|
|
8540
|
+
const active = foreground !== "" && !s.shellNames.has(foreground);
|
|
8541
|
+
const label = (active ? foreground : s.shell).slice(0, 64);
|
|
8542
|
+
const state = active ? "active" : "idle";
|
|
8543
|
+
if (active) metrics.ptyActive++;
|
|
8544
|
+
if (s.observed.label !== label || s.observed.state !== state) s.observed = { label, state, since: this.now() };
|
|
8545
|
+
return { type: "pty", id: s.value.id, label, state, sinceEpochMs: s.observed.since };
|
|
8546
|
+
});
|
|
8547
|
+
return { metrics, items };
|
|
8548
|
+
}
|
|
8549
|
+
async dispose() {
|
|
8550
|
+
if (this.disposed) return;
|
|
8551
|
+
this.disposed = true;
|
|
8552
|
+
await Promise.all([...this.sessions.values()].map((s) => this.ordered(s, () => this.close(s))));
|
|
8553
|
+
}
|
|
8554
|
+
descriptor(s) {
|
|
8555
|
+
return { ...s.value, ...s.metadata?.read() };
|
|
8556
|
+
}
|
|
8557
|
+
available() {
|
|
8558
|
+
if (this.disposed) fail("pty_unavailable", "Terminal host is disposed");
|
|
8559
|
+
if (!this.module) fail("pty_unavailable", this.unavailable ?? "Terminal native dependency unavailable");
|
|
8560
|
+
}
|
|
8561
|
+
checkLimit() {
|
|
8562
|
+
if (this.sessions.size >= TERMINAL_GRID_LIMITS.maxSessions) fail("pty_limit", "Terminal session limit exceeded");
|
|
8563
|
+
}
|
|
8564
|
+
scheduleShellName(s, attempt = 0) {
|
|
8565
|
+
const live = () => !s.closed && !s.value.exited && !this.disposed;
|
|
8566
|
+
if (!live()) return;
|
|
8567
|
+
s.shellNameTimer = this.scheduler.schedule(() => {
|
|
8568
|
+
s.shellNameTimer = void 0;
|
|
8569
|
+
if (!live()) return;
|
|
8570
|
+
const retry = () => {
|
|
8571
|
+
if (attempt < 2) this.scheduleShellName(s, attempt + 1);
|
|
8572
|
+
};
|
|
8573
|
+
void Promise.resolve().then(() => live() ? (this.options.shellProcessName ?? defaultShellProcessName)(s.pty.pid) : null).then((name) => {
|
|
8574
|
+
if (!live()) return;
|
|
8575
|
+
const shell = name && basename(name);
|
|
8576
|
+
if (shell && shell !== "spawn-helper") s.shellNames.add(shell);
|
|
8577
|
+
else retry();
|
|
8578
|
+
}, retry);
|
|
8579
|
+
}, this.options.shellNameDelayMs ?? 250);
|
|
8580
|
+
}
|
|
8581
|
+
ordered(s, action) {
|
|
8582
|
+
const operation = s.queue.then(action);
|
|
8583
|
+
s.queue = operation.catch(() => {
|
|
8584
|
+
});
|
|
8585
|
+
return operation;
|
|
8586
|
+
}
|
|
8587
|
+
async settle(s) {
|
|
8588
|
+
for (; ; ) {
|
|
8589
|
+
const rendered = s.rendered;
|
|
8590
|
+
await rendered;
|
|
8591
|
+
if (rendered === s.rendered) break;
|
|
8327
8592
|
}
|
|
8593
|
+
if (s.failure) throw s.failure;
|
|
8328
8594
|
}
|
|
8329
|
-
|
|
8330
|
-
|
|
8595
|
+
output(s, data) {
|
|
8596
|
+
if (s.closed || !data || s.failure) return;
|
|
8597
|
+
if (!s.shellNameStarted) {
|
|
8598
|
+
s.shellNameStarted = true;
|
|
8599
|
+
this.scheduleShellName(s);
|
|
8600
|
+
}
|
|
8601
|
+
const bytes = Buffer.byteLength(data);
|
|
8602
|
+
s.pendingBytes += bytes;
|
|
8331
8603
|
try {
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8604
|
+
if (s.pendingBytes > 256 * 1024) s.pty.pause();
|
|
8605
|
+
s.metadata?.onData?.(data);
|
|
8606
|
+
s.rendered = s.screen.write(data);
|
|
8607
|
+
void s.rendered.then(() => {
|
|
8608
|
+
s.pendingBytes -= bytes;
|
|
8609
|
+
try {
|
|
8610
|
+
if (!s.closed && !s.value.exited && s.pendingBytes < 64 * 1024) s.pty.resume();
|
|
8611
|
+
} catch (error) {
|
|
8612
|
+
this.failed(s, error);
|
|
8613
|
+
}
|
|
8614
|
+
this.dirty(s);
|
|
8615
|
+
}, (error) => this.failed(s, error));
|
|
8616
|
+
this.dirty(s);
|
|
8617
|
+
} catch (error) {
|
|
8618
|
+
this.failed(s, error);
|
|
8335
8619
|
}
|
|
8336
8620
|
}
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
if (s.closed || s.exited) return;
|
|
8343
|
-
try {
|
|
8344
|
-
const name = await (this.options.shellProcessName ?? defaultShellProcessName)(s.pty.pid);
|
|
8345
|
-
if (name) s.shellNames.add(processBasename(name));
|
|
8346
|
-
} catch {
|
|
8621
|
+
failed(s, error) {
|
|
8622
|
+
if (!s.closed) {
|
|
8623
|
+
s.failure = error;
|
|
8624
|
+
s.captureTimer?.dispose();
|
|
8625
|
+
s.captureTimer = void 0;
|
|
8347
8626
|
}
|
|
8348
8627
|
}
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8628
|
+
dirty(s) {
|
|
8629
|
+
if (s.closed || s.failure) return;
|
|
8630
|
+
s.dirty = true;
|
|
8631
|
+
if (!s.captureTimer) s.captureTimer = this.scheduler.schedule(() => {
|
|
8632
|
+
s.captureTimer = void 0;
|
|
8633
|
+
void this.ordered(s, async () => {
|
|
8634
|
+
if (s.closed) return;
|
|
8635
|
+
await this.settle(s);
|
|
8636
|
+
this.capture(s);
|
|
8637
|
+
}).catch((error) => {
|
|
8638
|
+
if (!(error instanceof KeeperMethodError && error.code === "pty_snapshot_too_large")) this.failed(s, error);
|
|
8639
|
+
});
|
|
8640
|
+
}, Math.max(0, 50 - (this.now() - s.capturedAt)));
|
|
8641
|
+
}
|
|
8642
|
+
async captureDue(s) {
|
|
8643
|
+
if (s.dirty && this.now() - s.capturedAt < 50) {
|
|
8644
|
+
s.captureTimer?.dispose();
|
|
8645
|
+
s.captureTimer = void 0;
|
|
8646
|
+
await new Promise((resolve) => this.scheduler.schedule(resolve, 50 - (this.now() - s.capturedAt)));
|
|
8647
|
+
}
|
|
8648
|
+
await this.settle(s);
|
|
8649
|
+
this.capture(s, true);
|
|
8650
|
+
}
|
|
8651
|
+
capture(s, force = false) {
|
|
8652
|
+
if (!s.dirty || !force && this.now() - s.capturedAt < 50) return;
|
|
8653
|
+
s.frames.publish(s.screen.capture(), this.descriptor(s), s.geometry);
|
|
8654
|
+
s.dirty = false;
|
|
8655
|
+
s.capturedAt = this.now();
|
|
8656
|
+
s.captureTimer?.dispose();
|
|
8657
|
+
s.captureTimer = void 0;
|
|
8658
|
+
}
|
|
8659
|
+
async capacity(s) {
|
|
8660
|
+
if (!s.attachments.size) return;
|
|
8661
|
+
const cols = Math.min(...[...s.attachments.values()].map((a) => a.cols));
|
|
8662
|
+
const rows = Math.min(...[...s.attachments.values()].map((a) => a.rows));
|
|
8663
|
+
if (cols === s.value.cols && rows === s.value.rows) return;
|
|
8664
|
+
await this.settle(s);
|
|
8665
|
+
if (!s.value.exited) s.pty.resize(cols, rows);
|
|
8666
|
+
try {
|
|
8667
|
+
await s.screen.resize(cols, rows);
|
|
8668
|
+
await this.settle(s);
|
|
8669
|
+
} catch (error) {
|
|
8670
|
+
this.failed(s, error);
|
|
8671
|
+
try {
|
|
8672
|
+
if (!s.value.exited) s.pty.resize(s.value.cols, s.value.rows);
|
|
8673
|
+
} catch (rollback) {
|
|
8674
|
+
this.failed(s, rollback);
|
|
8365
8675
|
}
|
|
8366
|
-
|
|
8367
|
-
const fg = this.foreground(s);
|
|
8368
|
-
const busy = fg !== "" && !s.shellNames.has(fg);
|
|
8369
|
-
const label = (busy ? fg : s.shellName).slice(0, PTY_LABEL_CHARS);
|
|
8370
|
-
const state = busy ? "active" : "idle";
|
|
8371
|
-
if (s.observed.label !== label || s.observed.state !== state) s.observed = { label, state, since: now };
|
|
8372
|
-
if (busy) active += 1;
|
|
8373
|
-
items.push({ type: "pty", id: s.id, label, state, sinceEpochMs: s.observed.since });
|
|
8676
|
+
throw error;
|
|
8374
8677
|
}
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8678
|
+
s.value.cols = cols;
|
|
8679
|
+
s.value.rows = rows;
|
|
8680
|
+
s.geometry++;
|
|
8681
|
+
this.dirty(s);
|
|
8682
|
+
}
|
|
8683
|
+
inputContext(s) {
|
|
8684
|
+
return { cols: s.value.cols, rows: s.value.rows, geometry: s.geometry, modes: s.screen.state().modes };
|
|
8685
|
+
}
|
|
8686
|
+
coordinates(s, event) {
|
|
8687
|
+
if (event.geometry !== s.geometry) fail("pty_geometry_mismatch", "Terminal geometry changed");
|
|
8688
|
+
if (event.x >= s.value.cols || event.y >= s.value.rows) bad("Terminal coordinates outside geometry");
|
|
8689
|
+
}
|
|
8690
|
+
assertRunning(s) {
|
|
8691
|
+
if (s.value.exited) fail("pty_exited", "Terminal has exited");
|
|
8692
|
+
}
|
|
8693
|
+
release(s, clientId) {
|
|
8694
|
+
if (s.attachments.delete(clientId)) s.input.release(clientId);
|
|
8695
|
+
this.scheduleLease(s);
|
|
8696
|
+
}
|
|
8697
|
+
async expire(s) {
|
|
8698
|
+
let changed = false;
|
|
8699
|
+
for (const [id, attachment] of s.attachments) if (attachment.expires <= this.now()) {
|
|
8700
|
+
this.release(s, id);
|
|
8701
|
+
changed = true;
|
|
8702
|
+
}
|
|
8703
|
+
if (changed) await this.capacity(s);
|
|
8704
|
+
}
|
|
8705
|
+
scheduleLease(s) {
|
|
8706
|
+
s.leaseTimer?.dispose();
|
|
8707
|
+
s.leaseTimer = void 0;
|
|
8708
|
+
if (s.closed || this.disposed || !s.attachments.size) return;
|
|
8709
|
+
const expires = Math.min(...[...s.attachments.values()].map((attachment) => attachment.expires));
|
|
8710
|
+
s.leaseTimer = this.scheduler.schedule(() => {
|
|
8711
|
+
s.leaseTimer = void 0;
|
|
8712
|
+
void this.ordered(s, () => this.expire(s)).catch((error) => this.failed(s, error)).finally(() => this.scheduleLease(s));
|
|
8713
|
+
}, Math.max(0, expires - this.now()));
|
|
8714
|
+
}
|
|
8715
|
+
async close(s) {
|
|
8716
|
+
if (s.closed) return;
|
|
8717
|
+
s.closed = true;
|
|
8718
|
+
if (this.sessions.get(s.value.id) === s) this.sessions.delete(s.value.id);
|
|
8719
|
+
s.shellNameTimer?.dispose();
|
|
8720
|
+
s.shellNameTimer = void 0;
|
|
8721
|
+
s.captureTimer?.dispose();
|
|
8722
|
+
s.captureTimer = void 0;
|
|
8723
|
+
s.leaseTimer?.dispose();
|
|
8724
|
+
s.leaseTimer = void 0;
|
|
8725
|
+
for (const listener of s.listeners) listener.dispose();
|
|
8726
|
+
for (const id of [...s.attachments.keys()]) this.release(s, id);
|
|
8727
|
+
s.input.dispose();
|
|
8728
|
+
s.metadata?.dispose?.();
|
|
8729
|
+
try {
|
|
8730
|
+
if (!s.value.exited) s.pty.kill();
|
|
8731
|
+
} finally {
|
|
8732
|
+
s.screen.dispose();
|
|
8733
|
+
await s.rendered.catch(() => {
|
|
8734
|
+
});
|
|
8384
8735
|
}
|
|
8385
|
-
this.sessions.clear();
|
|
8386
8736
|
}
|
|
8387
8737
|
};
|
|
8738
|
+
function disposable(value) {
|
|
8739
|
+
return value && typeof value.dispose === "function" ? value : { dispose: () => {
|
|
8740
|
+
} };
|
|
8741
|
+
}
|
|
8742
|
+
function request(params) {
|
|
8743
|
+
if (Buffer.byteLength(JSON.stringify(params)) > TERMINAL_GRID_LIMITS.maxRequestBytes) bad("Terminal request exceeds limit");
|
|
8744
|
+
}
|
|
8745
|
+
function keys2(params, allowed) {
|
|
8746
|
+
if (Object.keys(params).some((key) => !allowed.includes(key))) bad("Unexpected terminal parameter");
|
|
8747
|
+
}
|
|
8748
|
+
function identifier(params, name) {
|
|
8749
|
+
const value = params[name];
|
|
8750
|
+
if (typeof value !== "string" || !/^[A-Za-z0-9_.:-]{1,128}$/.test(value)) return bad(`Invalid ${name}`);
|
|
8751
|
+
return value;
|
|
8752
|
+
}
|
|
8753
|
+
function integer2(params, name, min, max) {
|
|
8754
|
+
const value = params[name];
|
|
8755
|
+
if (!Number.isSafeInteger(value) || value < min || value > max) return bad(`Invalid ${name}`);
|
|
8756
|
+
return value;
|
|
8757
|
+
}
|
|
8758
|
+
function position(params) {
|
|
8759
|
+
return { x: integer2(params, "x", 0, TERMINAL_GRID_LIMITS.maxCols - 1), y: integer2(params, "y", 0, TERMINAL_GRID_LIMITS.maxRows - 1), geometry: integer2(params, "geometry", 1, Number.MAX_SAFE_INTEGER) };
|
|
8760
|
+
}
|
|
8761
|
+
function input(params, ref) {
|
|
8762
|
+
switch (params.kind) {
|
|
8763
|
+
case "text":
|
|
8764
|
+
case "paste":
|
|
8765
|
+
keys2(params, [...ref, "kind", "text"]);
|
|
8766
|
+
if (typeof params.text !== "string" || Buffer.byteLength(params.text) > TERMINAL_GRID_LIMITS.maxInputBytes) return bad("Terminal input exceeds limit");
|
|
8767
|
+
return { kind: params.kind, text: params.text };
|
|
8768
|
+
case "key":
|
|
8769
|
+
keys2(params, [...ref, "kind", "usage", "down", "modifiers"]);
|
|
8770
|
+
if (typeof params.down !== "boolean") return bad("Invalid down");
|
|
8771
|
+
return { kind: "key", usage: integer2(params, "usage", 0, 65535), down: params.down, modifiers: integer2(params, "modifiers", 0, 15) };
|
|
8772
|
+
case "pointer":
|
|
8773
|
+
case "button": {
|
|
8774
|
+
keys2(params, [...ref, "kind", "x", "y", "geometry", "modifiers", ...params.kind === "button" ? ["button", "down"] : []]);
|
|
8775
|
+
const point = { ...position(params), modifiers: integer2(params, "modifiers", 0, 15) };
|
|
8776
|
+
if (params.kind === "pointer") return { kind: "pointer", ...point };
|
|
8777
|
+
if (typeof params.down !== "boolean") return bad("Invalid down");
|
|
8778
|
+
return { kind: "button", ...point, button: integer2(params, "button", 0, 2), down: params.down };
|
|
8779
|
+
}
|
|
8780
|
+
case "release":
|
|
8781
|
+
keys2(params, [...ref, "kind"]);
|
|
8782
|
+
return { kind: "release" };
|
|
8783
|
+
default:
|
|
8784
|
+
return bad("Invalid terminal input kind");
|
|
8785
|
+
}
|
|
8786
|
+
}
|
|
8787
|
+
function defaultShellProcessName(pid) {
|
|
8788
|
+
if (process.platform !== "darwin") return Promise.resolve(null);
|
|
8789
|
+
return new Promise((resolve) => {
|
|
8790
|
+
execFile4("ps", ["-o", "ucomm=", "-p", String(pid)], { timeout: 1e3 }, (error, stdout) => resolve(error ? null : stdout.trim() || null));
|
|
8791
|
+
});
|
|
8792
|
+
}
|
|
8388
8793
|
|
|
8389
8794
|
// src/workstation/keepers/terminal/keeper.ts
|
|
8390
8795
|
async function launchOf(p) {
|
|
@@ -8397,18 +8802,29 @@ async function launchOf(p) {
|
|
|
8397
8802
|
if (!executable) badRequest("Terminal shell is not an executable file");
|
|
8398
8803
|
return { cwd, shell, env };
|
|
8399
8804
|
}
|
|
8400
|
-
var KEEPER_CREATE_KEYS = [
|
|
8805
|
+
var KEEPER_CREATE_KEYS = ["id", "cwd", "shell", "env", "registrationId"];
|
|
8401
8806
|
function createTerminalKeeper(options = {}) {
|
|
8402
|
-
|
|
8807
|
+
let available = false;
|
|
8808
|
+
const sessions = new NativePtySessions({ ...options, loadPty: () => {
|
|
8809
|
+
const module = (options.loadPty ?? (() => createRequire2(import.meta.url)("node-pty")))();
|
|
8810
|
+
available = true;
|
|
8811
|
+
return module;
|
|
8812
|
+
} });
|
|
8403
8813
|
const exec = options.exec;
|
|
8404
8814
|
return {
|
|
8405
8815
|
sessions,
|
|
8406
8816
|
exec,
|
|
8407
|
-
capabilities: [...
|
|
8817
|
+
capabilities: [...available ? [PTY_CAPABILITY] : [], ...exec ? [EXEC_CAPABILITY] : []],
|
|
8408
8818
|
install(server) {
|
|
8409
|
-
server.register("pty.create", (params) =>
|
|
8410
|
-
|
|
8411
|
-
|
|
8819
|
+
server.register("pty.create", (params) => {
|
|
8820
|
+
if (Object.keys(params).some((key) => !KEEPER_CREATE_KEYS.includes(key))) badRequest("Unexpected tool parameter");
|
|
8821
|
+
return sessions.create({ id: params.id, ...params.cwd !== void 0 ? { cwd: params.cwd } : {}, ...params.registrationId !== void 0 ? { registrationId: params.registrationId } : {} }, () => launchOf(params));
|
|
8822
|
+
}, { startsWork: true });
|
|
8823
|
+
server.register("pty.list", (params) => {
|
|
8824
|
+
if (Object.keys(params).length) badRequest("Unexpected tool parameter");
|
|
8825
|
+
return sessions.list();
|
|
8826
|
+
});
|
|
8827
|
+
for (const op of NATIVE_PTY_OPERATIONS)
|
|
8412
8828
|
server.register(`pty.${op}`, (params) => sessions.operate(op, params));
|
|
8413
8829
|
server.addActivitySampler(() => sessions.activity());
|
|
8414
8830
|
if (!exec) return;
|
|
@@ -8438,9 +8854,9 @@ function createTerminalKeeper(options = {}) {
|
|
|
8438
8854
|
}
|
|
8439
8855
|
|
|
8440
8856
|
// src/workstation/keepers/terminal/main.ts
|
|
8441
|
-
var protocolVersion =
|
|
8857
|
+
var protocolVersion = 2;
|
|
8442
8858
|
function loadBundledPty(bundleDir) {
|
|
8443
|
-
const load =
|
|
8859
|
+
const load = createRequire3(import.meta.url);
|
|
8444
8860
|
const resolved = realpathSync(load.resolve("node-pty"));
|
|
8445
8861
|
if (!resolved.startsWith(realpathSync(bundleDir) + sep)) throw new Error(`node-pty resolves outside the keeper bundle (${resolved})`);
|
|
8446
8862
|
return load("node-pty");
|
|
@@ -8449,7 +8865,7 @@ await runKeeperMain({
|
|
|
8449
8865
|
kind: "terminal",
|
|
8450
8866
|
protocolVersion,
|
|
8451
8867
|
create: async (config, { log }) => {
|
|
8452
|
-
const exec = new ExecHost({ root:
|
|
8868
|
+
const exec = new ExecHost({ root: path6.join(config.dataDir, "exec"), owner: { pid: process.pid, gen: config.gen, bundleDir: config.bundleDir }, log });
|
|
8453
8869
|
await exec.open();
|
|
8454
8870
|
return createTerminalKeeper({
|
|
8455
8871
|
exec,
|