@hydra-acp/cli 0.1.41 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +85 -15
- package/dist/index.d.ts +3 -0
- package/dist/index.js +10 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -985,7 +985,8 @@ function mergeMeta(passthrough, ours) {
|
|
|
985
985
|
function sessionListEntryToWire(entry) {
|
|
986
986
|
const hydraMeta = {
|
|
987
987
|
attachedClients: entry.attachedClients,
|
|
988
|
-
status: entry.status
|
|
988
|
+
status: entry.status,
|
|
989
|
+
busy: entry.busy
|
|
989
990
|
};
|
|
990
991
|
if (entry.agentId !== void 0) {
|
|
991
992
|
hydraMeta.agentId = entry.agentId;
|
|
@@ -1131,6 +1132,10 @@ var init_types = __esm({
|
|
|
1131
1132
|
updatedAt: z3.string(),
|
|
1132
1133
|
attachedClients: z3.number().int().nonnegative(),
|
|
1133
1134
|
status: z3.enum(["live", "cold"]).default("live"),
|
|
1135
|
+
// True while the session is mid-turn (an agent prompt is in flight).
|
|
1136
|
+
// Always false for cold sessions. Lets pickers render a busy dot
|
|
1137
|
+
// without having to attach.
|
|
1138
|
+
busy: z3.boolean().default(false),
|
|
1134
1139
|
_meta: z3.record(z3.unknown()).optional()
|
|
1135
1140
|
});
|
|
1136
1141
|
SessionListEntryWire = z3.object({
|
|
@@ -4449,7 +4454,8 @@ async function listSessions(target, opts = {}, fetchImpl = fetch) {
|
|
|
4449
4454
|
currentUsage: s.currentUsage,
|
|
4450
4455
|
title: s.title,
|
|
4451
4456
|
importedFromMachine: s.importedFromMachine,
|
|
4452
|
-
importedFromUpstreamSessionId: s.importedFromUpstreamSessionId
|
|
4457
|
+
importedFromUpstreamSessionId: s.importedFromUpstreamSessionId,
|
|
4458
|
+
busy: s.busy
|
|
4453
4459
|
}));
|
|
4454
4460
|
}
|
|
4455
4461
|
async function killSession(target, id, fetchImpl = fetch) {
|
|
@@ -4573,7 +4579,7 @@ function toRow(s, now = Date.now()) {
|
|
|
4573
4579
|
return {
|
|
4574
4580
|
session: stripHydraSessionPrefix(s.sessionId),
|
|
4575
4581
|
upstream: formatUpstreamCell(s.upstreamSessionId, s.importedFromMachine),
|
|
4576
|
-
state: formatState(s.status, s.
|
|
4582
|
+
state: formatState(s.status, s.busy),
|
|
4577
4583
|
agent: formatAgentCell(s.agentId, s.currentUsage),
|
|
4578
4584
|
age: formatRelativeAge(s.updatedAt, now),
|
|
4579
4585
|
title: s.title ?? "-",
|
|
@@ -4589,11 +4595,11 @@ function formatUpstreamCell(upstreamSessionId, importedFromMachine) {
|
|
|
4589
4595
|
}
|
|
4590
4596
|
return "-";
|
|
4591
4597
|
}
|
|
4592
|
-
function formatState(status,
|
|
4598
|
+
function formatState(status, busy) {
|
|
4593
4599
|
if (status === "cold") {
|
|
4594
4600
|
return "COLD";
|
|
4595
4601
|
}
|
|
4596
|
-
return
|
|
4602
|
+
return busy ? "LIVE\u2022" : "LIVE";
|
|
4597
4603
|
}
|
|
4598
4604
|
function computeWidths(rows) {
|
|
4599
4605
|
return {
|
|
@@ -7029,6 +7035,10 @@ uncaught: ${err.stack ?? err.message}
|
|
|
7029
7035
|
this.handleCsi27Stdin(text);
|
|
7030
7036
|
return;
|
|
7031
7037
|
}
|
|
7038
|
+
if (text.includes("\x1B[200~")) {
|
|
7039
|
+
this.handleRawStdinSegment(text);
|
|
7040
|
+
return;
|
|
7041
|
+
}
|
|
7032
7042
|
if (text.includes("\n")) {
|
|
7033
7043
|
const parts = text.split("\n");
|
|
7034
7044
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -8793,7 +8803,7 @@ async function pickSession(term, opts) {
|
|
|
8793
8803
|
if (tier !== 0) {
|
|
8794
8804
|
return tier;
|
|
8795
8805
|
}
|
|
8796
|
-
return b.updatedAt.localeCompare(a.updatedAt);
|
|
8806
|
+
return b.updatedAt.slice(0, 16).localeCompare(a.updatedAt.slice(0, 16));
|
|
8797
8807
|
});
|
|
8798
8808
|
};
|
|
8799
8809
|
let cwdOnly = false;
|
|
@@ -9200,6 +9210,8 @@ async function pickSession(term, opts) {
|
|
|
9200
9210
|
renderFromScratch();
|
|
9201
9211
|
return await new Promise((resolve6) => {
|
|
9202
9212
|
let resolved = false;
|
|
9213
|
+
let autoRefreshTimer = null;
|
|
9214
|
+
let autoRefreshInFlight = false;
|
|
9203
9215
|
const onResize = () => {
|
|
9204
9216
|
if (resolved) {
|
|
9205
9217
|
return;
|
|
@@ -9211,6 +9223,10 @@ async function pickSession(term, opts) {
|
|
|
9211
9223
|
return;
|
|
9212
9224
|
}
|
|
9213
9225
|
resolved = true;
|
|
9226
|
+
if (autoRefreshTimer) {
|
|
9227
|
+
clearInterval(autoRefreshTimer);
|
|
9228
|
+
autoRefreshTimer = null;
|
|
9229
|
+
}
|
|
9214
9230
|
term.off("key", onKey);
|
|
9215
9231
|
term.off("resize", onResize);
|
|
9216
9232
|
process.stdout.write("\x1B[?2004l");
|
|
@@ -9227,8 +9243,16 @@ async function pickSession(term, opts) {
|
|
|
9227
9243
|
term.moveTo(1, indicatorRow() + 1);
|
|
9228
9244
|
term("\n");
|
|
9229
9245
|
};
|
|
9230
|
-
const
|
|
9246
|
+
const renderFingerprint = () => {
|
|
9247
|
+
const cells = rows.map(
|
|
9248
|
+
(r) => `${r.session}|${r.upstream}|${r.state}|${r.agent}|${r.age}|${r.title}|${r.cwd}`
|
|
9249
|
+
).join("\n");
|
|
9250
|
+
return `${selectedIdx}:${scrollOffset}:${transientStatus ?? ""}
|
|
9251
|
+
${cells}`;
|
|
9252
|
+
};
|
|
9253
|
+
const refresh = async (preferredId, refreshOpts = {}) => {
|
|
9231
9254
|
try {
|
|
9255
|
+
const beforeKey = refreshOpts.silent ? renderFingerprint() : "";
|
|
9232
9256
|
const next = await listSessions(opts.target);
|
|
9233
9257
|
allSessions = sortSessions(next);
|
|
9234
9258
|
applyFilter();
|
|
@@ -9245,8 +9269,14 @@ async function pickSession(term, opts) {
|
|
|
9245
9269
|
scrollOffset = Math.max(0, visible.length - viewportSize);
|
|
9246
9270
|
}
|
|
9247
9271
|
adjustScroll();
|
|
9272
|
+
if (refreshOpts.silent && renderFingerprint() === beforeKey) {
|
|
9273
|
+
return;
|
|
9274
|
+
}
|
|
9248
9275
|
renderFromScratch();
|
|
9249
9276
|
} catch (err) {
|
|
9277
|
+
if (refreshOpts.silent) {
|
|
9278
|
+
return;
|
|
9279
|
+
}
|
|
9250
9280
|
transientStatus = `refresh failed: ${err.message}`;
|
|
9251
9281
|
renderFromScratch();
|
|
9252
9282
|
}
|
|
@@ -9723,6 +9753,16 @@ async function pickSession(term, opts) {
|
|
|
9723
9753
|
}
|
|
9724
9754
|
term.on("key", onKey);
|
|
9725
9755
|
term.on("resize", onResize);
|
|
9756
|
+
autoRefreshTimer = setInterval(() => {
|
|
9757
|
+
if (resolved || mode !== "normal" || searchActive || autoRefreshInFlight) {
|
|
9758
|
+
return;
|
|
9759
|
+
}
|
|
9760
|
+
const currentId = selectedIdx > 0 ? visible[selectedIdx - 1]?.sessionId : void 0;
|
|
9761
|
+
autoRefreshInFlight = true;
|
|
9762
|
+
void refresh(currentId, { silent: true }).finally(() => {
|
|
9763
|
+
autoRefreshInFlight = false;
|
|
9764
|
+
});
|
|
9765
|
+
}, 3e3);
|
|
9726
9766
|
});
|
|
9727
9767
|
}
|
|
9728
9768
|
function readTermHeight(term) {
|
|
@@ -11161,9 +11201,38 @@ async function runTuiApp(opts) {
|
|
|
11161
11201
|
const viewPrefs = {
|
|
11162
11202
|
showThoughts: config.tui.showThoughts
|
|
11163
11203
|
};
|
|
11204
|
+
let altScreenEngaged = false;
|
|
11205
|
+
const enterAltScreen = () => {
|
|
11206
|
+
if (altScreenEngaged) {
|
|
11207
|
+
return;
|
|
11208
|
+
}
|
|
11209
|
+
term.fullscreen(true);
|
|
11210
|
+
altScreenEngaged = true;
|
|
11211
|
+
};
|
|
11212
|
+
const leaveAltScreen = () => {
|
|
11213
|
+
if (!altScreenEngaged) {
|
|
11214
|
+
return;
|
|
11215
|
+
}
|
|
11216
|
+
term.fullscreen(false);
|
|
11217
|
+
altScreenEngaged = false;
|
|
11218
|
+
process.stdout.write("\n");
|
|
11219
|
+
};
|
|
11220
|
+
enterAltScreen();
|
|
11221
|
+
const altScreenCleanup = () => {
|
|
11222
|
+
if (altScreenEngaged) {
|
|
11223
|
+
term.fullscreen(false);
|
|
11224
|
+
altScreenEngaged = false;
|
|
11225
|
+
}
|
|
11226
|
+
};
|
|
11227
|
+
process.once("exit", altScreenCleanup);
|
|
11164
11228
|
let nextOpts = opts;
|
|
11165
|
-
|
|
11166
|
-
|
|
11229
|
+
try {
|
|
11230
|
+
while (nextOpts !== null) {
|
|
11231
|
+
nextOpts = await runSession(term, config, target, nextOpts, exitHint, viewPrefs);
|
|
11232
|
+
}
|
|
11233
|
+
} finally {
|
|
11234
|
+
leaveAltScreen();
|
|
11235
|
+
process.off("exit", altScreenCleanup);
|
|
11167
11236
|
}
|
|
11168
11237
|
const pendingUpdate = await getPendingUpdate();
|
|
11169
11238
|
if (pendingUpdate) {
|
|
@@ -11173,7 +11242,6 @@ async function runTuiApp(opts) {
|
|
|
11173
11242
|
if (exitHint.sessionId && process.stdout.isTTY) {
|
|
11174
11243
|
const short = stripHydraSessionPrefix(exitHint.sessionId);
|
|
11175
11244
|
const flags = exitHint.readonly ? " --readonly" : "";
|
|
11176
|
-
process.stdout.write("\x1B[2J\x1B[H");
|
|
11177
11245
|
process.stdout.write(
|
|
11178
11246
|
`To resume: ${invokedBinName()} tui --session ${short}${flags}
|
|
11179
11247
|
`
|
|
@@ -11184,7 +11252,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
11184
11252
|
const ctx = await resolveSession(term, config, target, opts);
|
|
11185
11253
|
if (!ctx) {
|
|
11186
11254
|
term.grabInput(false);
|
|
11187
|
-
|
|
11255
|
+
return null;
|
|
11188
11256
|
}
|
|
11189
11257
|
const launchLabelBase = ctx.sessionId === "__new__" ? "Starting new session\u2026" : "Resuming session\u2026";
|
|
11190
11258
|
const installStatus = createInstallStatusLine(term, launchLabelBase);
|
|
@@ -11917,7 +11985,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
11917
11985
|
const sessionbarAgent = resolvedAgentId || agentInfoName || "?";
|
|
11918
11986
|
const usage = { ...initialUsage ?? {} };
|
|
11919
11987
|
installStatus.finalize();
|
|
11920
|
-
screen.start();
|
|
11988
|
+
screen.start({ skipFullscreen: true });
|
|
11921
11989
|
screen.setHideThoughts(!viewPrefs.showThoughts);
|
|
11922
11990
|
screen.setSessionbar({
|
|
11923
11991
|
agent: sessionbarAgent,
|
|
@@ -12065,7 +12133,7 @@ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
|
|
|
12065
12133
|
sessionElapsedTimer = null;
|
|
12066
12134
|
}
|
|
12067
12135
|
screen.clearWindowTitle();
|
|
12068
|
-
screen.stop();
|
|
12136
|
+
screen.stop({ keepFullscreen: true });
|
|
12069
12137
|
saveHistory(historyFile, history).catch(() => void 0);
|
|
12070
12138
|
void stream.close().catch(() => void 0);
|
|
12071
12139
|
};
|
|
@@ -15692,7 +15760,8 @@ var SessionManager = class {
|
|
|
15692
15760
|
currentUsage: session.currentUsage,
|
|
15693
15761
|
updatedAt: used,
|
|
15694
15762
|
attachedClients: session.attachedCount,
|
|
15695
|
-
status: "live"
|
|
15763
|
+
status: "live",
|
|
15764
|
+
busy: session.turnStartedAt !== void 0
|
|
15696
15765
|
});
|
|
15697
15766
|
}
|
|
15698
15767
|
const records = await this.store.list().catch(() => []);
|
|
@@ -15716,7 +15785,8 @@ var SessionManager = class {
|
|
|
15716
15785
|
importedFromUpstreamSessionId: r.importedFromUpstreamSessionId,
|
|
15717
15786
|
updatedAt: used,
|
|
15718
15787
|
attachedClients: 0,
|
|
15719
|
-
status: "cold"
|
|
15788
|
+
status: "cold",
|
|
15789
|
+
busy: false
|
|
15720
15790
|
});
|
|
15721
15791
|
}
|
|
15722
15792
|
entries.sort((a, b) => a.updatedAt < b.updatedAt ? 1 : -1);
|
package/dist/index.d.ts
CHANGED
|
@@ -1415,6 +1415,7 @@ declare const SessionListEntry: z.ZodObject<{
|
|
|
1415
1415
|
updatedAt: z.ZodString;
|
|
1416
1416
|
attachedClients: z.ZodNumber;
|
|
1417
1417
|
status: z.ZodDefault<z.ZodEnum<["live", "cold"]>>;
|
|
1418
|
+
busy: z.ZodDefault<z.ZodBoolean>;
|
|
1418
1419
|
_meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1419
1420
|
}, "strip", z.ZodTypeAny, {
|
|
1420
1421
|
sessionId: string;
|
|
@@ -1422,6 +1423,7 @@ declare const SessionListEntry: z.ZodObject<{
|
|
|
1422
1423
|
status: "live" | "cold";
|
|
1423
1424
|
updatedAt: string;
|
|
1424
1425
|
attachedClients: number;
|
|
1426
|
+
busy: boolean;
|
|
1425
1427
|
agentId?: string | undefined;
|
|
1426
1428
|
upstreamSessionId?: string | undefined;
|
|
1427
1429
|
title?: string | undefined;
|
|
@@ -1454,6 +1456,7 @@ declare const SessionListEntry: z.ZodObject<{
|
|
|
1454
1456
|
} | undefined;
|
|
1455
1457
|
importedFromMachine?: string | undefined;
|
|
1456
1458
|
importedFromUpstreamSessionId?: string | undefined;
|
|
1459
|
+
busy?: boolean | undefined;
|
|
1457
1460
|
}>;
|
|
1458
1461
|
type SessionListEntry = z.infer<typeof SessionListEntry>;
|
|
1459
1462
|
declare const SessionListResult: z.ZodObject<{
|
package/dist/index.js
CHANGED
|
@@ -1388,6 +1388,10 @@ var SessionListEntry = z3.object({
|
|
|
1388
1388
|
updatedAt: z3.string(),
|
|
1389
1389
|
attachedClients: z3.number().int().nonnegative(),
|
|
1390
1390
|
status: z3.enum(["live", "cold"]).default("live"),
|
|
1391
|
+
// True while the session is mid-turn (an agent prompt is in flight).
|
|
1392
|
+
// Always false for cold sessions. Lets pickers render a busy dot
|
|
1393
|
+
// without having to attach.
|
|
1394
|
+
busy: z3.boolean().default(false),
|
|
1391
1395
|
_meta: z3.record(z3.unknown()).optional()
|
|
1392
1396
|
});
|
|
1393
1397
|
var SessionListEntryWire = z3.object({
|
|
@@ -1404,7 +1408,8 @@ var SessionListResult = z3.object({
|
|
|
1404
1408
|
function sessionListEntryToWire(entry) {
|
|
1405
1409
|
const hydraMeta = {
|
|
1406
1410
|
attachedClients: entry.attachedClients,
|
|
1407
|
-
status: entry.status
|
|
1411
|
+
status: entry.status,
|
|
1412
|
+
busy: entry.busy
|
|
1408
1413
|
};
|
|
1409
1414
|
if (entry.agentId !== void 0) {
|
|
1410
1415
|
hydraMeta.agentId = entry.agentId;
|
|
@@ -5307,7 +5312,8 @@ var SessionManager = class {
|
|
|
5307
5312
|
currentUsage: session.currentUsage,
|
|
5308
5313
|
updatedAt: used,
|
|
5309
5314
|
attachedClients: session.attachedCount,
|
|
5310
|
-
status: "live"
|
|
5315
|
+
status: "live",
|
|
5316
|
+
busy: session.turnStartedAt !== void 0
|
|
5311
5317
|
});
|
|
5312
5318
|
}
|
|
5313
5319
|
const records = await this.store.list().catch(() => []);
|
|
@@ -5331,7 +5337,8 @@ var SessionManager = class {
|
|
|
5331
5337
|
importedFromUpstreamSessionId: r.importedFromUpstreamSessionId,
|
|
5332
5338
|
updatedAt: used,
|
|
5333
5339
|
attachedClients: 0,
|
|
5334
|
-
status: "cold"
|
|
5340
|
+
status: "cold",
|
|
5341
|
+
busy: false
|
|
5335
5342
|
});
|
|
5336
5343
|
}
|
|
5337
5344
|
entries.sort((a, b) => a.updatedAt < b.updatedAt ? 1 : -1);
|