@vendian/cli 0.0.29 → 0.0.31
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/cli-wrapper.mjs +127 -67
- package/package.json +1 -1
package/cli-wrapper.mjs
CHANGED
|
@@ -1107,7 +1107,7 @@ import path8 from "node:path";
|
|
|
1107
1107
|
import readlinePromises from "node:readline/promises";
|
|
1108
1108
|
|
|
1109
1109
|
// src/version.js
|
|
1110
|
-
var CLI_VERSION = true ? "0.0.
|
|
1110
|
+
var CLI_VERSION = true ? "0.0.31" : process.env.npm_package_version || "0.0.0-dev";
|
|
1111
1111
|
|
|
1112
1112
|
// src/npm-update.js
|
|
1113
1113
|
var NPM_CHECK_INTERVAL_MS = 30 * 60 * 1e3;
|
|
@@ -2398,6 +2398,7 @@ async function loadTerm() {
|
|
|
2398
2398
|
term = tk.default.terminal;
|
|
2399
2399
|
}
|
|
2400
2400
|
var HEADER_ROWS_BASE = 7;
|
|
2401
|
+
var HEADER_ROWS_SERVE = 8;
|
|
2401
2402
|
var SERVE_CONTENT_ROW = 10;
|
|
2402
2403
|
function clampListIndex(index, count) {
|
|
2403
2404
|
if (!Number.isFinite(count) || count <= 0) return 0;
|
|
@@ -2988,6 +2989,7 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
2988
2989
|
let child = null;
|
|
2989
2990
|
let startupError = "";
|
|
2990
2991
|
let overlayActive = false;
|
|
2992
|
+
let overlayRedraw = null;
|
|
2991
2993
|
let ctrlCArmed = false;
|
|
2992
2994
|
let ctrlCArmTimer = null;
|
|
2993
2995
|
let dashboardClosed = false;
|
|
@@ -3005,7 +3007,8 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3005
3007
|
const status = friendlyStatus(rt.status);
|
|
3006
3008
|
const path_ = agent.relativePath || ".";
|
|
3007
3009
|
const runst = state.agentRunState[path_];
|
|
3008
|
-
const
|
|
3010
|
+
const rawErr = runst?.errorMessage || (rt.status === "error" ? "Something went wrong" : null);
|
|
3011
|
+
const errMsg2 = rawErr ? typeof rawErr === "string" ? rawErr : rawErr.message || JSON.stringify(rawErr) : null;
|
|
3009
3012
|
return { num: i + 1, name, status, errMsg: errMsg2, path: path_ };
|
|
3010
3013
|
});
|
|
3011
3014
|
}
|
|
@@ -3024,55 +3027,62 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3024
3027
|
}
|
|
3025
3028
|
function redraw() {
|
|
3026
3029
|
if (dashboardClosed || overlayActive) return;
|
|
3030
|
+
const W = term.width || 80;
|
|
3031
|
+
const H = term.height || 24;
|
|
3027
3032
|
const agents = agentDisplayList();
|
|
3028
3033
|
const activity = recentActivityLines();
|
|
3029
3034
|
const diagnostics = daemonDebugLines();
|
|
3030
3035
|
const viewport = computeServeDashboardViewport({
|
|
3031
|
-
termHeight:
|
|
3036
|
+
termHeight: H,
|
|
3032
3037
|
agentCount: agents.length,
|
|
3033
3038
|
selectedIdx,
|
|
3034
3039
|
activityCount: activity.length,
|
|
3035
3040
|
diagnosticsCount: diagnostics.length
|
|
3036
3041
|
});
|
|
3037
3042
|
selectedIdx = viewport.selectedIdx;
|
|
3038
|
-
|
|
3039
|
-
term.moveTo(1, SERVE_CONTENT_ROW);
|
|
3040
|
-
term.eraseDisplayBelow();
|
|
3043
|
+
term.clear();
|
|
3041
3044
|
agentRowMap.clear();
|
|
3045
|
+
drawHeader({ env, platform, serveState: state });
|
|
3046
|
+
term("\n");
|
|
3047
|
+
let currentRow = HEADER_ROWS_SERVE + 2;
|
|
3042
3048
|
if (startupError) {
|
|
3043
|
-
term.red(` ${fig.cross} ${clip(startupError,
|
|
3049
|
+
term.red(` ${fig.cross} ${clip(startupError, W - 6)}
|
|
3044
3050
|
`);
|
|
3045
3051
|
} else if (stopRequested) {
|
|
3046
|
-
term.yellow(` ${fig.warning} ${clip(state.activity || "Stopping your agents\u2026",
|
|
3052
|
+
term.yellow(` ${fig.warning} ${clip(state.activity || "Stopping your agents\u2026", W - 6)}
|
|
3047
3053
|
`);
|
|
3048
3054
|
} else if (state.stopped) {
|
|
3049
3055
|
term.yellow(` ${fig.warning} Your agents have stopped.
|
|
3050
3056
|
`);
|
|
3051
3057
|
} else if (state.connected) {
|
|
3052
3058
|
term.green(` ${fig.dot} `);
|
|
3053
|
-
term.gray(`${clip(state.activity || "Your agents are running",
|
|
3059
|
+
term.gray(`${clip(state.activity || "Your agents are running", W - 10)}
|
|
3054
3060
|
`);
|
|
3055
3061
|
} else {
|
|
3056
3062
|
term.cyan(` ${fig.dotEmpty} `);
|
|
3057
|
-
term.gray(`${clip(state.activity || "Starting up\u2026",
|
|
3063
|
+
term.gray(`${clip(state.activity || "Starting up\u2026", W - 10)}
|
|
3058
3064
|
`);
|
|
3059
3065
|
}
|
|
3066
|
+
currentRow++;
|
|
3060
3067
|
if (agents.length > 0) {
|
|
3061
|
-
if (viewport.showBlankAfterStatus)
|
|
3068
|
+
if (viewport.showBlankAfterStatus) {
|
|
3069
|
+
term("\n");
|
|
3070
|
+
currentRow++;
|
|
3071
|
+
}
|
|
3062
3072
|
term.bold.gray(" Your agents:\n");
|
|
3063
|
-
|
|
3073
|
+
currentRow++;
|
|
3064
3074
|
const visibleAgents = agents.slice(
|
|
3065
3075
|
viewport.agentWindowStart,
|
|
3066
3076
|
viewport.agentWindowStart + viewport.visibleAgentCount
|
|
3067
3077
|
);
|
|
3068
3078
|
for (const ag of visibleAgents) {
|
|
3069
3079
|
const isSelected = ag.num - 1 === selectedIdx;
|
|
3070
|
-
agentRowMap.set(
|
|
3080
|
+
agentRowMap.set(currentRow, ag.num - 1);
|
|
3071
3081
|
const numStr = String(ag.num).padStart(2);
|
|
3072
3082
|
const nameStr = clip(ag.name, 28).padEnd(28);
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
else {
|
|
3083
|
+
if (isSelected) {
|
|
3084
|
+
term.bgCyan.black.bold(` ${numStr} ${ag.status.icon} ${nameStr} ${ag.status.text}`);
|
|
3085
|
+
} else {
|
|
3076
3086
|
term(` ${numStr} `);
|
|
3077
3087
|
switch (ag.status.color) {
|
|
3078
3088
|
case "green":
|
|
@@ -3115,11 +3125,11 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3115
3125
|
}
|
|
3116
3126
|
}
|
|
3117
3127
|
term("\n");
|
|
3118
|
-
|
|
3128
|
+
currentRow++;
|
|
3119
3129
|
if (viewport.showInlineErrors && isSelected && ag.errMsg) {
|
|
3120
|
-
term.red(` \u2514\u2500 ${clip(ag.errMsg,
|
|
3130
|
+
term.red(` \u2514\u2500 ${clip(ag.errMsg, W - 14)}
|
|
3121
3131
|
`);
|
|
3122
|
-
|
|
3132
|
+
currentRow++;
|
|
3123
3133
|
}
|
|
3124
3134
|
}
|
|
3125
3135
|
if (viewport.showAgentRange) {
|
|
@@ -3127,24 +3137,31 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3127
3137
|
const last = viewport.agentWindowStart + visibleAgents.length;
|
|
3128
3138
|
term.gray(` Showing agents ${first}\u2013${last} of ${agents.length}
|
|
3129
3139
|
`);
|
|
3140
|
+
currentRow++;
|
|
3130
3141
|
}
|
|
3131
3142
|
if (viewport.showAgentHint) {
|
|
3132
3143
|
term.gray(` Click an agent or use \u2191\u2193 + Enter to see its activity log
|
|
3133
3144
|
`);
|
|
3145
|
+
currentRow++;
|
|
3134
3146
|
}
|
|
3135
3147
|
} else {
|
|
3136
|
-
if (viewport.showBlankAfterStatus)
|
|
3148
|
+
if (viewport.showBlankAfterStatus) {
|
|
3149
|
+
term("\n");
|
|
3150
|
+
currentRow++;
|
|
3151
|
+
}
|
|
3137
3152
|
term.gray(" Looking for your agents\u2026\n");
|
|
3153
|
+
currentRow++;
|
|
3138
3154
|
}
|
|
3139
3155
|
if (viewport.showActivityHeader) {
|
|
3140
3156
|
const visibleActivity = activity.slice(-viewport.visibleActivityCount);
|
|
3141
|
-
const divW = Math.min(
|
|
3157
|
+
const divW = Math.min(W - 4, 60);
|
|
3142
3158
|
term.gray(` ${"\u2500".repeat(3)} Recent activity ${"\u2500".repeat(Math.max(0, divW - 18))}
|
|
3143
3159
|
`);
|
|
3160
|
+
currentRow++;
|
|
3144
3161
|
for (const e of visibleActivity) {
|
|
3145
3162
|
const t = formatLogTime(e.timestamp);
|
|
3146
3163
|
const name = clip(e._agentName || "Agent", 20);
|
|
3147
|
-
const msg = clip(friendlyActivityLine(e),
|
|
3164
|
+
const msg = clip(friendlyActivityLine(e), W - 32);
|
|
3148
3165
|
if (e.level === "error" || e.eventType === "completion" && e.success === false) {
|
|
3149
3166
|
term.gray(` ${t} `);
|
|
3150
3167
|
term.red(`${name} \u2014 ${msg}
|
|
@@ -3161,31 +3178,32 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3161
3178
|
term.gray(` ${t} ${name} \u2014 ${msg}
|
|
3162
3179
|
`);
|
|
3163
3180
|
}
|
|
3181
|
+
currentRow++;
|
|
3164
3182
|
}
|
|
3165
3183
|
}
|
|
3166
3184
|
if (viewport.showDiagnosticsHeader) {
|
|
3167
3185
|
const visibleDiagnostics = diagnostics.slice(-viewport.visibleDiagnosticsCount);
|
|
3168
|
-
const divW = Math.min(
|
|
3186
|
+
const divW = Math.min(W - 4, 72);
|
|
3169
3187
|
term.gray(` ${"\u2500".repeat(3)} Daemon diagnostics ${"\u2500".repeat(Math.max(0, divW - 23))}
|
|
3170
3188
|
`);
|
|
3189
|
+
currentRow++;
|
|
3171
3190
|
for (const entry of visibleDiagnostics) {
|
|
3172
3191
|
const t = formatLogTime(entry.timestamp);
|
|
3173
|
-
const type = clip(entry.eventType || "event",
|
|
3174
|
-
const msg = clip(entry.message || "",
|
|
3192
|
+
const type = clip(entry.eventType || "event", 22).padEnd(22);
|
|
3193
|
+
const msg = clip(entry.message || "", W - 36);
|
|
3175
3194
|
term.gray(` ${t} `);
|
|
3176
|
-
if (entry.level === "error") {
|
|
3177
|
-
term.red(`${type} ${msg}
|
|
3195
|
+
if (entry.level === "error") term.red(`${type} ${msg}
|
|
3178
3196
|
`);
|
|
3179
|
-
|
|
3180
|
-
term.yellow(`${type} ${msg}
|
|
3197
|
+
else if (entry.level === "warn") term.yellow(`${type} ${msg}
|
|
3181
3198
|
`);
|
|
3182
|
-
|
|
3183
|
-
term.gray(`${type} ${msg}
|
|
3199
|
+
else term.gray(`${type} ${msg}
|
|
3184
3200
|
`);
|
|
3185
|
-
|
|
3201
|
+
currentRow++;
|
|
3186
3202
|
}
|
|
3187
3203
|
}
|
|
3188
|
-
|
|
3204
|
+
const footerRow = Math.max(currentRow + 1, H - 1);
|
|
3205
|
+
if (footerRow < H) term.moveTo(1, footerRow);
|
|
3206
|
+
else term("\n");
|
|
3189
3207
|
if (ctrlCArmed) {
|
|
3190
3208
|
term.yellow.bold(" Press Ctrl+C again to exit.\n");
|
|
3191
3209
|
} else if (stopRequested) {
|
|
@@ -3202,7 +3220,7 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3202
3220
|
}
|
|
3203
3221
|
term.clear();
|
|
3204
3222
|
drawHeader({ env, platform, serveState: state });
|
|
3205
|
-
term
|
|
3223
|
+
term("\n");
|
|
3206
3224
|
term.cyan(` ${fig.dotEmpty} Getting your agents ready\u2026
|
|
3207
3225
|
`);
|
|
3208
3226
|
try {
|
|
@@ -3233,12 +3251,14 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3233
3251
|
(updater) => {
|
|
3234
3252
|
if (dashboardClosed) return;
|
|
3235
3253
|
state = updater(state);
|
|
3236
|
-
|
|
3254
|
+
if (overlayActive && typeof overlayRedraw === "function") overlayRedraw();
|
|
3255
|
+
else redraw();
|
|
3237
3256
|
},
|
|
3238
3257
|
({ message } = {}) => {
|
|
3239
3258
|
if (dashboardClosed) return;
|
|
3240
3259
|
if (!state.stopped) state = { ...state, stopped: true, activity: message || "Stopped" };
|
|
3241
|
-
|
|
3260
|
+
if (overlayActive && typeof overlayRedraw === "function") overlayRedraw();
|
|
3261
|
+
else redraw();
|
|
3242
3262
|
},
|
|
3243
3263
|
logStore
|
|
3244
3264
|
);
|
|
@@ -3252,10 +3272,20 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3252
3272
|
const clampedIdx = clampListIndex(idx, agents.length);
|
|
3253
3273
|
if (dashboardClosed || exitPromptActive || agents.length === 0 || idx !== clampedIdx) return;
|
|
3254
3274
|
overlayActive = true;
|
|
3275
|
+
overlayRedraw = null;
|
|
3255
3276
|
const ag = agents[clampedIdx];
|
|
3256
|
-
showAgentLog({
|
|
3277
|
+
showAgentLog({
|
|
3278
|
+
agent: ag,
|
|
3279
|
+
getState: () => state,
|
|
3280
|
+
onAttachLiveUpdates: (redrawFn) => {
|
|
3281
|
+
overlayRedraw = redrawFn;
|
|
3282
|
+
},
|
|
3283
|
+
env,
|
|
3284
|
+
platform
|
|
3285
|
+
}).then(() => {
|
|
3257
3286
|
if (dashboardClosed) return;
|
|
3258
3287
|
overlayActive = false;
|
|
3288
|
+
overlayRedraw = null;
|
|
3259
3289
|
term.clear();
|
|
3260
3290
|
redraw();
|
|
3261
3291
|
});
|
|
@@ -3411,48 +3441,57 @@ async function runServeDashboard({ env, platform, agentsDir, collectionId }) {
|
|
|
3411
3441
|
}
|
|
3412
3442
|
});
|
|
3413
3443
|
}
|
|
3414
|
-
async function showAgentLog({ agent,
|
|
3415
|
-
const
|
|
3416
|
-
const
|
|
3417
|
-
const
|
|
3418
|
-
const status = friendlyStatus(runtime.status);
|
|
3444
|
+
async function showAgentLog({ agent, getState, onAttachLiveUpdates, env, platform }) {
|
|
3445
|
+
const liveState = typeof getState === "function" ? getState : () => getState;
|
|
3446
|
+
const H = term.height || 24;
|
|
3447
|
+
const visibleCount = Math.max(4, H - 14);
|
|
3419
3448
|
let scrollOffset = 0;
|
|
3420
|
-
|
|
3449
|
+
let autoScroll = true;
|
|
3450
|
+
let done = false;
|
|
3451
|
+
function currentLogs() {
|
|
3452
|
+
return agentLogEntries(liveState().agentLogs, agent.path);
|
|
3453
|
+
}
|
|
3421
3454
|
function draw() {
|
|
3455
|
+
if (done) return;
|
|
3456
|
+
const curState = liveState();
|
|
3457
|
+
const logs = currentLogs();
|
|
3458
|
+
const agentObj = curState.agents.find((a) => (a.relativePath || ".") === agent.path);
|
|
3459
|
+
const runtime = agentObj ? agentRuntimeStatus(agentObj, curState.agentRunState) : { status: "unknown", label: "offline" };
|
|
3460
|
+
const status = friendlyStatus(runtime.status);
|
|
3461
|
+
const W = term.width || 80;
|
|
3462
|
+
if (autoScroll || scrollOffset > Math.max(0, logs.length - visibleCount)) {
|
|
3463
|
+
scrollOffset = Math.max(0, logs.length - visibleCount);
|
|
3464
|
+
autoScroll = logs.length > 0;
|
|
3465
|
+
}
|
|
3422
3466
|
term.clear();
|
|
3423
|
-
drawHeader({ env, platform, serveState:
|
|
3467
|
+
drawHeader({ env, platform, serveState: curState });
|
|
3424
3468
|
term("\n");
|
|
3425
3469
|
term.bold(` ${agent.name}
|
|
3426
3470
|
`);
|
|
3427
|
-
term.gray(
|
|
3471
|
+
term.gray(" ");
|
|
3428
3472
|
switch (status.color) {
|
|
3429
3473
|
case "green":
|
|
3430
|
-
term.green(`${status.icon} ${status.text}
|
|
3431
|
-
`);
|
|
3474
|
+
term.green(`${status.icon} ${status.text}`);
|
|
3432
3475
|
break;
|
|
3433
3476
|
case "brightBlue":
|
|
3434
|
-
term.brightBlue(`${status.icon} ${status.text}
|
|
3435
|
-
`);
|
|
3477
|
+
term.brightBlue(`${status.icon} ${status.text}`);
|
|
3436
3478
|
break;
|
|
3437
3479
|
case "yellow":
|
|
3438
|
-
term.yellow(`${status.icon} ${status.text}
|
|
3439
|
-
`);
|
|
3480
|
+
term.yellow(`${status.icon} ${status.text}`);
|
|
3440
3481
|
break;
|
|
3441
3482
|
case "red":
|
|
3442
|
-
term.red(`${status.icon} ${status.text}
|
|
3443
|
-
`);
|
|
3483
|
+
term.red(`${status.icon} ${status.text}`);
|
|
3444
3484
|
break;
|
|
3445
3485
|
default:
|
|
3446
|
-
term.gray(`${status.icon} ${status.text}
|
|
3447
|
-
`);
|
|
3486
|
+
term.gray(`${status.icon} ${status.text}`);
|
|
3448
3487
|
}
|
|
3449
|
-
term("\n");
|
|
3488
|
+
term("\n\n");
|
|
3450
3489
|
if (logs.length === 0) {
|
|
3451
|
-
term.gray(" No activity
|
|
3490
|
+
term.gray(" No activity yet \u2014 logs appear here as the agent runs.\n");
|
|
3452
3491
|
} else {
|
|
3453
|
-
const eff = scrollOffset
|
|
3492
|
+
const eff = Math.min(scrollOffset, Math.max(0, logs.length - visibleCount));
|
|
3454
3493
|
const visible = logs.slice(eff, eff + visibleCount);
|
|
3455
|
-
const msgW = Math.max(
|
|
3494
|
+
const msgW = Math.max(30, W - 16);
|
|
3456
3495
|
for (const entry of visible) {
|
|
3457
3496
|
const t = formatLogTime(entry.timestamp);
|
|
3458
3497
|
const text = clip(formatAgentLogEntry(entry), msgW);
|
|
@@ -3465,6 +3504,9 @@ async function showAgentLog({ agent, state, env, platform }) {
|
|
|
3465
3504
|
`);
|
|
3466
3505
|
} else if (entry.eventType === "job_started") {
|
|
3467
3506
|
term.brightBlue(`\u25B6 ${text}
|
|
3507
|
+
`);
|
|
3508
|
+
} else if (entry.eventType === "progress") {
|
|
3509
|
+
term.cyan(`\u2192 ${text}
|
|
3468
3510
|
`);
|
|
3469
3511
|
} else {
|
|
3470
3512
|
term.gray(`\u2014 ${text}
|
|
@@ -3472,38 +3514,56 @@ async function showAgentLog({ agent, state, env, platform }) {
|
|
|
3472
3514
|
}
|
|
3473
3515
|
}
|
|
3474
3516
|
if (logs.length > visibleCount) {
|
|
3517
|
+
const eff2 = Math.min(eff, Math.max(0, logs.length - visibleCount));
|
|
3475
3518
|
term.gray(`
|
|
3476
|
-
|
|
3477
|
-
|
|
3519
|
+
${eff2 + 1}\u2013${eff2 + visible.length} of ${logs.length}`);
|
|
3520
|
+
if (autoScroll) term.cyan(" \u2193 live");
|
|
3521
|
+
term("\n");
|
|
3478
3522
|
}
|
|
3479
3523
|
}
|
|
3480
|
-
term(
|
|
3524
|
+
term.moveTo(1, Math.max(H - 1, 6));
|
|
3481
3525
|
term.gray(" ");
|
|
3482
3526
|
term.brightBlue.bold("\u2191\u2193");
|
|
3483
|
-
term.gray(" scroll ");
|
|
3484
|
-
|
|
3485
|
-
|
|
3527
|
+
term.gray("/PgUp/PgDn scroll ");
|
|
3528
|
+
if (!autoScroll) {
|
|
3529
|
+
term.brightBlue.bold("End");
|
|
3530
|
+
term.gray(" resume live ");
|
|
3531
|
+
}
|
|
3486
3532
|
term.brightBlue.bold("Esc");
|
|
3487
3533
|
term.gray(" back\n");
|
|
3488
3534
|
}
|
|
3535
|
+
if (typeof onAttachLiveUpdates === "function") {
|
|
3536
|
+
onAttachLiveUpdates(() => draw());
|
|
3537
|
+
}
|
|
3489
3538
|
draw();
|
|
3490
3539
|
await new Promise((resolve) => {
|
|
3491
3540
|
function handler(name) {
|
|
3541
|
+
if (done) return;
|
|
3542
|
+
const logs = currentLogs();
|
|
3492
3543
|
const maxOff = Math.max(0, logs.length - visibleCount);
|
|
3493
3544
|
if (name === "ESCAPE") {
|
|
3545
|
+
done = true;
|
|
3494
3546
|
term.off("key", handler);
|
|
3495
3547
|
resolve();
|
|
3496
3548
|
} else if (name === "UP") {
|
|
3549
|
+
autoScroll = false;
|
|
3497
3550
|
scrollOffset = Math.max(0, scrollOffset - 1);
|
|
3498
3551
|
draw();
|
|
3499
3552
|
} else if (name === "DOWN") {
|
|
3500
3553
|
scrollOffset = Math.min(maxOff, scrollOffset + 1);
|
|
3554
|
+
if (scrollOffset >= maxOff) autoScroll = true;
|
|
3501
3555
|
draw();
|
|
3502
3556
|
} else if (name === "PAGE_UP") {
|
|
3503
|
-
|
|
3557
|
+
autoScroll = false;
|
|
3558
|
+
scrollOffset = Math.max(0, scrollOffset - Math.max(1, visibleCount - 1));
|
|
3504
3559
|
draw();
|
|
3505
3560
|
} else if (name === "PAGE_DOWN") {
|
|
3506
|
-
scrollOffset = Math.min(maxOff, scrollOffset + visibleCount);
|
|
3561
|
+
scrollOffset = Math.min(maxOff, scrollOffset + Math.max(1, visibleCount - 1));
|
|
3562
|
+
if (scrollOffset >= maxOff) autoScroll = true;
|
|
3563
|
+
draw();
|
|
3564
|
+
} else if (name === "END" || name === "g") {
|
|
3565
|
+
autoScroll = true;
|
|
3566
|
+
scrollOffset = maxOff;
|
|
3507
3567
|
draw();
|
|
3508
3568
|
}
|
|
3509
3569
|
}
|