@pantheon.ai/agents 0.0.15 → 0.0.16
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/index.js +659 -224
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { Http2ServerRequest } from "http2";
|
|
|
16
16
|
import { Readable } from "stream";
|
|
17
17
|
import blessed from "reblessed";
|
|
18
18
|
import { inspect } from "node:util";
|
|
19
|
+
import { parse } from "shell-quote";
|
|
19
20
|
|
|
20
21
|
//#region ../../node_modules/dotenv/package.json
|
|
21
22
|
var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -394,7 +395,7 @@ var require_cli_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
394
395
|
|
|
395
396
|
//#endregion
|
|
396
397
|
//#region package.json
|
|
397
|
-
var version$1 = "0.0.
|
|
398
|
+
var version$1 = "0.0.16";
|
|
398
399
|
|
|
399
400
|
//#endregion
|
|
400
401
|
//#region src/schemas/task-list.ts
|
|
@@ -2344,7 +2345,7 @@ const _parse$1 = (_Err) => (schema, value, _ctx, _params) => {
|
|
|
2344
2345
|
}
|
|
2345
2346
|
return result.value;
|
|
2346
2347
|
};
|
|
2347
|
-
const parse$
|
|
2348
|
+
const parse$2 = /* @__PURE__ */ _parse$1($ZodRealError);
|
|
2348
2349
|
const _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
2349
2350
|
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
|
2350
2351
|
let result = schema._zod.run({
|
|
@@ -5521,7 +5522,7 @@ const ZodRealError = $constructor("ZodError", initializer, { Parent: Error });
|
|
|
5521
5522
|
|
|
5522
5523
|
//#endregion
|
|
5523
5524
|
//#region ../../node_modules/zod/v4/classic/parse.js
|
|
5524
|
-
const parse = /* @__PURE__ */ _parse$1(ZodRealError);
|
|
5525
|
+
const parse$1 = /* @__PURE__ */ _parse$1(ZodRealError);
|
|
5525
5526
|
const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
5526
5527
|
const safeParse$1 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
5527
5528
|
const safeParseAsync$1 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -5560,7 +5561,7 @@ const ZodType$1 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
5560
5561
|
reg.add(inst, meta);
|
|
5561
5562
|
return inst;
|
|
5562
5563
|
});
|
|
5563
|
-
inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse });
|
|
5564
|
+
inst.parse = (data, params) => parse$1(inst, data, params, { callee: inst.parse });
|
|
5564
5565
|
inst.safeParse = (data, params) => safeParse$1(inst, data, params);
|
|
5565
5566
|
inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync });
|
|
5566
5567
|
inst.safeParseAsync = async (data, params) => safeParseAsync$1(inst, data, params);
|
|
@@ -17342,32 +17343,40 @@ async function consumeOpaqueSseStream(options) {
|
|
|
17342
17343
|
};
|
|
17343
17344
|
}
|
|
17344
17345
|
var WatchStepAggregator = class {
|
|
17345
|
-
maxLeadingTextChars;
|
|
17346
|
-
maxLeadingReasoningChars;
|
|
17347
17346
|
maxLogLines;
|
|
17348
17347
|
maxWarnings;
|
|
17349
|
-
leadingText = "";
|
|
17350
|
-
leadingReasoning = "";
|
|
17351
17348
|
toolActions = /* @__PURE__ */ new Map();
|
|
17349
|
+
timeline = [];
|
|
17352
17350
|
logLines = [];
|
|
17351
|
+
todoItems = [];
|
|
17353
17352
|
warnings = [];
|
|
17353
|
+
warningItems = [];
|
|
17354
17354
|
unknownEventCount = 0;
|
|
17355
17355
|
orderCounter = 0;
|
|
17356
17356
|
constructor(options = {}) {
|
|
17357
|
-
this.maxLeadingTextChars = options.maxLeadingTextChars ?? 800;
|
|
17358
|
-
this.maxLeadingReasoningChars = options.maxLeadingReasoningChars ?? 800;
|
|
17359
17357
|
this.maxLogLines = options.maxLogLines ?? 200;
|
|
17360
17358
|
this.maxWarnings = options.maxWarnings ?? 50;
|
|
17361
17359
|
}
|
|
17362
17360
|
pushLog(line) {
|
|
17363
17361
|
if (!line) return;
|
|
17364
17362
|
this.logLines.push(line);
|
|
17365
|
-
if (this.logLines.length > this.maxLogLines) this.logLines.splice(0, this.logLines.length - this.maxLogLines);
|
|
17363
|
+
if (Number.isFinite(this.maxLogLines) && this.maxLogLines > 0 && this.logLines.length > this.maxLogLines) this.logLines.splice(0, this.logLines.length - this.maxLogLines);
|
|
17366
17364
|
}
|
|
17367
17365
|
pushWarning(message) {
|
|
17368
17366
|
if (!message) return;
|
|
17367
|
+
const order = this.orderCounter++;
|
|
17369
17368
|
this.warnings.push(message);
|
|
17369
|
+
this.warningItems.push({
|
|
17370
|
+
message,
|
|
17371
|
+
order
|
|
17372
|
+
});
|
|
17373
|
+
this.timeline.push({
|
|
17374
|
+
kind: "warning",
|
|
17375
|
+
message,
|
|
17376
|
+
order
|
|
17377
|
+
});
|
|
17370
17378
|
if (this.warnings.length > this.maxWarnings) this.warnings.splice(0, this.warnings.length - this.maxWarnings);
|
|
17379
|
+
if (this.warningItems.length > this.maxWarnings) this.warningItems.splice(0, this.warningItems.length - this.maxWarnings);
|
|
17371
17380
|
}
|
|
17372
17381
|
pushCommandExecutionOutput(output) {
|
|
17373
17382
|
const out = output;
|
|
@@ -17377,6 +17386,31 @@ var WatchStepAggregator = class {
|
|
|
17377
17386
|
if (trimmed) trimmed.split("\n").forEach((line) => this.pushLog(line));
|
|
17378
17387
|
if (exitCode != null && exitCode !== 0) this.pushLog(`exit_code=${exitCode}`);
|
|
17379
17388
|
}
|
|
17389
|
+
setTodoItems(items) {
|
|
17390
|
+
if (!Array.isArray(items)) return;
|
|
17391
|
+
const normalized = [];
|
|
17392
|
+
for (const item of items) {
|
|
17393
|
+
if (typeof item !== "object" || item === null) continue;
|
|
17394
|
+
const text = typeof item.text === "string" ? item.text : "";
|
|
17395
|
+
const completed = Boolean(item.completed);
|
|
17396
|
+
if (!text) continue;
|
|
17397
|
+
normalized.push({
|
|
17398
|
+
text,
|
|
17399
|
+
completed
|
|
17400
|
+
});
|
|
17401
|
+
}
|
|
17402
|
+
this.todoItems = normalized;
|
|
17403
|
+
}
|
|
17404
|
+
pushTimelineText(kind, delta) {
|
|
17405
|
+
if (!delta) return this.orderCounter;
|
|
17406
|
+
const order = this.orderCounter++;
|
|
17407
|
+
this.timeline.push({
|
|
17408
|
+
kind,
|
|
17409
|
+
order,
|
|
17410
|
+
text: delta
|
|
17411
|
+
});
|
|
17412
|
+
return order;
|
|
17413
|
+
}
|
|
17380
17414
|
getOrCreateToolAction(toolCallId) {
|
|
17381
17415
|
const existing = this.toolActions.get(toolCallId);
|
|
17382
17416
|
if (existing) return existing;
|
|
@@ -17386,6 +17420,11 @@ var WatchStepAggregator = class {
|
|
|
17386
17420
|
_order: this.orderCounter++
|
|
17387
17421
|
};
|
|
17388
17422
|
this.toolActions.set(toolCallId, created);
|
|
17423
|
+
this.timeline.push({
|
|
17424
|
+
kind: "tool",
|
|
17425
|
+
order: created._order,
|
|
17426
|
+
toolCallId
|
|
17427
|
+
});
|
|
17389
17428
|
return created;
|
|
17390
17429
|
}
|
|
17391
17430
|
pushUiChunk(chunk) {
|
|
@@ -17396,19 +17435,13 @@ var WatchStepAggregator = class {
|
|
|
17396
17435
|
case "text-delta": {
|
|
17397
17436
|
const delta = typeof chunk.delta === "string" ? chunk.delta : "";
|
|
17398
17437
|
if (!delta) return;
|
|
17399
|
-
|
|
17400
|
-
const remaining = this.maxLeadingTextChars - this.leadingText.length;
|
|
17401
|
-
this.leadingText += delta.slice(0, remaining);
|
|
17402
|
-
}
|
|
17438
|
+
this.pushTimelineText("message", delta);
|
|
17403
17439
|
return;
|
|
17404
17440
|
}
|
|
17405
17441
|
case "reasoning-delta": {
|
|
17406
17442
|
const delta = typeof chunk.delta === "string" ? chunk.delta : "";
|
|
17407
17443
|
if (!delta) return;
|
|
17408
|
-
|
|
17409
|
-
const remaining = this.maxLeadingReasoningChars - this.leadingReasoning.length;
|
|
17410
|
-
this.leadingReasoning += delta.slice(0, remaining);
|
|
17411
|
-
}
|
|
17444
|
+
this.pushTimelineText("reasoning", delta);
|
|
17412
17445
|
return;
|
|
17413
17446
|
}
|
|
17414
17447
|
case "tool-input-start": {
|
|
@@ -17476,6 +17509,11 @@ var WatchStepAggregator = class {
|
|
|
17476
17509
|
this.pushLog(`! unknown: ${reason}`);
|
|
17477
17510
|
return;
|
|
17478
17511
|
}
|
|
17512
|
+
case "data-agent-event": {
|
|
17513
|
+
const data = chunk.data;
|
|
17514
|
+
if (data?.kind === "codex.todo_list") this.setTodoItems(data.items);
|
|
17515
|
+
return;
|
|
17516
|
+
}
|
|
17479
17517
|
default: return;
|
|
17480
17518
|
}
|
|
17481
17519
|
}
|
|
@@ -17483,13 +17521,16 @@ var WatchStepAggregator = class {
|
|
|
17483
17521
|
chunks.forEach((chunk) => this.pushUiChunk(chunk));
|
|
17484
17522
|
}
|
|
17485
17523
|
snapshot() {
|
|
17486
|
-
const actions = Array.from(this.toolActions.values()).sort((a, b) => a._order - b._order).map(({ _order: _unused, ...rest }) => rest);
|
|
17487
17524
|
return {
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
|
|
17525
|
+
toolActions: Array.from(this.toolActions.values()).sort((a, b) => a._order - b._order).map(({ _order, ...rest }) => ({
|
|
17526
|
+
...rest,
|
|
17527
|
+
order: _order
|
|
17528
|
+
})),
|
|
17529
|
+
timeline: this.timeline.map((item) => ({ ...item })),
|
|
17491
17530
|
logLines: [...this.logLines],
|
|
17531
|
+
todoItems: this.todoItems.map((item) => ({ ...item })),
|
|
17492
17532
|
warnings: [...this.warnings],
|
|
17533
|
+
warningItems: this.warningItems.map((item) => ({ ...item })),
|
|
17493
17534
|
unknownEventCount: this.unknownEventCount
|
|
17494
17535
|
};
|
|
17495
17536
|
}
|
|
@@ -21138,7 +21179,7 @@ const ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
|
|
|
21138
21179
|
$ZodType.init(inst, def);
|
|
21139
21180
|
inst.def = def;
|
|
21140
21181
|
inst.type = def.type;
|
|
21141
|
-
inst.parse = (data, params) => parse$
|
|
21182
|
+
inst.parse = (data, params) => parse$2(inst, data, params, { callee: inst.parse });
|
|
21142
21183
|
inst.safeParse = (data, params) => safeParse$2(inst, data, params);
|
|
21143
21184
|
inst.parseAsync = async (data, params) => parseAsync$1(inst, data, params, { callee: inst.parseAsync });
|
|
21144
21185
|
inst.safeParseAsync = async (data, params) => safeParseAsync$2(inst, data, params);
|
|
@@ -32085,36 +32126,150 @@ function tryExtractBashCommand(command) {
|
|
|
32085
32126
|
}
|
|
32086
32127
|
return rest.trim();
|
|
32087
32128
|
}
|
|
32088
|
-
function
|
|
32129
|
+
function normalizeCommand(command) {
|
|
32089
32130
|
const trimmed = command.trim();
|
|
32090
32131
|
return tryExtractBashCommand(trimmed)?.trim() || trimmed;
|
|
32091
32132
|
}
|
|
32092
|
-
function
|
|
32093
|
-
|
|
32094
|
-
|
|
32095
|
-
|
|
32096
|
-
const
|
|
32097
|
-
|
|
32098
|
-
return
|
|
32133
|
+
function splitCommandLines(command) {
|
|
32134
|
+
return command.replaceAll("\r\n", "\n").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
32135
|
+
}
|
|
32136
|
+
function stripCommentPrefix(line) {
|
|
32137
|
+
const trimmed = line.trim();
|
|
32138
|
+
if (trimmed.startsWith("//")) return trimmed.slice(2).trimStart();
|
|
32139
|
+
return trimmed;
|
|
32140
|
+
}
|
|
32141
|
+
function commandBasename(value) {
|
|
32142
|
+
const lastSlash = value.lastIndexOf("/");
|
|
32143
|
+
return lastSlash === -1 ? value : value.slice(lastSlash + 1);
|
|
32144
|
+
}
|
|
32145
|
+
function parseShellEntries(line) {
|
|
32146
|
+
try {
|
|
32147
|
+
return parse(line);
|
|
32148
|
+
} catch {
|
|
32149
|
+
return;
|
|
32150
|
+
}
|
|
32151
|
+
}
|
|
32152
|
+
function takeMainTokens(entries) {
|
|
32153
|
+
const stopSet = new Set([
|
|
32154
|
+
"|",
|
|
32155
|
+
"||",
|
|
32156
|
+
"&&",
|
|
32157
|
+
";",
|
|
32158
|
+
"|&",
|
|
32159
|
+
";;",
|
|
32160
|
+
"&",
|
|
32161
|
+
"(",
|
|
32162
|
+
")",
|
|
32163
|
+
"<",
|
|
32164
|
+
">",
|
|
32165
|
+
">>",
|
|
32166
|
+
">&",
|
|
32167
|
+
"<("
|
|
32168
|
+
]);
|
|
32169
|
+
const out = [];
|
|
32170
|
+
for (const entry of entries) {
|
|
32171
|
+
if (typeof entry === "string") {
|
|
32172
|
+
out.push(entry);
|
|
32173
|
+
continue;
|
|
32174
|
+
}
|
|
32175
|
+
if ("op" in entry) {
|
|
32176
|
+
if (stopSet.has(entry.op)) break;
|
|
32177
|
+
continue;
|
|
32178
|
+
}
|
|
32179
|
+
if ("comment" in entry) break;
|
|
32180
|
+
}
|
|
32181
|
+
return out;
|
|
32182
|
+
}
|
|
32183
|
+
function pickLastNonOptionArg(tokens) {
|
|
32184
|
+
const values = tokens.filter((token) => !token.startsWith("-"));
|
|
32185
|
+
return values.length > 0 ? values[values.length - 1] : void 0;
|
|
32186
|
+
}
|
|
32187
|
+
function parseExploredItem(line) {
|
|
32188
|
+
const entries = parseShellEntries(normalizeCommand(line));
|
|
32189
|
+
if (!entries) return void 0;
|
|
32190
|
+
const tokens = takeMainTokens(entries);
|
|
32191
|
+
if (tokens.length === 0) return void 0;
|
|
32192
|
+
const command = commandBasename(tokens[0] ?? "");
|
|
32193
|
+
if (command === "rg") {
|
|
32194
|
+
const args = tokens.slice(1);
|
|
32195
|
+
if (args.includes("--files")) return {
|
|
32196
|
+
kind: "list",
|
|
32197
|
+
target: pickLastNonOptionArg(args)
|
|
32198
|
+
};
|
|
32199
|
+
const firstValueIndex = args.findIndex((token) => !token.startsWith("-"));
|
|
32200
|
+
if (firstValueIndex === -1) return void 0;
|
|
32201
|
+
const terms = args[firstValueIndex];
|
|
32202
|
+
const file = args[firstValueIndex + 1];
|
|
32203
|
+
if (!terms || !file) return void 0;
|
|
32204
|
+
return {
|
|
32205
|
+
kind: "search",
|
|
32206
|
+
terms,
|
|
32207
|
+
file
|
|
32208
|
+
};
|
|
32209
|
+
}
|
|
32210
|
+
if (command === "ls") return {
|
|
32211
|
+
kind: "list",
|
|
32212
|
+
target: pickLastNonOptionArg(tokens.slice(1))
|
|
32213
|
+
};
|
|
32214
|
+
if (command === "sed" || command === "nl" || command === "cat") {
|
|
32215
|
+
if (tokens.length < 2) return void 0;
|
|
32216
|
+
const file = tokens[tokens.length - 1];
|
|
32217
|
+
if (!file || file.startsWith("-")) return void 0;
|
|
32218
|
+
return {
|
|
32219
|
+
kind: "read",
|
|
32220
|
+
file
|
|
32221
|
+
};
|
|
32222
|
+
}
|
|
32223
|
+
}
|
|
32224
|
+
function parseExploredItemsFromCommand(command) {
|
|
32225
|
+
const rawLines = splitCommandLines(normalizeCommand(command));
|
|
32226
|
+
const items = [];
|
|
32227
|
+
for (const rawLine of rawLines) {
|
|
32228
|
+
const line = stripCommentPrefix(rawLine);
|
|
32229
|
+
if (!line) continue;
|
|
32230
|
+
const item = parseExploredItem(normalizeCommand(line));
|
|
32231
|
+
if (!item) return void 0;
|
|
32232
|
+
items.push(item);
|
|
32233
|
+
}
|
|
32234
|
+
if (items.length === 0) return void 0;
|
|
32235
|
+
return items;
|
|
32236
|
+
}
|
|
32237
|
+
function formatExploredItemsLines(items) {
|
|
32238
|
+
const lines = ["Explored"];
|
|
32239
|
+
for (const item of items) {
|
|
32240
|
+
if (item.kind === "read") {
|
|
32241
|
+
lines.push(`Read ${item.file}`);
|
|
32242
|
+
continue;
|
|
32243
|
+
}
|
|
32244
|
+
if (item.kind === "list") {
|
|
32245
|
+
lines.push(item.target ? `List ${item.target}` : "List");
|
|
32246
|
+
continue;
|
|
32247
|
+
}
|
|
32248
|
+
lines.push(`Search ${item.terms} in ${item.file}`);
|
|
32249
|
+
}
|
|
32250
|
+
return lines;
|
|
32251
|
+
}
|
|
32252
|
+
function getExploredCommandLines(command) {
|
|
32253
|
+
const explored = parseExploredItemsFromCommand(command);
|
|
32254
|
+
if (!explored) return void 0;
|
|
32255
|
+
return formatExploredItemsLines(explored);
|
|
32256
|
+
}
|
|
32257
|
+
function isExploredCommandExecution(command) {
|
|
32258
|
+
return parseExploredItemsFromCommand(command) != null;
|
|
32259
|
+
}
|
|
32260
|
+
function formatCommandExecutionDisplayCommand(command) {
|
|
32261
|
+
const exploredLines = getExploredCommandLines(command);
|
|
32262
|
+
if (exploredLines) return exploredLines.join("\n");
|
|
32263
|
+
return normalizeCommand(command);
|
|
32099
32264
|
}
|
|
32100
32265
|
|
|
32101
32266
|
//#endregion
|
|
32102
32267
|
//#region src/cli/commands/watch.ts
|
|
32103
32268
|
const PANTHEON_BASE_URL = "https://pantheon-ai.tidb.ai";
|
|
32104
|
-
|
|
32105
|
-
|
|
32106
|
-
|
|
32107
|
-
|
|
32108
|
-
function parseScreenGrid(value) {
|
|
32109
|
-
const match = value.trim().toLowerCase().match(/^(\d+)x(\d+)$/);
|
|
32110
|
-
if (!match) throw new InvalidArgumentError("screen must be <cols>x<rows>, e.g. 3x1 or 5x4");
|
|
32111
|
-
const cols = Number(match[1]);
|
|
32112
|
-
const rows = Number(match[2]);
|
|
32113
|
-
if (!Number.isInteger(cols) || !Number.isInteger(rows) || cols <= 0 || rows <= 0) throw new InvalidArgumentError("screen requires positive integer cols/rows, e.g. 3x1");
|
|
32114
|
-
return {
|
|
32115
|
-
cols,
|
|
32116
|
-
rows
|
|
32117
|
-
};
|
|
32269
|
+
function parseListWidth(value) {
|
|
32270
|
+
const width = Number(value);
|
|
32271
|
+
if (!Number.isInteger(width) || width <= 0) throw new InvalidArgumentError("list-width requires a positive integer, e.g. 32");
|
|
32272
|
+
return width;
|
|
32118
32273
|
}
|
|
32119
32274
|
function ensureEnvOrExit(keys) {
|
|
32120
32275
|
const missing = keys.filter((key) => !process.env[key]);
|
|
@@ -32122,33 +32277,6 @@ function ensureEnvOrExit(keys) {
|
|
|
32122
32277
|
for (const key of missing) console.error(`${key} environment variable is not set.`);
|
|
32123
32278
|
process.exit(1);
|
|
32124
32279
|
}
|
|
32125
|
-
function formatDurationMs(ms) {
|
|
32126
|
-
const seconds = Math.max(0, Math.floor(ms / 1e3));
|
|
32127
|
-
const minutes = Math.floor(seconds / 60);
|
|
32128
|
-
const hours = Math.floor(minutes / 60);
|
|
32129
|
-
if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
32130
|
-
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
|
|
32131
|
-
return `${seconds}s`;
|
|
32132
|
-
}
|
|
32133
|
-
function getTaskStartTime(task) {
|
|
32134
|
-
switch (task.status) {
|
|
32135
|
-
case "pending": return task.queued_at;
|
|
32136
|
-
case "running": return task.started_at;
|
|
32137
|
-
case "completed":
|
|
32138
|
-
case "failed": return task.started_at ?? task.queued_at;
|
|
32139
|
-
case "cancelled": return task.queued_at;
|
|
32140
|
-
}
|
|
32141
|
-
}
|
|
32142
|
-
function getTaskElapsedMs(task, now = /* @__PURE__ */ new Date()) {
|
|
32143
|
-
const start = getTaskStartTime(task);
|
|
32144
|
-
if (!start) return 0;
|
|
32145
|
-
switch (task.status) {
|
|
32146
|
-
case "completed": return task.ended_at.getTime() - start.getTime();
|
|
32147
|
-
case "failed": return (task.ended_at ?? now).getTime() - start.getTime();
|
|
32148
|
-
case "cancelled": return task.cancelled_at.getTime() - start.getTime();
|
|
32149
|
-
default: return now.getTime() - start.getTime();
|
|
32150
|
-
}
|
|
32151
|
-
}
|
|
32152
32280
|
function toStreamSourceFromExecuteAgent(executeAgent) {
|
|
32153
32281
|
if (!executeAgent) return void 0;
|
|
32154
32282
|
const normalized = executeAgent.toLowerCase();
|
|
@@ -32296,42 +32424,36 @@ function yellow(text, enabled) {
|
|
|
32296
32424
|
function cyan(text, enabled) {
|
|
32297
32425
|
return sgrWrap(text, ANSI.cyan, enabled);
|
|
32298
32426
|
}
|
|
32427
|
+
function dimGray(text, enabled) {
|
|
32428
|
+
return sgrWrap(text, `${ANSI.dim}${ANSI.gray}`, enabled);
|
|
32429
|
+
}
|
|
32299
32430
|
function kv(label, value, style) {
|
|
32300
32431
|
return `${dim(`${label}:`, style)} ${value}`;
|
|
32301
32432
|
}
|
|
32302
|
-
function
|
|
32303
|
-
|
|
32304
|
-
|
|
32305
|
-
|
|
32306
|
-
case "failed": return red(status, style);
|
|
32307
|
-
case "pending": return cyan(status, style);
|
|
32308
|
-
case "cancelled": return gray(status, style);
|
|
32309
|
-
}
|
|
32433
|
+
function getCommandExecutionDisplayCommand(tool) {
|
|
32434
|
+
const raw = getCommandExecutionRawCommand(tool);
|
|
32435
|
+
if (!raw) return void 0;
|
|
32436
|
+
return formatCommandExecutionDisplayCommand(raw) || void 0;
|
|
32310
32437
|
}
|
|
32311
|
-
function
|
|
32312
|
-
|
|
32313
|
-
|
|
32314
|
-
|
|
32315
|
-
|
|
32316
|
-
case "running":
|
|
32317
|
-
case "pending": return yellow(status, style);
|
|
32318
|
-
case "manifesting":
|
|
32319
|
-
case "ready_for_manifest": return cyan(status, style);
|
|
32320
|
-
default: return gray(status, style);
|
|
32321
|
-
}
|
|
32438
|
+
function colorizeCommandProgram(display, style) {
|
|
32439
|
+
const match = display.match(/^(\s*)(\S+)([\s\S]*)$/);
|
|
32440
|
+
if (!match) return display;
|
|
32441
|
+
const [, leading, program, rest] = match;
|
|
32442
|
+
return `${leading}${cyan(program ?? "", style)}${rest ?? ""}`;
|
|
32322
32443
|
}
|
|
32323
|
-
function
|
|
32444
|
+
function getCommandExecutionRawCommand(tool) {
|
|
32324
32445
|
const title = typeof tool.title === "string" ? tool.title : "";
|
|
32325
32446
|
const inputCommand = typeof tool.input?.command === "string" ? tool.input.command : "";
|
|
32326
|
-
|
|
32327
|
-
if (!raw) return void 0;
|
|
32328
|
-
return formatCommandExecutionDisplayCommand(raw) || void 0;
|
|
32447
|
+
return title || inputCommand || void 0;
|
|
32329
32448
|
}
|
|
32330
32449
|
function formatToolLabel(tool, style) {
|
|
32331
32450
|
const name = tool.toolName ?? "<tool>";
|
|
32332
32451
|
if (name === "command_execution") {
|
|
32452
|
+
const rawCommand = getCommandExecutionRawCommand(tool);
|
|
32453
|
+
const exploredLines = rawCommand ? getExploredCommandLines(rawCommand) : void 0;
|
|
32454
|
+
if (exploredLines && exploredLines.length > 1) return cyan(exploredLines[0] ?? "Explored", style);
|
|
32333
32455
|
const display = getCommandExecutionDisplayCommand(tool) ?? "(unknown command)";
|
|
32334
|
-
return `${bold("$", style)} ${
|
|
32456
|
+
return `${bold("$", style)} ${colorizeCommandProgram(display, style)}`;
|
|
32335
32457
|
}
|
|
32336
32458
|
const renderedName = bold(name, style);
|
|
32337
32459
|
if (!tool.title) return renderedName;
|
|
@@ -32346,45 +32468,56 @@ function formatToolSummaryLine(tool, style) {
|
|
|
32346
32468
|
default: return `${yellow("…", style)} ${label} (${id})`;
|
|
32347
32469
|
}
|
|
32348
32470
|
}
|
|
32349
|
-
function
|
|
32350
|
-
|
|
32471
|
+
function getToolStatus(value) {
|
|
32472
|
+
if (value === "completed" || value === "failed") return value;
|
|
32473
|
+
return "in_progress";
|
|
32351
32474
|
}
|
|
32352
|
-
function
|
|
32353
|
-
const
|
|
32354
|
-
if (
|
|
32355
|
-
if (
|
|
32356
|
-
|
|
32357
|
-
|
|
32358
|
-
|
|
32359
|
-
|
|
32360
|
-
|
|
32361
|
-
|
|
32362
|
-
|
|
32363
|
-
|
|
32364
|
-
|
|
32365
|
-
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
|
|
32370
|
-
|
|
32371
|
-
|
|
32372
|
-
|
|
32373
|
-
|
|
32374
|
-
|
|
32475
|
+
function combineToolStatuses(statuses) {
|
|
32476
|
+
const normalized = statuses.map((status) => getToolStatus(status));
|
|
32477
|
+
if (normalized.some((status) => status === "failed")) return "failed";
|
|
32478
|
+
if (normalized.some((status) => status === "in_progress")) return "in_progress";
|
|
32479
|
+
return "completed";
|
|
32480
|
+
}
|
|
32481
|
+
function formatToolStatusIcon(status, style) {
|
|
32482
|
+
switch (getToolStatus(status)) {
|
|
32483
|
+
case "completed": return green("✓", style);
|
|
32484
|
+
case "failed": return red("✗", style);
|
|
32485
|
+
default: return yellow("…", style);
|
|
32486
|
+
}
|
|
32487
|
+
}
|
|
32488
|
+
function getExploredSubCommandLines(tool) {
|
|
32489
|
+
if (tool.toolName !== "command_execution") return void 0;
|
|
32490
|
+
const rawCommand = getCommandExecutionRawCommand(tool);
|
|
32491
|
+
if (!rawCommand) return void 0;
|
|
32492
|
+
const exploredLines = getExploredCommandLines(rawCommand);
|
|
32493
|
+
if (!exploredLines || exploredLines.length <= 1) return void 0;
|
|
32494
|
+
return exploredLines.slice(1);
|
|
32495
|
+
}
|
|
32496
|
+
function formatExploredSubCommandLine(line, style) {
|
|
32497
|
+
if (line.startsWith("Search ")) {
|
|
32498
|
+
const payload = line.slice(7);
|
|
32499
|
+
const at = payload.lastIndexOf(" in ");
|
|
32500
|
+
if (at !== -1) {
|
|
32501
|
+
const terms = payload.slice(0, at);
|
|
32502
|
+
const file = payload.slice(at + 4);
|
|
32503
|
+
return `${cyan("Search", style)} ${terms} ${dimGray("in", style)} ${file}`;
|
|
32375
32504
|
}
|
|
32376
|
-
|
|
32377
|
-
current = "";
|
|
32378
|
-
if (word.length <= width) current = word;
|
|
32379
|
-
else pushLongWord(word);
|
|
32505
|
+
return `${cyan("Search", style)} ${payload}`;
|
|
32380
32506
|
}
|
|
32381
|
-
if (
|
|
32382
|
-
return
|
|
32507
|
+
if (line.startsWith("Read ")) return `${cyan("Read", style)} ${line.slice(5)}`;
|
|
32508
|
+
if (line === "List") return cyan("List", style);
|
|
32509
|
+
if (line.startsWith("List ")) return `${cyan("List", style)} ${line.slice(5)}`;
|
|
32510
|
+
return line;
|
|
32383
32511
|
}
|
|
32384
|
-
function
|
|
32385
|
-
|
|
32386
|
-
|
|
32387
|
-
|
|
32512
|
+
function toDisplayLines(text) {
|
|
32513
|
+
return text.replaceAll("\r\n", "\n").split("\n");
|
|
32514
|
+
}
|
|
32515
|
+
function wrapRawLineToWidth(line, width) {
|
|
32516
|
+
if (width <= 0) return [line];
|
|
32517
|
+
if (line.length === 0) return [""];
|
|
32518
|
+
const out = [];
|
|
32519
|
+
for (let i = 0; i < line.length; i += width) out.push(line.slice(i, i + width));
|
|
32520
|
+
return out;
|
|
32388
32521
|
}
|
|
32389
32522
|
function trimLinesWithEllipsis(lines, maxLines) {
|
|
32390
32523
|
if (maxLines <= 0) return [];
|
|
@@ -32395,14 +32528,34 @@ function trimLinesWithEllipsis(lines, maxLines) {
|
|
|
32395
32528
|
kept[lastIndex] = last ? `${last}…` : "…";
|
|
32396
32529
|
return kept;
|
|
32397
32530
|
}
|
|
32531
|
+
function trimCommandOutputTopBottom(lines) {
|
|
32532
|
+
if (lines.length <= 4) return lines;
|
|
32533
|
+
const hidden = lines.length - 4;
|
|
32534
|
+
return [
|
|
32535
|
+
lines[0],
|
|
32536
|
+
lines[1],
|
|
32537
|
+
`… +${hidden} lines`,
|
|
32538
|
+
lines[lines.length - 2],
|
|
32539
|
+
lines[lines.length - 1]
|
|
32540
|
+
];
|
|
32541
|
+
}
|
|
32398
32542
|
function formatToolResultPreviewLines(tool, options) {
|
|
32399
32543
|
if (tool.status === "in_progress") return [];
|
|
32400
32544
|
if (options.maxLines <= 0) return [];
|
|
32401
|
-
if (tool.
|
|
32545
|
+
if (tool.toolName === "command_execution") {
|
|
32546
|
+
const rawCommand = getCommandExecutionRawCommand(tool);
|
|
32547
|
+
if (rawCommand && isExploredCommandExecution(rawCommand)) return [];
|
|
32548
|
+
}
|
|
32549
|
+
if (tool.status === "failed") {
|
|
32550
|
+
const lines = toDisplayLines(tool.errorText ?? "(no error text)");
|
|
32551
|
+
return trimLinesWithEllipsis(tool.toolName === "command_execution" ? trimCommandOutputTopBottom(lines) : lines, options.maxLines);
|
|
32552
|
+
}
|
|
32402
32553
|
if (tool.output == null) return ["(none)"];
|
|
32403
32554
|
if (tool.toolName === "command_execution") {
|
|
32404
32555
|
const output = tool.output;
|
|
32405
|
-
|
|
32556
|
+
const allLines = toDisplayLines((typeof output?.aggregated_output === "string" ? output.aggregated_output : "").trimEnd());
|
|
32557
|
+
if (!allLines.some((line) => line.length > 0)) return ["(none)"];
|
|
32558
|
+
return trimLinesWithEllipsis(trimCommandOutputTopBottom(allLines), options.maxLines);
|
|
32406
32559
|
}
|
|
32407
32560
|
return trimLinesWithEllipsis(toDisplayLines(inspect(tool.output, {
|
|
32408
32561
|
depth: 6,
|
|
@@ -32442,8 +32595,59 @@ function clip(value, maxVisible) {
|
|
|
32442
32595
|
const sliced = sliceSgrByVisibleWidth(value, maxVisible - 1);
|
|
32443
32596
|
return `${sliced}…${sliced.includes("\x1B[") ? ANSI.reset : ""}`;
|
|
32444
32597
|
}
|
|
32598
|
+
const TODO_PREVIEW_MAX_ITEMS = 3;
|
|
32599
|
+
const TODO_PREVIEW_MAX_PENDING = 2;
|
|
32600
|
+
function selectTodoPreviewItems(todoItems, options) {
|
|
32601
|
+
const selected = [];
|
|
32602
|
+
let pendingCount = 0;
|
|
32603
|
+
for (let index = todoItems.length - 1; index >= 0; index--) {
|
|
32604
|
+
const item = todoItems[index];
|
|
32605
|
+
if (selected.length >= options.maxItems) break;
|
|
32606
|
+
if (!item.completed && pendingCount >= options.maxPending) continue;
|
|
32607
|
+
selected.push({
|
|
32608
|
+
ordinal: index + 1,
|
|
32609
|
+
item
|
|
32610
|
+
});
|
|
32611
|
+
if (!item.completed) pendingCount += 1;
|
|
32612
|
+
}
|
|
32613
|
+
selected.reverse();
|
|
32614
|
+
return selected;
|
|
32615
|
+
}
|
|
32616
|
+
function wrapTodoItemLine(entry, widthHint) {
|
|
32617
|
+
const { ordinal, item } = entry;
|
|
32618
|
+
const normalizedText = item.text.trim().replaceAll(/\s+/g, " ") || "(empty)";
|
|
32619
|
+
const prefix = `${ordinal}. ${item.completed ? "[x]" : "[ ]"} `;
|
|
32620
|
+
return wrapRawLineToWidth(normalizedText, Math.max(1, widthHint - prefix.length)).map((chunk, chunkIndex) => chunkIndex === 0 ? `${prefix}${chunk}` : `${" ".repeat(prefix.length)}${chunk}`);
|
|
32621
|
+
}
|
|
32622
|
+
function trimLinesToHeight(lines, maxLines, style) {
|
|
32623
|
+
if (maxLines <= 0) return [];
|
|
32624
|
+
if (lines.length <= maxLines) return lines;
|
|
32625
|
+
if (maxLines === 1) return [dimGray(`… +${lines.length} more lines`, style)];
|
|
32626
|
+
const kept = lines.slice(0, maxLines - 1);
|
|
32627
|
+
const hidden = lines.length - kept.length;
|
|
32628
|
+
kept.push(dimGray(`… +${hidden} more lines`, style));
|
|
32629
|
+
return kept;
|
|
32630
|
+
}
|
|
32631
|
+
function formatTodoPanelLines(options) {
|
|
32632
|
+
if (options.todoItems.length === 0) return [];
|
|
32633
|
+
const selectedEntries = options.fullView ? options.todoItems.map((item, index) => ({
|
|
32634
|
+
ordinal: index + 1,
|
|
32635
|
+
item
|
|
32636
|
+
})) : selectTodoPreviewItems(options.todoItems, {
|
|
32637
|
+
maxItems: TODO_PREVIEW_MAX_ITEMS,
|
|
32638
|
+
maxPending: TODO_PREVIEW_MAX_PENDING
|
|
32639
|
+
});
|
|
32640
|
+
const lines = [bold("todos", options.style)];
|
|
32641
|
+
selectedEntries.forEach((entry) => lines.push(...wrapTodoItemLine(entry, Math.max(1, options.widthHint))));
|
|
32642
|
+
if (!options.fullView && selectedEntries.length < options.todoItems.length) {
|
|
32643
|
+
const hidden = options.todoItems.length - selectedEntries.length;
|
|
32644
|
+
lines.push(dimGray(`… +${hidden} more todos (t for full)`, options.style));
|
|
32645
|
+
}
|
|
32646
|
+
lines.push(dimGray("─".repeat(Math.max(1, options.widthHint)), options.style));
|
|
32647
|
+
return lines;
|
|
32648
|
+
}
|
|
32445
32649
|
function createWatchCommand(version) {
|
|
32446
|
-
return createCommand("watch").version(version).description("Inspect task progress via live stream data (internal tooling).").option("--tasks <ids>", "Comma-separated task IDs to watch.", parseCommaList, []).option("--agents <names>", "Comma-separated agent names to watch.", parseCommaList, []).option("--
|
|
32650
|
+
return createCommand("watch").version(version).description("Inspect task progress via live stream data (internal tooling).").option("--tasks <ids>", "Comma-separated task IDs to watch.", parseCommaList, []).option("--agents <names>", "Comma-separated agent names to watch.", parseCommaList, []).option("--list-width <cols>", "Left task-list width in columns (default: 32).", parseListWidth, 32).action(async function() {
|
|
32447
32651
|
ensureEnvOrExit(["PANTHEON_API_KEY", "DATABASE_URL"]);
|
|
32448
32652
|
const options = this.opts();
|
|
32449
32653
|
if (options.tasks.length > 0 && options.agents.length > 0) {
|
|
@@ -32471,9 +32675,20 @@ function createWatchCommand(version) {
|
|
|
32471
32675
|
process.on("SIGINT", onSigInt);
|
|
32472
32676
|
const runtime = targets.map((target) => ({
|
|
32473
32677
|
target,
|
|
32474
|
-
aggregator: new WatchStepAggregator({ maxLogLines:
|
|
32678
|
+
aggregator: new WatchStepAggregator({ maxLogLines: Number.POSITIVE_INFINITY }),
|
|
32475
32679
|
streamDone: false
|
|
32476
32680
|
}));
|
|
32681
|
+
const logViewportByTaskId = /* @__PURE__ */ new Map();
|
|
32682
|
+
function getLogViewport(taskId) {
|
|
32683
|
+
const existing = logViewportByTaskId.get(taskId);
|
|
32684
|
+
if (existing) return existing;
|
|
32685
|
+
const created = {
|
|
32686
|
+
autoFollow: true,
|
|
32687
|
+
scrollOffset: 0
|
|
32688
|
+
};
|
|
32689
|
+
logViewportByTaskId.set(taskId, created);
|
|
32690
|
+
return created;
|
|
32691
|
+
}
|
|
32477
32692
|
async function startStream(rt, streamId) {
|
|
32478
32693
|
rt.streamAbort?.abort();
|
|
32479
32694
|
rt.streamAbort = new AbortController();
|
|
@@ -32509,7 +32724,7 @@ function createWatchCommand(version) {
|
|
|
32509
32724
|
normalizer = createAgentStreamNormalizer({
|
|
32510
32725
|
source: rt.source,
|
|
32511
32726
|
emitStartChunk: false,
|
|
32512
|
-
includeMetaEvents:
|
|
32727
|
+
includeMetaEvents: true,
|
|
32513
32728
|
unknownChunkPolicy: "emit"
|
|
32514
32729
|
});
|
|
32515
32730
|
}
|
|
@@ -32544,7 +32759,10 @@ function createWatchCommand(version) {
|
|
|
32544
32759
|
const nextStreamId = branch.latest_snap?.event_stream_id ?? void 0;
|
|
32545
32760
|
if (nextStreamId && nextStreamId !== rt.streamId) {
|
|
32546
32761
|
rt.streamId = nextStreamId;
|
|
32547
|
-
rt.aggregator = new WatchStepAggregator({ maxLogLines:
|
|
32762
|
+
rt.aggregator = new WatchStepAggregator({ maxLogLines: Number.POSITIVE_INFINITY });
|
|
32763
|
+
const viewport = getLogViewport(rt.target.task.id);
|
|
32764
|
+
viewport.autoFollow = true;
|
|
32765
|
+
viewport.scrollOffset = 0;
|
|
32548
32766
|
await startStream(rt, nextStreamId);
|
|
32549
32767
|
}
|
|
32550
32768
|
} catch (error) {
|
|
@@ -32557,7 +32775,7 @@ function createWatchCommand(version) {
|
|
|
32557
32775
|
title: "pantheon-agents watch"
|
|
32558
32776
|
});
|
|
32559
32777
|
screen.key(["q", "C-c"], () => abortController.abort());
|
|
32560
|
-
const
|
|
32778
|
+
const globalFooter = blessed.box({
|
|
32561
32779
|
parent: screen,
|
|
32562
32780
|
bottom: 0,
|
|
32563
32781
|
left: 0,
|
|
@@ -32567,108 +32785,325 @@ function createWatchCommand(version) {
|
|
|
32567
32785
|
content: "Ctrl+C to exit • q to quit",
|
|
32568
32786
|
style: { fg: "gray" }
|
|
32569
32787
|
});
|
|
32570
|
-
const
|
|
32788
|
+
const taskListPane = blessed.list({
|
|
32571
32789
|
parent: screen,
|
|
32572
32790
|
top: 0,
|
|
32573
32791
|
left: 0,
|
|
32574
32792
|
height: "100%-1",
|
|
32575
|
-
width:
|
|
32793
|
+
width: options.listWidth,
|
|
32794
|
+
border: "line",
|
|
32795
|
+
tags: false,
|
|
32796
|
+
wrap: false,
|
|
32797
|
+
keys: false,
|
|
32798
|
+
vi: false,
|
|
32799
|
+
mouse: false,
|
|
32800
|
+
style: {
|
|
32801
|
+
border: { fg: "cyan" },
|
|
32802
|
+
selected: {
|
|
32803
|
+
fg: "black",
|
|
32804
|
+
bg: "cyan"
|
|
32805
|
+
},
|
|
32806
|
+
item: { fg: "white" }
|
|
32807
|
+
}
|
|
32808
|
+
});
|
|
32809
|
+
const rightPane = blessed.box({
|
|
32810
|
+
parent: screen,
|
|
32811
|
+
top: 0,
|
|
32812
|
+
left: options.listWidth,
|
|
32813
|
+
height: "100%-1",
|
|
32814
|
+
width: `100%-${options.listWidth}`,
|
|
32576
32815
|
border: "line",
|
|
32577
32816
|
tags: false,
|
|
32578
|
-
scrollable: false,
|
|
32579
32817
|
wrap: false,
|
|
32580
32818
|
style: { border: { fg: "gray" } }
|
|
32581
|
-
})
|
|
32819
|
+
});
|
|
32820
|
+
const rightHeader = blessed.box({
|
|
32821
|
+
parent: rightPane,
|
|
32822
|
+
top: 0,
|
|
32823
|
+
left: 1,
|
|
32824
|
+
height: 2,
|
|
32825
|
+
width: "100%-2",
|
|
32826
|
+
tags: false,
|
|
32827
|
+
wrap: false
|
|
32828
|
+
});
|
|
32829
|
+
const rightBody = blessed.box({
|
|
32830
|
+
parent: rightPane,
|
|
32831
|
+
top: 2,
|
|
32832
|
+
left: 1,
|
|
32833
|
+
width: "100%-2",
|
|
32834
|
+
height: 1,
|
|
32835
|
+
tags: false,
|
|
32836
|
+
wrap: false,
|
|
32837
|
+
scrollable: false
|
|
32838
|
+
});
|
|
32839
|
+
const rightFooter = blessed.box({
|
|
32840
|
+
parent: rightPane,
|
|
32841
|
+
left: 1,
|
|
32842
|
+
height: 1,
|
|
32843
|
+
width: "100%-2",
|
|
32844
|
+
tags: false,
|
|
32845
|
+
wrap: false,
|
|
32846
|
+
style: { fg: "gray" }
|
|
32847
|
+
});
|
|
32582
32848
|
let lastGlobalError;
|
|
32583
|
-
|
|
32584
|
-
|
|
32585
|
-
|
|
32586
|
-
|
|
32587
|
-
|
|
32588
|
-
|
|
32589
|
-
|
|
32590
|
-
|
|
32591
|
-
|
|
32592
|
-
|
|
32593
|
-
|
|
32594
|
-
|
|
32595
|
-
|
|
32596
|
-
|
|
32597
|
-
|
|
32849
|
+
let selectedIndex = 0;
|
|
32850
|
+
let focus = "list";
|
|
32851
|
+
let showFullTodoList = false;
|
|
32852
|
+
function normalizeTaskText(taskText) {
|
|
32853
|
+
return taskText.trim().replaceAll(/\s+/g, " ");
|
|
32854
|
+
}
|
|
32855
|
+
function getSelectedRuntimeTask() {
|
|
32856
|
+
if (selectedIndex < 0) selectedIndex = 0;
|
|
32857
|
+
if (selectedIndex >= runtime.length) selectedIndex = runtime.length - 1;
|
|
32858
|
+
return runtime[selectedIndex];
|
|
32859
|
+
}
|
|
32860
|
+
function getFormattedLogLines(rt, options) {
|
|
32861
|
+
const step = rt.aggregator.snapshot();
|
|
32862
|
+
const blocks = [];
|
|
32863
|
+
const reasoningWrapWidth = Math.max(1, options.widthHint);
|
|
32864
|
+
const messageWrapWidth = Math.max(1, options.widthHint);
|
|
32865
|
+
const toolById = new Map(step.toolActions.map((tool) => [tool.toolCallId, tool]));
|
|
32866
|
+
function pushBlock(order, lines) {
|
|
32867
|
+
if (lines.length === 0) return;
|
|
32868
|
+
blocks.push({
|
|
32869
|
+
order: order ?? Number.MAX_SAFE_INTEGER,
|
|
32870
|
+
lines
|
|
32871
|
+
});
|
|
32872
|
+
}
|
|
32873
|
+
for (let timelineIndex = 0; timelineIndex < step.timeline.length; timelineIndex++) {
|
|
32874
|
+
const entry = step.timeline[timelineIndex];
|
|
32875
|
+
if (entry.kind === "reasoning") {
|
|
32876
|
+
const reasoningBlock = [];
|
|
32877
|
+
const hasTrailingLineFeed = entry.text.endsWith("\n");
|
|
32878
|
+
const rawReasoningLines = toDisplayLines(entry.text);
|
|
32879
|
+
for (const rawLine of rawReasoningLines) wrapRawLineToWidth(rawLine, reasoningWrapWidth).forEach((chunk) => reasoningBlock.push(gray(chunk, options.style)));
|
|
32880
|
+
if (!hasTrailingLineFeed) reasoningBlock.push("");
|
|
32881
|
+
pushBlock(entry.order, reasoningBlock);
|
|
32882
|
+
continue;
|
|
32883
|
+
}
|
|
32884
|
+
if (entry.kind === "message") {
|
|
32885
|
+
const messageBlock = [];
|
|
32886
|
+
const rawMessageLines = toDisplayLines(entry.text);
|
|
32887
|
+
for (const rawLine of rawMessageLines) wrapRawLineToWidth(rawLine, messageWrapWidth).forEach((chunk) => messageBlock.push(chunk));
|
|
32888
|
+
pushBlock(entry.order, messageBlock);
|
|
32598
32889
|
continue;
|
|
32599
32890
|
}
|
|
32600
|
-
|
|
32601
|
-
|
|
32602
|
-
|
|
32603
|
-
|
|
32604
|
-
const
|
|
32605
|
-
|
|
32606
|
-
|
|
32607
|
-
|
|
32608
|
-
|
|
32609
|
-
|
|
32610
|
-
|
|
32891
|
+
if (entry.kind === "warning") {
|
|
32892
|
+
pushBlock(entry.order, [kv("warning", yellow(entry.message, options.style), options.style)]);
|
|
32893
|
+
continue;
|
|
32894
|
+
}
|
|
32895
|
+
const tool = toolById.get(entry.toolCallId);
|
|
32896
|
+
if (!tool) continue;
|
|
32897
|
+
const exploredSubLines = getExploredSubCommandLines(tool);
|
|
32898
|
+
if (exploredSubLines != null) {
|
|
32899
|
+
const groupedTools = [tool];
|
|
32900
|
+
const groupedSubLines = [...exploredSubLines];
|
|
32901
|
+
let lookahead = timelineIndex + 1;
|
|
32902
|
+
while (lookahead < step.timeline.length) {
|
|
32903
|
+
const next = step.timeline[lookahead];
|
|
32904
|
+
if (next.kind !== "tool") break;
|
|
32905
|
+
const nextTool = toolById.get(next.toolCallId);
|
|
32906
|
+
if (!nextTool) break;
|
|
32907
|
+
const nextSubLines = getExploredSubCommandLines(nextTool);
|
|
32908
|
+
if (nextSubLines == null) break;
|
|
32909
|
+
groupedTools.push(nextTool);
|
|
32910
|
+
groupedSubLines.push(...nextSubLines);
|
|
32911
|
+
lookahead += 1;
|
|
32912
|
+
}
|
|
32913
|
+
const groupedBlock = [` ${[
|
|
32914
|
+
formatToolStatusIcon(combineToolStatuses(groupedTools.map((groupedTool) => groupedTool.status)), options.style),
|
|
32915
|
+
cyan("Explored", options.style),
|
|
32916
|
+
groupedTools.length > 1 ? gray(`x${groupedTools.length}`, options.style) : void 0
|
|
32917
|
+
].filter(Boolean).join(" ")}`];
|
|
32918
|
+
groupedSubLines.forEach((subLine, subIndex) => groupedBlock.push(subIndex === 0 ? ` ${dimGray("└", options.style)} ${formatExploredSubCommandLine(subLine, options.style)}` : ` ${formatExploredSubCommandLine(subLine, options.style)}`));
|
|
32919
|
+
pushBlock(entry.order, groupedBlock);
|
|
32920
|
+
timelineIndex = lookahead - 1;
|
|
32921
|
+
continue;
|
|
32922
|
+
}
|
|
32923
|
+
const toolBlock = [];
|
|
32924
|
+
toDisplayLines(formatToolSummaryLine(tool, options.style)).forEach((line, index) => toolBlock.push(index === 0 ? ` ${line}` : ` ${line}`));
|
|
32925
|
+
if (tool.toolName === "command_execution") formatToolResultPreviewLines(tool, {
|
|
32926
|
+
maxLines: Number.MAX_SAFE_INTEGER,
|
|
32927
|
+
widthHint: Math.max(20, options.widthHint - 10),
|
|
32928
|
+
style: options.style
|
|
32929
|
+
}).forEach((line, index) => toolBlock.push(index === 0 ? ` ${dimGray("└", options.style)} ${dimGray(line, options.style)}` : ` ${dimGray(line, options.style)}`));
|
|
32930
|
+
pushBlock(entry.order, toolBlock);
|
|
32611
32931
|
}
|
|
32612
|
-
|
|
32613
|
-
|
|
32614
|
-
|
|
32615
|
-
|
|
32932
|
+
if (rt.lastError) pushBlock(void 0, [kv("error", red(rt.lastError, options.style), options.style)]);
|
|
32933
|
+
blocks.sort((a, b) => a.order - b.order);
|
|
32934
|
+
const lines = [];
|
|
32935
|
+
for (const block of blocks) {
|
|
32936
|
+
if (lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
|
|
32937
|
+
lines.push(...block.lines);
|
|
32938
|
+
}
|
|
32939
|
+
if (lines.length === 0) lines.push(gray("(waiting for formatted stream output)", options.style));
|
|
32940
|
+
return lines;
|
|
32941
|
+
}
|
|
32942
|
+
function moveTaskSelection(delta) {
|
|
32943
|
+
if (runtime.length === 0) return;
|
|
32944
|
+
selectedIndex = Math.max(0, Math.min(runtime.length - 1, selectedIndex + delta));
|
|
32945
|
+
}
|
|
32946
|
+
function scrollSelectedLog(delta) {
|
|
32947
|
+
const selected = getSelectedRuntimeTask();
|
|
32948
|
+
const viewport = getLogViewport(selected.target.task.id);
|
|
32949
|
+
const bodyHeight = typeof rightBody.height === "number" ? rightBody.height : 0;
|
|
32950
|
+
if (bodyHeight <= 0) return;
|
|
32951
|
+
const bodyWidth = typeof rightBody.width === "number" ? rightBody.width : 80;
|
|
32952
|
+
const lines = getFormattedLogLines(selected, {
|
|
32953
|
+
style: useAnsiStyles(),
|
|
32954
|
+
widthHint: Math.max(20, bodyWidth)
|
|
32955
|
+
});
|
|
32956
|
+
const maxOffset = Math.max(0, lines.length - bodyHeight);
|
|
32957
|
+
viewport.autoFollow = false;
|
|
32958
|
+
viewport.scrollOffset = Math.max(0, Math.min(maxOffset, viewport.scrollOffset + delta));
|
|
32959
|
+
}
|
|
32960
|
+
function scrollSelectedLogToTop() {
|
|
32961
|
+
const viewport = getLogViewport(getSelectedRuntimeTask().target.task.id);
|
|
32962
|
+
viewport.autoFollow = false;
|
|
32963
|
+
viewport.scrollOffset = 0;
|
|
32964
|
+
}
|
|
32965
|
+
function scrollSelectedLogToBottom() {
|
|
32966
|
+
const selected = getSelectedRuntimeTask();
|
|
32967
|
+
const viewport = getLogViewport(selected.target.task.id);
|
|
32968
|
+
const bodyHeight = typeof rightBody.height === "number" ? rightBody.height : 0;
|
|
32969
|
+
if (bodyHeight <= 0) return;
|
|
32970
|
+
const bodyWidth = typeof rightBody.width === "number" ? rightBody.width : 80;
|
|
32971
|
+
const lines = getFormattedLogLines(selected, {
|
|
32972
|
+
style: useAnsiStyles(),
|
|
32973
|
+
widthHint: Math.max(20, bodyWidth)
|
|
32974
|
+
});
|
|
32975
|
+
const maxOffset = Math.max(0, lines.length - bodyHeight);
|
|
32976
|
+
viewport.autoFollow = false;
|
|
32977
|
+
viewport.scrollOffset = maxOffset;
|
|
32978
|
+
}
|
|
32979
|
+
function getHalfScreenScrollStep() {
|
|
32980
|
+
const bodyHeight = typeof rightBody.height === "number" ? rightBody.height : 0;
|
|
32981
|
+
return Math.max(1, Math.floor(bodyHeight / 2));
|
|
32616
32982
|
}
|
|
32983
|
+
function resumeAutoFollowForSelectedLog() {
|
|
32984
|
+
const viewport = getLogViewport(getSelectedRuntimeTask().target.task.id);
|
|
32985
|
+
viewport.autoFollow = true;
|
|
32986
|
+
}
|
|
32987
|
+
screen.key(["left"], () => {
|
|
32988
|
+
focus = "list";
|
|
32989
|
+
});
|
|
32990
|
+
screen.key(["right"], () => {
|
|
32991
|
+
focus = "log";
|
|
32992
|
+
});
|
|
32993
|
+
screen.key(["up"], () => {
|
|
32994
|
+
if (focus === "list") moveTaskSelection(-1);
|
|
32995
|
+
else scrollSelectedLog(-getHalfScreenScrollStep());
|
|
32996
|
+
});
|
|
32997
|
+
screen.key(["down"], () => {
|
|
32998
|
+
if (focus === "list") moveTaskSelection(1);
|
|
32999
|
+
else scrollSelectedLog(getHalfScreenScrollStep());
|
|
33000
|
+
});
|
|
33001
|
+
screen.key(["g", "home"], () => {
|
|
33002
|
+
if (focus !== "log") return;
|
|
33003
|
+
scrollSelectedLogToTop();
|
|
33004
|
+
});
|
|
33005
|
+
screen.key([
|
|
33006
|
+
"G",
|
|
33007
|
+
"S-g",
|
|
33008
|
+
"end"
|
|
33009
|
+
], () => {
|
|
33010
|
+
if (focus !== "log") return;
|
|
33011
|
+
scrollSelectedLogToBottom();
|
|
33012
|
+
});
|
|
33013
|
+
screen.key(["f"], () => {
|
|
33014
|
+
resumeAutoFollowForSelectedLog();
|
|
33015
|
+
});
|
|
33016
|
+
screen.key(["t"], () => {
|
|
33017
|
+
showFullTodoList = !showFullTodoList;
|
|
33018
|
+
});
|
|
32617
33019
|
const renderTimer = setInterval(() => {
|
|
32618
33020
|
const style = useAnsiStyles();
|
|
32619
33021
|
const columns = Math.max(40, screen.width ?? 120);
|
|
32620
|
-
const
|
|
32621
|
-
const
|
|
32622
|
-
|
|
32623
|
-
|
|
32624
|
-
|
|
32625
|
-
|
|
32626
|
-
|
|
32627
|
-
|
|
32628
|
-
|
|
32629
|
-
|
|
32630
|
-
|
|
32631
|
-
|
|
32632
|
-
|
|
32633
|
-
|
|
32634
|
-
|
|
32635
|
-
|
|
32636
|
-
|
|
32637
|
-
|
|
32638
|
-
|
|
32639
|
-
|
|
32640
|
-
|
|
32641
|
-
|
|
32642
|
-
|
|
32643
|
-
|
|
32644
|
-
|
|
32645
|
-
|
|
32646
|
-
|
|
32647
|
-
|
|
32648
|
-
|
|
32649
|
-
|
|
32650
|
-
|
|
32651
|
-
|
|
32652
|
-
|
|
32653
|
-
|
|
32654
|
-
|
|
32655
|
-
|
|
32656
|
-
|
|
32657
|
-
|
|
32658
|
-
|
|
32659
|
-
|
|
32660
|
-
|
|
32661
|
-
|
|
32662
|
-
|
|
32663
|
-
|
|
32664
|
-
|
|
32665
|
-
|
|
32666
|
-
|
|
32667
|
-
|
|
32668
|
-
|
|
32669
|
-
|
|
32670
|
-
pane.setContent(baseLines.map((line) => clip(line, paneInnerWidth)).join("\n"));
|
|
33022
|
+
const rows = Math.max(8, screen.height ?? 24);
|
|
33023
|
+
const contentHeight = Math.max(1, rows - 1);
|
|
33024
|
+
const minListWidth = 12;
|
|
33025
|
+
const maxListWidth = Math.max(minListWidth, columns - 24);
|
|
33026
|
+
const listWidth = Math.min(Math.max(minListWidth, options.listWidth), maxListWidth);
|
|
33027
|
+
const rightPaneWidth = Math.max(1, columns - listWidth);
|
|
33028
|
+
taskListPane.top = 0;
|
|
33029
|
+
taskListPane.left = 0;
|
|
33030
|
+
taskListPane.width = listWidth;
|
|
33031
|
+
taskListPane.height = contentHeight;
|
|
33032
|
+
taskListPane.setLabel(" Tasks ");
|
|
33033
|
+
taskListPane.style.border = { fg: focus === "list" ? "cyan" : "gray" };
|
|
33034
|
+
rightPane.top = 0;
|
|
33035
|
+
rightPane.left = listWidth;
|
|
33036
|
+
rightPane.width = rightPaneWidth;
|
|
33037
|
+
rightPane.height = contentHeight;
|
|
33038
|
+
rightPane.style.border = { fg: focus === "log" ? "cyan" : "gray" };
|
|
33039
|
+
const selected = getSelectedRuntimeTask();
|
|
33040
|
+
const selectedTaskId = selected.target.task.id;
|
|
33041
|
+
const viewport = getLogViewport(selectedTaskId);
|
|
33042
|
+
const snapshot = selected.aggregator.snapshot();
|
|
33043
|
+
const paneInnerWidth = Math.max(1, rightPaneWidth - 2);
|
|
33044
|
+
const paneInnerHeight = Math.max(1, contentHeight - 2);
|
|
33045
|
+
const headerHeight = Math.min(2, paneInnerHeight);
|
|
33046
|
+
const maxRightFooterHeight = Math.max(0, paneInnerHeight - headerHeight);
|
|
33047
|
+
const visibleTodoPanelLines = trimLinesToHeight(formatTodoPanelLines({
|
|
33048
|
+
todoItems: snapshot.todoItems,
|
|
33049
|
+
fullView: showFullTodoList,
|
|
33050
|
+
widthHint: paneInnerWidth,
|
|
33051
|
+
style
|
|
33052
|
+
}), maxRightFooterHeight, style);
|
|
33053
|
+
const rightFooterHeight = visibleTodoPanelLines.length;
|
|
33054
|
+
const bodyHeight = Math.max(0, paneInnerHeight - headerHeight - rightFooterHeight);
|
|
33055
|
+
const listInnerWidth = Math.max(1, listWidth - 2);
|
|
33056
|
+
const taskListItems = runtime.map((rt) => clip(`${rt.target.agent}: ${normalizeTaskText(rt.target.task.task)}`, listInnerWidth));
|
|
33057
|
+
taskListPane.setItems(taskListItems);
|
|
33058
|
+
taskListPane.select(selectedIndex);
|
|
33059
|
+
rightPane.setLabel(` ${selected.target.agent} `);
|
|
33060
|
+
rightHeader.top = 0;
|
|
33061
|
+
rightHeader.left = 1;
|
|
33062
|
+
rightHeader.width = paneInnerWidth;
|
|
33063
|
+
rightHeader.height = headerHeight;
|
|
33064
|
+
rightHeader.show();
|
|
33065
|
+
const latestSnapId = selected.branch?.latest_snap_id ?? "(none)";
|
|
33066
|
+
const streamId = selected.streamId ?? selected.branch?.latest_snap?.event_stream_id ?? "(none)";
|
|
33067
|
+
const headerLines = [clip(`project id: ${selected.target.task.project_id} • task id: ${selected.target.task.id} • latest snap id: ${latestSnapId}`, paneInnerWidth), clip(`stream id: ${streamId}`, paneInnerWidth)];
|
|
33068
|
+
rightHeader.setContent(headerLines.slice(0, headerHeight).join("\n"));
|
|
33069
|
+
const formattedLogLines = getFormattedLogLines(selected, {
|
|
33070
|
+
style,
|
|
33071
|
+
widthHint: paneInnerWidth
|
|
32671
33072
|
});
|
|
33073
|
+
const maxOffset = Math.max(0, formattedLogLines.length - bodyHeight);
|
|
33074
|
+
if (viewport.autoFollow) viewport.scrollOffset = maxOffset;
|
|
33075
|
+
else viewport.scrollOffset = Math.max(0, Math.min(maxOffset, viewport.scrollOffset));
|
|
33076
|
+
rightBody.top = headerHeight + rightFooterHeight;
|
|
33077
|
+
rightBody.left = 1;
|
|
33078
|
+
rightBody.width = paneInnerWidth;
|
|
33079
|
+
rightBody.height = bodyHeight;
|
|
33080
|
+
if (bodyHeight <= 0) rightBody.hide();
|
|
33081
|
+
else {
|
|
33082
|
+
const visibleLines = formattedLogLines.slice(viewport.scrollOffset, viewport.scrollOffset + bodyHeight);
|
|
33083
|
+
rightBody.setContent(visibleLines.map((line) => clip(line, paneInnerWidth)).join("\n"));
|
|
33084
|
+
rightBody.show();
|
|
33085
|
+
}
|
|
33086
|
+
rightFooter.top = headerHeight;
|
|
33087
|
+
rightFooter.left = 1;
|
|
33088
|
+
rightFooter.width = paneInnerWidth;
|
|
33089
|
+
rightFooter.height = rightFooterHeight;
|
|
33090
|
+
if (rightFooterHeight <= 0) rightFooter.hide();
|
|
33091
|
+
else {
|
|
33092
|
+
rightFooter.setContent(visibleTodoPanelLines.map((line) => clip(line, paneInnerWidth)).join("\n"));
|
|
33093
|
+
rightFooter.show();
|
|
33094
|
+
}
|
|
33095
|
+
const footerParts = [
|
|
33096
|
+
"Ctrl+C to exit",
|
|
33097
|
+
"q to quit",
|
|
33098
|
+
"←/→ focus",
|
|
33099
|
+
focus === "list" ? "↑/↓ select task" : "↑/↓ half-page",
|
|
33100
|
+
"g/G top/bottom",
|
|
33101
|
+
"f resume auto-scroll",
|
|
33102
|
+
showFullTodoList ? "t todo preview" : "t todo full"
|
|
33103
|
+
];
|
|
33104
|
+
if (!viewport.autoFollow) footerParts.push("auto-scroll paused");
|
|
33105
|
+
if (lastGlobalError) footerParts.push(`error: ${clip(lastGlobalError, 40)}`);
|
|
33106
|
+
globalFooter.setContent(footerParts.join(" • "));
|
|
32672
33107
|
screen.render();
|
|
32673
33108
|
}, 300);
|
|
32674
33109
|
let pollTimer;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pantheon.ai/agents",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.16",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pantheon-agents": "dist/index.js"
|
|
7
7
|
},
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
22
22
|
"@openrouter/ai-sdk-provider": "^2.2.3",
|
|
23
23
|
"@types/express": "^5.0.6",
|
|
24
|
+
"@types/shell-quote": "^1.7.5",
|
|
24
25
|
"commander": "^14.0.3",
|
|
25
26
|
"dotenv": "^17.2.4",
|
|
26
27
|
"expand-tilde": "^2.0.2",
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
"pino-pretty": "^13.1.3",
|
|
32
33
|
"pino-roll": "^4.0.0",
|
|
33
34
|
"reblessed": "^0.2.1",
|
|
35
|
+
"shell-quote": "^1.8.3",
|
|
34
36
|
"smol-toml": "^1.6.0",
|
|
35
37
|
"zod": "^4.3.6"
|
|
36
38
|
},
|