@pantheon.ai/agents 0.0.11 → 0.0.12

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.
Files changed (2) hide show
  1. package/dist/index.js +1929 -2
  2. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -13,6 +13,8 @@ import expandTilde from "expand-tilde";
13
13
  import express, { Router } from "express";
14
14
  import { randomUUID } from "node:crypto";
15
15
  import { URL as URL$1 } from "node:url";
16
+ import blessed from "reblessed";
17
+ import { inspect } from "node:util";
16
18
 
17
19
  //#region \0rolldown/runtime.js
18
20
  var __create = Object.create;
@@ -420,7 +422,7 @@ var require_cli_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
420
422
 
421
423
  //#endregion
422
424
  //#region package.json
423
- var version$1 = "0.0.11";
425
+ var version$1 = "0.0.12";
424
426
 
425
427
  //#endregion
426
428
  //#region src/schemas/task-list.ts
@@ -9611,6 +9613,12 @@ async function getPantheonBranch({ projectId, branchId, getOutputIfFinished = fa
9611
9613
  }
9612
9614
  return { state: "others" };
9613
9615
  }
9616
+ async function getPantheonBranchInfo({ projectId, branchId }) {
9617
+ return await executor.execute(getProjectBranch, {
9618
+ projectId,
9619
+ branchId
9620
+ }, null);
9621
+ }
9614
9622
  async function executeOnPantheon({ projectId, branchId, prompt, agent }) {
9615
9623
  return (await executor.execute(createProjectExploration, { projectId }, {
9616
9624
  shared_prompt_sequence: [prompt],
@@ -9706,6 +9714,327 @@ async function startPendingTask(provider, task, logger) {
9706
9714
  logger.info(`Task ${task.id} started successfully.`);
9707
9715
  }
9708
9716
 
9717
+ //#endregion
9718
+ //#region src/core/watch/selector.ts
9719
+ const finishedTaskStatuses = [
9720
+ "completed",
9721
+ "failed",
9722
+ "cancelled"
9723
+ ];
9724
+ function isFinishedTaskStatus(status) {
9725
+ return finishedTaskStatuses.includes(status);
9726
+ }
9727
+ function getTaskTimestampMs(task) {
9728
+ switch (task.status) {
9729
+ case "running": return task.started_at.getTime();
9730
+ case "completed": return task.ended_at.getTime();
9731
+ case "failed": return task.ended_at?.getTime() ?? task.started_at?.getTime() ?? 0;
9732
+ case "cancelled": return task.cancelled_at.getTime();
9733
+ case "pending": return task.queued_at.getTime();
9734
+ }
9735
+ }
9736
+ function pickLatestRunningTask(tasks) {
9737
+ const running = tasks.filter((task) => task.status === "running");
9738
+ running.sort((a, b) => getTaskTimestampMs(b) - getTaskTimestampMs(a));
9739
+ return running[0];
9740
+ }
9741
+ function pickLatestFinishedTasks(tasks, limit) {
9742
+ const finished = tasks.filter((task) => isFinishedTaskStatus(task.status));
9743
+ finished.sort((a, b) => getTaskTimestampMs(b) - getTaskTimestampMs(a));
9744
+ return finished.slice(0, limit);
9745
+ }
9746
+ function selectSingleAgentWatchTasks(tasks, options = {}) {
9747
+ const finishedLimit = options.finishedLimit ?? 3;
9748
+ const out = [];
9749
+ const running = pickLatestRunningTask(tasks);
9750
+ if (running) out.push(running);
9751
+ const finished = pickLatestFinishedTasks(tasks, finishedLimit);
9752
+ out.push(...finished);
9753
+ return out;
9754
+ }
9755
+ function selectMultiAgentWatchTasks(tasks, agentNames) {
9756
+ const out = [];
9757
+ for (const agent of agentNames) {
9758
+ const agentTasks = tasks.filter((entry) => entry.agent === agent).map((entry) => entry.task);
9759
+ const running = pickLatestRunningTask(agentTasks);
9760
+ if (running) {
9761
+ out.push({
9762
+ agent,
9763
+ task: running
9764
+ });
9765
+ continue;
9766
+ }
9767
+ const latestFinished = pickLatestFinishedTasks(agentTasks, 1)[0];
9768
+ if (latestFinished) out.push({
9769
+ agent,
9770
+ task: latestFinished
9771
+ });
9772
+ }
9773
+ return out;
9774
+ }
9775
+ function selectFallbackWatchTasks(tasks, options = {}) {
9776
+ const agentLimit = options.agentLimit ?? 3;
9777
+ const byAgent = /* @__PURE__ */ new Map();
9778
+ for (const entry of tasks) {
9779
+ const existing = byAgent.get(entry.agent);
9780
+ if (existing) existing.push(entry.task);
9781
+ else byAgent.set(entry.agent, [entry.task]);
9782
+ }
9783
+ const runningCandidates = [];
9784
+ const finishedCandidates = [];
9785
+ for (const [agent, agentTasks] of byAgent) {
9786
+ const running = pickLatestRunningTask(agentTasks);
9787
+ if (running) {
9788
+ runningCandidates.push({
9789
+ agent,
9790
+ task: running
9791
+ });
9792
+ continue;
9793
+ }
9794
+ const latestFinished = pickLatestFinishedTasks(agentTasks, 1)[0];
9795
+ if (latestFinished) finishedCandidates.push({
9796
+ agent,
9797
+ task: latestFinished
9798
+ });
9799
+ }
9800
+ runningCandidates.sort((a, b) => getTaskTimestampMs(b.task) - getTaskTimestampMs(a.task));
9801
+ finishedCandidates.sort((a, b) => getTaskTimestampMs(b.task) - getTaskTimestampMs(a.task));
9802
+ const selected = [];
9803
+ const selectedAgents = /* @__PURE__ */ new Set();
9804
+ for (const entry of [...runningCandidates, ...finishedCandidates]) {
9805
+ if (selected.length >= agentLimit) break;
9806
+ if (selectedAgents.has(entry.agent)) continue;
9807
+ selectedAgents.add(entry.agent);
9808
+ selected.push(entry);
9809
+ }
9810
+ return selected;
9811
+ }
9812
+
9813
+ //#endregion
9814
+ //#region src/core/watch/stream.ts
9815
+ async function consumeOpaqueSseStream(options) {
9816
+ const reader = options.stream.getReader();
9817
+ let ended = false;
9818
+ let abortedByIdleTimeout = false;
9819
+ let buffer = "";
9820
+ let idleTimer;
9821
+ function warn(message) {
9822
+ options.onWarning?.(message);
9823
+ }
9824
+ function cancelReader(reason) {
9825
+ try {
9826
+ reader.cancel(reason);
9827
+ } catch {}
9828
+ }
9829
+ function resetIdleTimer() {
9830
+ if (options.idleTimeoutMs == null) return;
9831
+ clearTimeout(idleTimer);
9832
+ idleTimer = setTimeout(() => {
9833
+ abortedByIdleTimeout = true;
9834
+ cancelReader("idle_timeout");
9835
+ }, options.idleTimeoutMs);
9836
+ }
9837
+ resetIdleTimer();
9838
+ function processEventBlock(block) {
9839
+ const lines = block.split("\n");
9840
+ for (const rawLine of lines) {
9841
+ const line = rawLine.trimEnd();
9842
+ if (!line.startsWith("data:")) continue;
9843
+ const part = line.slice(5).trimStart();
9844
+ if (!part || part === "[DONE]") continue;
9845
+ try {
9846
+ options.onData(part);
9847
+ resetIdleTimer();
9848
+ } catch (error) {
9849
+ warn(`onData handler threw; skipping chunk. ${error instanceof Error ? error.message : String(error)}`);
9850
+ }
9851
+ }
9852
+ }
9853
+ const textDecoder = new TextDecoder();
9854
+ try {
9855
+ while (true) {
9856
+ if (options.signal?.aborted) {
9857
+ cancelReader("aborted");
9858
+ break;
9859
+ }
9860
+ const { value, done } = await reader.read();
9861
+ if (done) {
9862
+ ended = !abortedByIdleTimeout;
9863
+ break;
9864
+ }
9865
+ const decoded = textDecoder.decode(value, { stream: true });
9866
+ buffer += decoded.replaceAll("\r\n", "\n");
9867
+ while (true) {
9868
+ const sepIndex = buffer.indexOf("\n\n");
9869
+ if (sepIndex === -1) break;
9870
+ const block = buffer.slice(0, sepIndex);
9871
+ buffer = buffer.slice(sepIndex + 2);
9872
+ if (block.trim()) processEventBlock(block);
9873
+ }
9874
+ }
9875
+ } finally {
9876
+ clearTimeout(idleTimer);
9877
+ }
9878
+ if (buffer.trim()) warn("Stream ended with trailing incomplete SSE data; ignoring remaining buffer.");
9879
+ return {
9880
+ ended,
9881
+ abortedByIdleTimeout
9882
+ };
9883
+ }
9884
+ var WatchStepAggregator = class {
9885
+ maxLeadingTextChars;
9886
+ maxLeadingReasoningChars;
9887
+ maxLogLines;
9888
+ maxWarnings;
9889
+ leadingText = "";
9890
+ leadingReasoning = "";
9891
+ toolActions = /* @__PURE__ */ new Map();
9892
+ logLines = [];
9893
+ warnings = [];
9894
+ unknownEventCount = 0;
9895
+ orderCounter = 0;
9896
+ constructor(options = {}) {
9897
+ this.maxLeadingTextChars = options.maxLeadingTextChars ?? 800;
9898
+ this.maxLeadingReasoningChars = options.maxLeadingReasoningChars ?? 800;
9899
+ this.maxLogLines = options.maxLogLines ?? 200;
9900
+ this.maxWarnings = options.maxWarnings ?? 50;
9901
+ }
9902
+ pushLog(line) {
9903
+ if (!line) return;
9904
+ this.logLines.push(line);
9905
+ if (this.logLines.length > this.maxLogLines) this.logLines.splice(0, this.logLines.length - this.maxLogLines);
9906
+ }
9907
+ pushWarning(message) {
9908
+ if (!message) return;
9909
+ this.warnings.push(message);
9910
+ if (this.warnings.length > this.maxWarnings) this.warnings.splice(0, this.warnings.length - this.maxWarnings);
9911
+ }
9912
+ pushCommandExecutionOutput(output) {
9913
+ const out = output;
9914
+ const aggregated = typeof out?.aggregated_output === "string" ? out.aggregated_output : "";
9915
+ const exitCode = typeof out?.exit_code === "number" ? out.exit_code : void 0;
9916
+ const trimmed = aggregated.replaceAll("\r\n", "\n").trimEnd();
9917
+ if (trimmed) trimmed.split("\n").forEach((line) => this.pushLog(line));
9918
+ if (exitCode != null && exitCode !== 0) this.pushLog(`exit_code=${exitCode}`);
9919
+ }
9920
+ getOrCreateToolAction(toolCallId) {
9921
+ const existing = this.toolActions.get(toolCallId);
9922
+ if (existing) return existing;
9923
+ const created = {
9924
+ toolCallId,
9925
+ status: "in_progress",
9926
+ _order: this.orderCounter++
9927
+ };
9928
+ this.toolActions.set(toolCallId, created);
9929
+ return created;
9930
+ }
9931
+ pushUiChunk(chunk) {
9932
+ if (typeof chunk !== "object" || chunk === null) return;
9933
+ const type = chunk.type;
9934
+ if (typeof type !== "string") return;
9935
+ switch (type) {
9936
+ case "text-delta": {
9937
+ const delta = typeof chunk.delta === "string" ? chunk.delta : "";
9938
+ if (!delta) return;
9939
+ if (this.leadingText.length < this.maxLeadingTextChars) {
9940
+ const remaining = this.maxLeadingTextChars - this.leadingText.length;
9941
+ this.leadingText += delta.slice(0, remaining);
9942
+ }
9943
+ return;
9944
+ }
9945
+ case "reasoning-delta": {
9946
+ const delta = typeof chunk.delta === "string" ? chunk.delta : "";
9947
+ if (!delta) return;
9948
+ if (this.leadingReasoning.length < this.maxLeadingReasoningChars) {
9949
+ const remaining = this.maxLeadingReasoningChars - this.leadingReasoning.length;
9950
+ this.leadingReasoning += delta.slice(0, remaining);
9951
+ }
9952
+ return;
9953
+ }
9954
+ case "tool-input-start": {
9955
+ const toolCallId = typeof chunk.toolCallId === "string" ? chunk.toolCallId : "";
9956
+ if (!toolCallId) return;
9957
+ const toolName = typeof chunk.toolName === "string" ? chunk.toolName : void 0;
9958
+ const toolAction = this.getOrCreateToolAction(toolCallId);
9959
+ toolAction.toolName = toolName ?? toolAction.toolName;
9960
+ toolAction.status = "in_progress";
9961
+ if (toolAction.toolName !== "command_execution") this.pushLog(`→ tool ${toolAction.toolName ?? "<tool>"} (${toolCallId})`);
9962
+ return;
9963
+ }
9964
+ case "tool-input-delta": {
9965
+ const toolCallId = typeof chunk.toolCallId === "string" ? chunk.toolCallId : "";
9966
+ if (!toolCallId) return;
9967
+ const toolAction = this.getOrCreateToolAction(toolCallId);
9968
+ toolAction.status = "in_progress";
9969
+ return;
9970
+ }
9971
+ case "tool-input-available": {
9972
+ const toolCallId = typeof chunk.toolCallId === "string" ? chunk.toolCallId : "";
9973
+ if (!toolCallId) return;
9974
+ const toolName = typeof chunk.toolName === "string" ? chunk.toolName : void 0;
9975
+ const title = typeof chunk.title === "string" ? chunk.title : void 0;
9976
+ const input = chunk.input;
9977
+ const toolAction = this.getOrCreateToolAction(toolCallId);
9978
+ toolAction.toolName = toolName ?? toolAction.toolName;
9979
+ toolAction.title = title ?? toolAction.title;
9980
+ toolAction.input = input ?? toolAction.input;
9981
+ toolAction.status = "in_progress";
9982
+ const toolLabel = toolAction.title ? `${toolAction.toolName ?? "<tool>"}: ${toolAction.title}` : `${toolAction.toolName ?? "<tool>"}`;
9983
+ if (toolAction.toolName !== "command_execution") this.pushLog(`→ tool ${toolLabel} (${toolCallId})`);
9984
+ return;
9985
+ }
9986
+ case "tool-output-available": {
9987
+ const toolCallId = typeof chunk.toolCallId === "string" ? chunk.toolCallId : "";
9988
+ if (!toolCallId) return;
9989
+ const output = chunk.output;
9990
+ const toolAction = this.getOrCreateToolAction(toolCallId);
9991
+ toolAction.output = output;
9992
+ toolAction.status = "completed";
9993
+ if (toolAction.toolName === "command_execution") {
9994
+ this.pushCommandExecutionOutput(output);
9995
+ return;
9996
+ }
9997
+ this.pushLog(`← tool ${toolAction.toolName ?? "<tool>"} ok (${toolCallId})`);
9998
+ return;
9999
+ }
10000
+ case "tool-output-error":
10001
+ case "tool-input-error": {
10002
+ const toolCallId = typeof chunk.toolCallId === "string" ? chunk.toolCallId : "";
10003
+ if (!toolCallId) return;
10004
+ const errorText = typeof chunk.errorText === "string" ? chunk.errorText : "";
10005
+ const toolAction = this.getOrCreateToolAction(toolCallId);
10006
+ toolAction.errorText = errorText || toolAction.errorText;
10007
+ toolAction.status = "failed";
10008
+ this.pushLog(`← tool ${toolAction.toolName ?? "<tool>"} error (${toolCallId})`);
10009
+ return;
10010
+ }
10011
+ case "data-agent-unknown": {
10012
+ this.unknownEventCount++;
10013
+ const data = chunk.data;
10014
+ const reason = typeof data?.reason === "string" ? data.reason : "unknown chunk";
10015
+ this.pushWarning(reason);
10016
+ this.pushLog(`! unknown: ${reason}`);
10017
+ return;
10018
+ }
10019
+ default: return;
10020
+ }
10021
+ }
10022
+ pushUiChunks(chunks) {
10023
+ chunks.forEach((chunk) => this.pushUiChunk(chunk));
10024
+ }
10025
+ snapshot() {
10026
+ const actions = Array.from(this.toolActions.values()).sort((a, b) => a._order - b._order).map(({ _order: _unused, ...rest }) => rest);
10027
+ return {
10028
+ leadingText: this.leadingText,
10029
+ leadingReasoning: this.leadingReasoning,
10030
+ toolActions: actions,
10031
+ logLines: [...this.logLines],
10032
+ warnings: [...this.warnings],
10033
+ unknownEventCount: this.unknownEventCount
10034
+ };
10035
+ }
10036
+ };
10037
+
9709
10038
  //#endregion
9710
10039
  //#region src/core/index.ts
9711
10040
  function normalizeSkills(value) {
@@ -32245,9 +32574,1607 @@ function createShowTasksCommand(version) {
32245
32574
  });
32246
32575
  }
32247
32576
 
32577
+ //#endregion
32578
+ //#region ../agent-stream-parser/src/utils.ts
32579
+ function isRecord(value) {
32580
+ return typeof value === "object" && value !== null;
32581
+ }
32582
+ function safeJsonParse(text) {
32583
+ try {
32584
+ return {
32585
+ ok: true,
32586
+ value: JSON.parse(text)
32587
+ };
32588
+ } catch (error) {
32589
+ const sanitized = sanitizeMalformedJsonLine(text);
32590
+ if (sanitized !== text) try {
32591
+ return {
32592
+ ok: true,
32593
+ value: JSON.parse(sanitized)
32594
+ };
32595
+ } catch {}
32596
+ return {
32597
+ ok: false,
32598
+ error
32599
+ };
32600
+ }
32601
+ }
32602
+ function sanitizeMalformedJsonLine(text) {
32603
+ return text.replaceAll("", "'").replaceAll("", "—").replaceAll("", "—").replaceAll(/[\u0000-\u001F]/g, "");
32604
+ }
32605
+ function toErrorMessage(error) {
32606
+ if (error instanceof Error) return error.message;
32607
+ try {
32608
+ return JSON.stringify(error);
32609
+ } catch {
32610
+ return String(error);
32611
+ }
32612
+ }
32613
+ function computeAppendDelta(previous, next) {
32614
+ if (next.startsWith(previous)) return {
32615
+ delta: next.slice(previous.length),
32616
+ reset: false
32617
+ };
32618
+ return {
32619
+ delta: next,
32620
+ reset: true
32621
+ };
32622
+ }
32623
+
32624
+ //#endregion
32625
+ //#region ../agent-stream-parser/src/codex.ts
32626
+ const usageSchema = z$1.object({
32627
+ input_tokens: z$1.number(),
32628
+ cached_input_tokens: z$1.number(),
32629
+ output_tokens: z$1.number()
32630
+ });
32631
+ const agentMessageItemSchema = z$1.object({
32632
+ id: z$1.string(),
32633
+ type: z$1.literal("agent_message"),
32634
+ text: z$1.string()
32635
+ });
32636
+ const reasoningItemSchema = z$1.object({
32637
+ id: z$1.string(),
32638
+ type: z$1.literal("reasoning"),
32639
+ text: z$1.string()
32640
+ });
32641
+ const commandExecutionItemSchema = z$1.object({
32642
+ id: z$1.string(),
32643
+ type: z$1.literal("command_execution"),
32644
+ command: z$1.string(),
32645
+ aggregated_output: z$1.string(),
32646
+ exit_code: z$1.preprocess((value) => value === null ? void 0 : value, z$1.number().optional()),
32647
+ status: z$1.enum([
32648
+ "in_progress",
32649
+ "completed",
32650
+ "failed"
32651
+ ])
32652
+ });
32653
+ const mcpToolCallItemSchema = z$1.object({
32654
+ id: z$1.string(),
32655
+ type: z$1.literal("mcp_tool_call"),
32656
+ server: z$1.string(),
32657
+ tool: z$1.string(),
32658
+ arguments: z$1.any(),
32659
+ result: z$1.object({
32660
+ content: z$1.array(z$1.any()),
32661
+ structured_content: z$1.any()
32662
+ }).optional(),
32663
+ error: z$1.object({ message: z$1.string() }).optional(),
32664
+ status: z$1.enum([
32665
+ "in_progress",
32666
+ "completed",
32667
+ "failed"
32668
+ ])
32669
+ });
32670
+ const fileChangeItemSchema = z$1.object({
32671
+ id: z$1.string(),
32672
+ type: z$1.literal("file_change"),
32673
+ changes: z$1.array(z$1.object({
32674
+ path: z$1.string(),
32675
+ kind: z$1.enum([
32676
+ "add",
32677
+ "delete",
32678
+ "update"
32679
+ ])
32680
+ })),
32681
+ status: z$1.enum(["completed", "failed"])
32682
+ });
32683
+ const webSearchItemSchema = z$1.object({
32684
+ id: z$1.string(),
32685
+ type: z$1.literal("web_search"),
32686
+ query: z$1.string()
32687
+ });
32688
+ const todoListItemSchema = z$1.object({
32689
+ id: z$1.string(),
32690
+ type: z$1.literal("todo_list"),
32691
+ items: z$1.array(z$1.object({
32692
+ text: z$1.string(),
32693
+ completed: z$1.boolean()
32694
+ }))
32695
+ });
32696
+ const errorItemSchema = z$1.object({
32697
+ id: z$1.string(),
32698
+ type: z$1.literal("error"),
32699
+ message: z$1.string()
32700
+ });
32701
+ const threadItemSchema = z$1.discriminatedUnion("type", [
32702
+ agentMessageItemSchema,
32703
+ reasoningItemSchema,
32704
+ commandExecutionItemSchema,
32705
+ mcpToolCallItemSchema,
32706
+ fileChangeItemSchema,
32707
+ webSearchItemSchema,
32708
+ todoListItemSchema,
32709
+ errorItemSchema
32710
+ ]);
32711
+ const threadEventSchema = z$1.discriminatedUnion("type", [
32712
+ z$1.object({
32713
+ type: z$1.literal("thread.started"),
32714
+ thread_id: z$1.string()
32715
+ }),
32716
+ z$1.object({ type: z$1.literal("turn.started") }),
32717
+ z$1.object({
32718
+ type: z$1.literal("turn.completed"),
32719
+ usage: usageSchema
32720
+ }),
32721
+ z$1.object({
32722
+ type: z$1.literal("turn.failed"),
32723
+ error: z$1.object({ message: z$1.string() })
32724
+ }),
32725
+ z$1.object({
32726
+ type: z$1.literal("item.started"),
32727
+ item: threadItemSchema
32728
+ }),
32729
+ z$1.object({
32730
+ type: z$1.literal("item.updated"),
32731
+ item: threadItemSchema
32732
+ }),
32733
+ z$1.object({
32734
+ type: z$1.literal("item.completed"),
32735
+ item: threadItemSchema
32736
+ }),
32737
+ z$1.object({
32738
+ type: z$1.literal("error"),
32739
+ message: z$1.string()
32740
+ })
32741
+ ]);
32742
+ function createCodexNormalizer(options = {}) {
32743
+ const includeMetaEvents = options.includeMetaEvents ?? false;
32744
+ const activeText = /* @__PURE__ */ new Map();
32745
+ const activeReasoning = /* @__PURE__ */ new Map();
32746
+ function maybeMetaEvent(event) {
32747
+ if (!includeMetaEvents) return [];
32748
+ return [{
32749
+ type: "data-agent-event",
32750
+ data: event
32751
+ }];
32752
+ }
32753
+ function handleTextLike({ map, id, fullText, eventType, startType, deltaType, endType }) {
32754
+ const out = [];
32755
+ let state = map.get(id);
32756
+ if (!state || !state.open) {
32757
+ state = {
32758
+ lastText: "",
32759
+ open: true
32760
+ };
32761
+ map.set(id, state);
32762
+ out.push({
32763
+ type: startType,
32764
+ id
32765
+ });
32766
+ }
32767
+ const { delta, reset } = computeAppendDelta(state.lastText, fullText);
32768
+ if (delta) {
32769
+ out.push({
32770
+ type: deltaType,
32771
+ id,
32772
+ delta
32773
+ });
32774
+ state.lastText = reset ? fullText : state.lastText + delta;
32775
+ }
32776
+ if (eventType === "item.completed") {
32777
+ out.push({
32778
+ type: endType,
32779
+ id
32780
+ });
32781
+ state.open = false;
32782
+ }
32783
+ return out;
32784
+ }
32785
+ function normalizeItemEvent(eventType, item) {
32786
+ const out = [];
32787
+ switch (item.type) {
32788
+ case "agent_message": return {
32789
+ recognized: true,
32790
+ chunks: handleTextLike({
32791
+ map: activeText,
32792
+ id: item.id,
32793
+ fullText: item.text,
32794
+ eventType,
32795
+ startType: "text-start",
32796
+ deltaType: "text-delta",
32797
+ endType: "text-end"
32798
+ })
32799
+ };
32800
+ case "reasoning": return {
32801
+ recognized: true,
32802
+ chunks: handleTextLike({
32803
+ map: activeReasoning,
32804
+ id: item.id,
32805
+ fullText: item.text,
32806
+ eventType,
32807
+ startType: "reasoning-start",
32808
+ deltaType: "reasoning-delta",
32809
+ endType: "reasoning-end"
32810
+ })
32811
+ };
32812
+ case "command_execution": {
32813
+ const toolCallId = item.id;
32814
+ out.push({
32815
+ type: "tool-input-available",
32816
+ toolCallId,
32817
+ toolName: "command_execution",
32818
+ title: item.command,
32819
+ input: { command: item.command },
32820
+ dynamic: true
32821
+ });
32822
+ if (item.status === "completed") out.push({
32823
+ type: "tool-output-available",
32824
+ toolCallId,
32825
+ output: {
32826
+ exit_code: item.exit_code ?? null,
32827
+ aggregated_output: item.aggregated_output
32828
+ },
32829
+ dynamic: true
32830
+ });
32831
+ else if (item.status === "failed") {
32832
+ const exitCode = item.exit_code;
32833
+ out.push({
32834
+ type: "tool-output-error",
32835
+ toolCallId,
32836
+ errorText: exitCode != null ? `Command failed (exit_code=${exitCode}).\n${item.aggregated_output}` : `Command failed.\n${item.aggregated_output}`,
32837
+ dynamic: true
32838
+ });
32839
+ }
32840
+ return {
32841
+ recognized: true,
32842
+ chunks: out
32843
+ };
32844
+ }
32845
+ case "mcp_tool_call": {
32846
+ const toolCallId = item.id;
32847
+ out.push({
32848
+ type: "tool-input-available",
32849
+ toolCallId,
32850
+ toolName: "mcp_tool_call",
32851
+ title: `${item.server}.${item.tool}`,
32852
+ input: item.arguments,
32853
+ dynamic: true
32854
+ });
32855
+ if (item.status === "completed") out.push({
32856
+ type: "tool-output-available",
32857
+ toolCallId,
32858
+ output: item.result?.structured_content ?? null,
32859
+ dynamic: true
32860
+ });
32861
+ else if (item.status === "failed") out.push({
32862
+ type: "tool-output-error",
32863
+ toolCallId,
32864
+ errorText: item.error?.message ?? "MCP tool call failed",
32865
+ dynamic: true
32866
+ });
32867
+ return {
32868
+ recognized: true,
32869
+ chunks: out
32870
+ };
32871
+ }
32872
+ case "file_change": {
32873
+ const toolCallId = item.id;
32874
+ out.push({
32875
+ type: "tool-input-available",
32876
+ toolCallId,
32877
+ toolName: "file_change",
32878
+ input: { changes: item.changes },
32879
+ dynamic: true
32880
+ });
32881
+ if (item.status === "completed") out.push({
32882
+ type: "tool-output-available",
32883
+ toolCallId,
32884
+ output: { status: "completed" },
32885
+ dynamic: true
32886
+ });
32887
+ else out.push({
32888
+ type: "tool-output-error",
32889
+ toolCallId,
32890
+ errorText: "Patch apply failed",
32891
+ dynamic: true
32892
+ });
32893
+ return {
32894
+ recognized: true,
32895
+ chunks: out
32896
+ };
32897
+ }
32898
+ case "web_search": {
32899
+ const toolCallId = item.id;
32900
+ out.push({
32901
+ type: "tool-input-available",
32902
+ toolCallId,
32903
+ toolName: "web_search",
32904
+ title: item.query,
32905
+ input: { query: item.query },
32906
+ dynamic: true
32907
+ });
32908
+ if (eventType === "item.completed") out.push({
32909
+ type: "tool-output-available",
32910
+ toolCallId,
32911
+ output: null,
32912
+ dynamic: true
32913
+ });
32914
+ return {
32915
+ recognized: true,
32916
+ chunks: out
32917
+ };
32918
+ }
32919
+ case "todo_list": return {
32920
+ recognized: true,
32921
+ chunks: maybeMetaEvent({
32922
+ kind: "codex.todo_list",
32923
+ items: item.items
32924
+ })
32925
+ };
32926
+ case "error":
32927
+ out.push({
32928
+ type: "error",
32929
+ errorText: item.message
32930
+ });
32931
+ out.push(...maybeMetaEvent({
32932
+ kind: "codex.error",
32933
+ message: item.message
32934
+ }));
32935
+ return {
32936
+ recognized: true,
32937
+ chunks: out
32938
+ };
32939
+ default: return {
32940
+ recognized: false,
32941
+ chunks: []
32942
+ };
32943
+ }
32944
+ }
32945
+ function push(chunk) {
32946
+ const parsed = threadEventSchema.safeParse(chunk);
32947
+ if (!parsed.success) return {
32948
+ recognized: false,
32949
+ chunks: []
32950
+ };
32951
+ const event = parsed.data;
32952
+ switch (event.type) {
32953
+ case "thread.started": {
32954
+ const out = [{
32955
+ type: "message-metadata",
32956
+ messageMetadata: {
32957
+ threadId: event.thread_id,
32958
+ source: "codex"
32959
+ }
32960
+ }];
32961
+ out.push(...maybeMetaEvent({
32962
+ kind: "codex.thread.started",
32963
+ threadId: event.thread_id
32964
+ }));
32965
+ return {
32966
+ recognized: true,
32967
+ chunks: out
32968
+ };
32969
+ }
32970
+ case "turn.started": {
32971
+ const out = [{ type: "start-step" }];
32972
+ out.push(...maybeMetaEvent({ kind: "codex.turn.started" }));
32973
+ return {
32974
+ recognized: true,
32975
+ chunks: out
32976
+ };
32977
+ }
32978
+ case "turn.completed": {
32979
+ const out = [{ type: "finish-step" }];
32980
+ out.push(...maybeMetaEvent({
32981
+ kind: "codex.turn.completed",
32982
+ usage: event.usage
32983
+ }));
32984
+ return {
32985
+ recognized: true,
32986
+ chunks: out
32987
+ };
32988
+ }
32989
+ case "turn.failed": {
32990
+ const out = [{
32991
+ type: "error",
32992
+ errorText: event.error.message
32993
+ }, { type: "finish-step" }];
32994
+ out.push(...maybeMetaEvent({
32995
+ kind: "codex.turn.failed",
32996
+ message: event.error.message
32997
+ }));
32998
+ return {
32999
+ recognized: true,
33000
+ chunks: out
33001
+ };
33002
+ }
33003
+ case "error": {
33004
+ const out = [{
33005
+ type: "error",
33006
+ errorText: event.message
33007
+ }];
33008
+ out.push(...maybeMetaEvent({
33009
+ kind: "codex.error",
33010
+ message: event.message
33011
+ }));
33012
+ return {
33013
+ recognized: true,
33014
+ chunks: out
33015
+ };
33016
+ }
33017
+ case "item.started":
33018
+ case "item.updated":
33019
+ case "item.completed": return normalizeItemEvent(event.type, event.item);
33020
+ default: return {
33021
+ recognized: false,
33022
+ chunks: []
33023
+ };
33024
+ }
33025
+ }
33026
+ function finish() {
33027
+ const out = [];
33028
+ for (const [id, state] of activeText) if (state.open) {
33029
+ out.push({
33030
+ type: "text-end",
33031
+ id
33032
+ });
33033
+ state.open = false;
33034
+ }
33035
+ for (const [id, state] of activeReasoning) if (state.open) {
33036
+ out.push({
33037
+ type: "reasoning-end",
33038
+ id
33039
+ });
33040
+ state.open = false;
33041
+ }
33042
+ return out;
33043
+ }
33044
+ return {
33045
+ push,
33046
+ finish
33047
+ };
33048
+ }
33049
+
33050
+ //#endregion
33051
+ //#region ../agent-stream-parser/src/claude.ts
33052
+ const topLevelSchema = z$1.object({ type: z$1.string() }).passthrough();
33053
+ const streamEventSchema = z$1.object({
33054
+ type: z$1.string(),
33055
+ index: z$1.number().optional()
33056
+ }).passthrough();
33057
+ function createClaudeCodeNormalizer(options = {}) {
33058
+ const includeMetaEvents = options.includeMetaEvents ?? false;
33059
+ const textBlocks = /* @__PURE__ */ new Map();
33060
+ const toolBlocks = /* @__PURE__ */ new Map();
33061
+ let sawStreamEvents = false;
33062
+ function maybeMeta(event) {
33063
+ if (!includeMetaEvents) return [];
33064
+ return [{
33065
+ type: "data-agent-event",
33066
+ data: event
33067
+ }];
33068
+ }
33069
+ function ensureTextBlock(index) {
33070
+ const existing = textBlocks.get(index);
33071
+ if (existing?.open) return [];
33072
+ const id = existing?.id ?? `claude-text-${index}`;
33073
+ textBlocks.set(index, {
33074
+ id,
33075
+ open: true
33076
+ });
33077
+ return [{
33078
+ type: "text-start",
33079
+ id
33080
+ }];
33081
+ }
33082
+ function ensureToolBlock(index, block) {
33083
+ const existing = toolBlocks.get(index);
33084
+ if (existing?.open) return [];
33085
+ const toolCallId = block?.id ?? existing?.toolCallId ?? `claude-tool-${index}`;
33086
+ const toolName = block?.name ?? existing?.toolName ?? "tool";
33087
+ toolBlocks.set(index, {
33088
+ toolCallId,
33089
+ toolName,
33090
+ json: "",
33091
+ open: true
33092
+ });
33093
+ return [{
33094
+ type: "tool-input-start",
33095
+ toolCallId,
33096
+ toolName,
33097
+ dynamic: true
33098
+ }];
33099
+ }
33100
+ function handleStreamEvent(event) {
33101
+ if (!isRecord(event) || typeof event.type !== "string") return [];
33102
+ const out = [];
33103
+ const index = typeof event.index === "number" ? event.index : void 0;
33104
+ switch (event.type) {
33105
+ case "content_block_start": {
33106
+ if (index == null) return [];
33107
+ const block = event.content_block;
33108
+ if (!isRecord(block) || typeof block.type !== "string") return [];
33109
+ sawStreamEvents = true;
33110
+ if (block.type === "text") out.push(...ensureTextBlock(index));
33111
+ else if (block.type === "tool_use") out.push(...ensureToolBlock(index, {
33112
+ id: typeof block.id === "string" ? block.id : void 0,
33113
+ name: typeof block.name === "string" ? block.name : void 0
33114
+ }));
33115
+ return out;
33116
+ }
33117
+ case "content_block_delta": {
33118
+ if (index == null) return [];
33119
+ const delta = event.delta;
33120
+ if (!isRecord(delta) || typeof delta.type !== "string") return [];
33121
+ sawStreamEvents = true;
33122
+ if (delta.type === "text_delta") {
33123
+ const text = typeof delta.text === "string" ? delta.text : "";
33124
+ if (!text) return [];
33125
+ out.push(...ensureTextBlock(index));
33126
+ const id = textBlocks.get(index).id;
33127
+ out.push({
33128
+ type: "text-delta",
33129
+ id,
33130
+ delta: text
33131
+ });
33132
+ return out;
33133
+ }
33134
+ if (delta.type === "input_json_delta") {
33135
+ const partialJson = typeof delta.partial_json === "string" ? delta.partial_json : "";
33136
+ if (!partialJson) return [];
33137
+ out.push(...ensureToolBlock(index));
33138
+ const tool = toolBlocks.get(index);
33139
+ tool.json += partialJson;
33140
+ out.push({
33141
+ type: "tool-input-delta",
33142
+ toolCallId: tool.toolCallId,
33143
+ inputTextDelta: partialJson
33144
+ });
33145
+ return out;
33146
+ }
33147
+ return [];
33148
+ }
33149
+ case "content_block_stop": {
33150
+ if (index == null) return [];
33151
+ sawStreamEvents = true;
33152
+ const text = textBlocks.get(index);
33153
+ if (text?.open) {
33154
+ text.open = false;
33155
+ out.push({
33156
+ type: "text-end",
33157
+ id: text.id
33158
+ });
33159
+ }
33160
+ const tool = toolBlocks.get(index);
33161
+ if (tool?.open) {
33162
+ tool.open = false;
33163
+ let input = tool.json ? tool.json : {};
33164
+ if (typeof input === "string") {
33165
+ const parsed = safeJsonParse(input);
33166
+ if (parsed.ok) input = parsed.value;
33167
+ }
33168
+ out.push({
33169
+ type: "tool-input-available",
33170
+ toolCallId: tool.toolCallId,
33171
+ toolName: tool.toolName,
33172
+ input,
33173
+ dynamic: true
33174
+ });
33175
+ }
33176
+ return out;
33177
+ }
33178
+ default: return [];
33179
+ }
33180
+ }
33181
+ function handleAssistantMessage(message) {
33182
+ if (sawStreamEvents) return [];
33183
+ const blocks = Array.isArray(message.content) ? message.content : [];
33184
+ const out = [];
33185
+ blocks.forEach((block, index) => {
33186
+ if (!isRecord(block) || typeof block.type !== "string") return;
33187
+ if (block.type === "text") {
33188
+ const id = `claude-assistant-text-${index}`;
33189
+ const text = typeof block.text === "string" ? block.text : "";
33190
+ out.push({
33191
+ type: "text-start",
33192
+ id
33193
+ });
33194
+ if (text) out.push({
33195
+ type: "text-delta",
33196
+ id,
33197
+ delta: text
33198
+ });
33199
+ out.push({
33200
+ type: "text-end",
33201
+ id
33202
+ });
33203
+ }
33204
+ if (block.type === "tool_use") {
33205
+ const toolCallId = typeof block.id === "string" ? block.id : `claude-assistant-tool-${index}`;
33206
+ const toolName = typeof block.name === "string" ? block.name : "tool";
33207
+ const input = block.input;
33208
+ out.push({
33209
+ type: "tool-input-available",
33210
+ toolCallId,
33211
+ toolName,
33212
+ input,
33213
+ dynamic: true
33214
+ });
33215
+ }
33216
+ });
33217
+ return out;
33218
+ }
33219
+ function push(chunk) {
33220
+ const parsed = topLevelSchema.safeParse(chunk);
33221
+ if (!parsed.success) return {
33222
+ recognized: false,
33223
+ chunks: []
33224
+ };
33225
+ const msg = parsed.data;
33226
+ const out = [];
33227
+ switch (msg.type) {
33228
+ case "system": {
33229
+ const model = typeof msg.model === "string" ? msg.model : void 0;
33230
+ const sessionId = typeof msg.session_id === "string" ? msg.session_id : typeof msg.sessionId === "string" ? msg.sessionId : void 0;
33231
+ out.push({
33232
+ type: "message-metadata",
33233
+ messageMetadata: {
33234
+ source: "claude-code",
33235
+ model,
33236
+ sessionId
33237
+ }
33238
+ });
33239
+ out.push(...maybeMeta({
33240
+ kind: "claude.system",
33241
+ model,
33242
+ sessionId
33243
+ }));
33244
+ return {
33245
+ recognized: true,
33246
+ chunks: out
33247
+ };
33248
+ }
33249
+ case "stream_event": {
33250
+ sawStreamEvents = true;
33251
+ const event = streamEventSchema.safeParse(msg.event);
33252
+ if (!event.success) return {
33253
+ recognized: false,
33254
+ chunks: []
33255
+ };
33256
+ return {
33257
+ recognized: true,
33258
+ chunks: handleStreamEvent(event.data)
33259
+ };
33260
+ }
33261
+ case "assistant": {
33262
+ const message = msg.message;
33263
+ if (!isRecord(message)) return {
33264
+ recognized: false,
33265
+ chunks: []
33266
+ };
33267
+ return {
33268
+ recognized: true,
33269
+ chunks: handleAssistantMessage(message)
33270
+ };
33271
+ }
33272
+ case "result": return {
33273
+ recognized: true,
33274
+ chunks: maybeMeta({
33275
+ kind: "claude.result",
33276
+ subtype: typeof msg.subtype === "string" ? msg.subtype : void 0,
33277
+ isError: typeof msg.is_error === "boolean" ? msg.is_error : void 0
33278
+ })
33279
+ };
33280
+ default: return {
33281
+ recognized: false,
33282
+ chunks: []
33283
+ };
33284
+ }
33285
+ }
33286
+ function finish() {
33287
+ const out = [];
33288
+ for (const [index, block] of textBlocks) if (block.open) {
33289
+ block.open = false;
33290
+ out.push({
33291
+ type: "text-end",
33292
+ id: block.id
33293
+ });
33294
+ }
33295
+ for (const [index, tool] of toolBlocks) if (tool.open) {
33296
+ tool.open = false;
33297
+ const reason = `Stream ended before tool input completed (index=${index}).`;
33298
+ out.push({
33299
+ type: "tool-input-error",
33300
+ toolCallId: tool.toolCallId,
33301
+ toolName: tool.toolName,
33302
+ input: tool.json,
33303
+ errorText: reason,
33304
+ dynamic: true
33305
+ });
33306
+ }
33307
+ return out;
33308
+ }
33309
+ return {
33310
+ push,
33311
+ finish
33312
+ };
33313
+ }
33314
+
33315
+ //#endregion
33316
+ //#region ../agent-stream-parser/src/normalizer.ts
33317
+ function createAgentStreamNormalizer(options) {
33318
+ const unknownChunkPolicy = options.unknownChunkPolicy ?? "ignore";
33319
+ const includeMetaEvents = options.includeMetaEvents ?? false;
33320
+ const emitStartChunk = options.emitStartChunk ?? true;
33321
+ const impl = options.source === "codex" ? createCodexNormalizer({ includeMetaEvents }) : createClaudeCodeNormalizer({ includeMetaEvents });
33322
+ let started = false;
33323
+ function maybeEmitStart() {
33324
+ if (!emitStartChunk || started) return [];
33325
+ started = true;
33326
+ const messageMetadata = { source: options.source };
33327
+ if (options.messageId) return [{
33328
+ type: "start",
33329
+ messageId: options.messageId,
33330
+ messageMetadata
33331
+ }];
33332
+ return [{
33333
+ type: "start",
33334
+ messageMetadata
33335
+ }];
33336
+ }
33337
+ function onUnknownChunk(chunk, reason) {
33338
+ if (unknownChunkPolicy === "ignore") return [];
33339
+ if (unknownChunkPolicy === "throw") throw new Error(`Unknown chunk: ${reason}`);
33340
+ return [{
33341
+ type: "data-agent-unknown",
33342
+ data: {
33343
+ source: options.source,
33344
+ reason,
33345
+ chunk
33346
+ }
33347
+ }];
33348
+ }
33349
+ function push(chunk) {
33350
+ let parsedChunk = chunk;
33351
+ if (typeof chunk === "string") {
33352
+ const parsed = safeJsonParse(chunk);
33353
+ if (!parsed.ok) {
33354
+ const unknown = onUnknownChunk(chunk, `invalid JSON string: ${toErrorMessage(parsed.error)}`);
33355
+ return unknown.length > 0 ? [...maybeEmitStart(), ...unknown] : [];
33356
+ }
33357
+ parsedChunk = parsed.value;
33358
+ }
33359
+ if (!isRecord(parsedChunk) || typeof parsedChunk.type !== "string") {
33360
+ const unknown = onUnknownChunk(chunk, "missing object with string 'type'");
33361
+ return unknown.length > 0 ? [...maybeEmitStart(), ...unknown] : [];
33362
+ }
33363
+ const result = impl.push(parsedChunk);
33364
+ if (result.chunks.length > 0) return [...maybeEmitStart(), ...result.chunks];
33365
+ if (result.recognized) return [];
33366
+ const type = typeof parsedChunk.type === "string" ? parsedChunk.type : "<unknown>";
33367
+ const unknown = onUnknownChunk(chunk, `unrecognized ${options.source} chunk type: ${type}`);
33368
+ return unknown.length > 0 ? [...maybeEmitStart(), ...unknown] : [];
33369
+ }
33370
+ function finish() {
33371
+ const out = impl.finish();
33372
+ if (out.length === 0) return [];
33373
+ return [...maybeEmitStart(), ...out];
33374
+ }
33375
+ return {
33376
+ source: options.source,
33377
+ push,
33378
+ finish
33379
+ };
33380
+ }
33381
+
33382
+ //#endregion
33383
+ //#region src/cli/commands/watch/format.ts
33384
+ function tryExtractBashCommand(command) {
33385
+ const wrapper = command.trim().match(/^(?:\/\S*\/bash|bash)\s+(-\S*c)\s+([\s\S]+)$/);
33386
+ if (!wrapper) return void 0;
33387
+ const rest = wrapper[2].trimStart();
33388
+ if (!rest) return void 0;
33389
+ if (rest.startsWith("$'")) {
33390
+ const end = rest.indexOf("'", 2);
33391
+ return end === -1 ? rest.slice(2) : rest.slice(2, end);
33392
+ }
33393
+ if (rest.startsWith("'")) {
33394
+ const end = rest.indexOf("'", 1);
33395
+ return end === -1 ? rest.slice(1) : rest.slice(1, end);
33396
+ }
33397
+ if (rest.startsWith("\"")) {
33398
+ let out = "";
33399
+ let escaped = false;
33400
+ for (let i = 1; i < rest.length; i++) {
33401
+ const ch = rest[i];
33402
+ if (escaped) {
33403
+ out += ch;
33404
+ escaped = false;
33405
+ continue;
33406
+ }
33407
+ if (ch === "\\") {
33408
+ escaped = true;
33409
+ continue;
33410
+ }
33411
+ if (ch === "\"") return out;
33412
+ out += ch;
33413
+ }
33414
+ return out;
33415
+ }
33416
+ return rest.trim();
33417
+ }
33418
+ function formatCommandExecutionDisplayCommand(command) {
33419
+ const trimmed = command.trim();
33420
+ return tryExtractBashCommand(trimmed)?.trim() || trimmed;
33421
+ }
33422
+ function formatPreviewLine(label, text, options = {}) {
33423
+ const trimmed = text.trim();
33424
+ if (!trimmed) return void 0;
33425
+ const oneLine = trimmed.replaceAll(/\s+/g, " ");
33426
+ const max = options.maxChars ?? 220;
33427
+ const preview = oneLine.length > max ? oneLine.slice(0, max - 1) + "…" : oneLine;
33428
+ return `${label}: ${options.formatValue ? options.formatValue(preview) : preview}`;
33429
+ }
33430
+
33431
+ //#endregion
33432
+ //#region src/cli/commands/watch.ts
33433
+ const PANTHEON_BASE_URL = "https://pantheon-ai.tidb.ai";
33434
+ function ensureEnvOrExit(keys) {
33435
+ const missing = keys.filter((key) => !process.env[key]);
33436
+ if (missing.length === 0) return;
33437
+ for (const key of missing) console.error(`${key} environment variable is not set.`);
33438
+ process.exit(1);
33439
+ }
33440
+ function createDb() {
33441
+ return new Kysely({ dialect: new MysqlDialect({ pool: createPool({
33442
+ uri: process.env.DATABASE_URL,
33443
+ supportBigNumbers: true,
33444
+ bigNumberStrings: true
33445
+ }) }) });
33446
+ }
33447
+ function formatDurationMs(ms) {
33448
+ const seconds = Math.max(0, Math.floor(ms / 1e3));
33449
+ const minutes = Math.floor(seconds / 60);
33450
+ const hours = Math.floor(minutes / 60);
33451
+ if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
33452
+ if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
33453
+ return `${seconds}s`;
33454
+ }
33455
+ function getTaskStartTime(task) {
33456
+ switch (task.status) {
33457
+ case "pending": return task.queued_at;
33458
+ case "running": return task.started_at;
33459
+ case "completed":
33460
+ case "failed": return task.started_at ?? task.queued_at;
33461
+ case "cancelled": return task.queued_at;
33462
+ }
33463
+ }
33464
+ function getTaskElapsedMs(task, now = /* @__PURE__ */ new Date()) {
33465
+ const start = getTaskStartTime(task);
33466
+ if (!start) return 0;
33467
+ switch (task.status) {
33468
+ case "completed": return task.ended_at.getTime() - start.getTime();
33469
+ case "failed": return (task.ended_at ?? now).getTime() - start.getTime();
33470
+ case "cancelled": return task.cancelled_at.getTime() - start.getTime();
33471
+ default: return now.getTime() - start.getTime();
33472
+ }
33473
+ }
33474
+ function toStreamSourceFromExecuteAgent(executeAgent) {
33475
+ if (!executeAgent) return void 0;
33476
+ const normalized = executeAgent.toLowerCase();
33477
+ if (normalized.includes("claude")) return "claude-code";
33478
+ if (normalized.includes("codex")) return "codex";
33479
+ }
33480
+ function detectStreamSourceFromRawPayload(payload) {
33481
+ if (payload.includes("\"type\":\"thread.") || payload.includes("\"type\":\"turn.") || payload.includes("\"type\":\"item.")) return "codex";
33482
+ if (payload.includes("\"type\":\"message_start\"") || payload.includes("\"type\":\"message_delta\"") || payload.includes("\"type\":\"message_stop\"") || payload.includes("\"type\":\"content_block_start\"") || payload.includes("\"type\":\"content_block_delta\"") || payload.includes("\"type\":\"content_block_stop\"")) return "claude-code";
33483
+ }
33484
+ async function getAgentExecuteAgentMap(db, targets) {
33485
+ const agents = Array.from(new Set(targets.map((t) => t.agent)));
33486
+ if (agents.length === 0) return /* @__PURE__ */ new Map();
33487
+ const configs = await db.selectFrom("agent_project_config").select([
33488
+ "agent",
33489
+ "project_id",
33490
+ "execute_agent"
33491
+ ]).where("agent", "in", agents).execute();
33492
+ const map = /* @__PURE__ */ new Map();
33493
+ for (const row of configs) map.set(`${row.agent}|${row.project_id}`, row.execute_agent);
33494
+ return map;
33495
+ }
33496
+ async function loadTasksByIds(db, ids) {
33497
+ if (ids.length === 0) return [];
33498
+ const rows = await db.selectFrom("task").selectAll().where("id", "in", ids).execute();
33499
+ const out = [];
33500
+ for (const row of rows) {
33501
+ const parsed = taskItemSchema.safeParse(row);
33502
+ if (!parsed.success) {
33503
+ console.error(`Failed to parse task row id=${row.id} agent=${row.agent} status=${row.status}: ${parsed.error.message}`);
33504
+ continue;
33505
+ }
33506
+ out.push({
33507
+ agent: row.agent,
33508
+ task: parsed.data
33509
+ });
33510
+ }
33511
+ return out;
33512
+ }
33513
+ async function loadTasksForAgent(db, agent) {
33514
+ const rows = await db.selectFrom("task").selectAll().where("agent", "=", agent).execute();
33515
+ const out = [];
33516
+ for (const row of rows) {
33517
+ const parsed = taskItemSchema.safeParse(row);
33518
+ if (!parsed.success) continue;
33519
+ out.push(parsed.data);
33520
+ }
33521
+ return out;
33522
+ }
33523
+ async function loadAllTasks(db, limit) {
33524
+ const rows = await db.selectFrom("task").selectAll().orderBy("queued_at", "desc").limit(limit).execute();
33525
+ const out = [];
33526
+ for (const row of rows) {
33527
+ const parsed = taskItemSchema.safeParse(row);
33528
+ if (!parsed.success) continue;
33529
+ out.push({
33530
+ agent: row.agent,
33531
+ task: parsed.data
33532
+ });
33533
+ }
33534
+ return out;
33535
+ }
33536
+ async function resolveWatchTargets(options) {
33537
+ const warnings = [];
33538
+ let selected = [];
33539
+ if (options.taskIds.length > 0) {
33540
+ const uniqueTaskIds = Array.from(new Set(options.taskIds));
33541
+ const found = await loadTasksByIds(options.db, uniqueTaskIds);
33542
+ const foundIds = new Set(found.map((t) => t.task.id));
33543
+ const missing = uniqueTaskIds.filter((id) => !foundIds.has(id));
33544
+ if (missing.length > 0) warnings.push(`Requested task IDs not found: ${missing.join(", ")}`);
33545
+ const byId = new Map(found.map((t) => [t.task.id, t]));
33546
+ selected = uniqueTaskIds.map((id) => byId.get(id)).filter(Boolean);
33547
+ if (selected.length === 0) warnings.push("No requested tasks found; falling back to default selection.");
33548
+ } else if (options.agentNames.length > 0) {
33549
+ const uniqueAgents = Array.from(new Set(options.agentNames));
33550
+ if (uniqueAgents.length === 1) {
33551
+ selected = selectSingleAgentWatchTasks(await loadTasksForAgent(options.db, uniqueAgents[0]), { finishedLimit: 3 }).map((task) => ({
33552
+ agent: uniqueAgents[0],
33553
+ task
33554
+ }));
33555
+ if (selected.length === 0) warnings.push(`No tasks found for agent ${uniqueAgents[0]}; falling back to default selection.`);
33556
+ } else {
33557
+ selected = selectMultiAgentWatchTasks(await Promise.all(uniqueAgents.map(async (agent) => {
33558
+ return (await loadTasksForAgent(options.db, agent)).map((task) => ({
33559
+ agent,
33560
+ task
33561
+ }));
33562
+ })).then((groups) => groups.flat()), uniqueAgents);
33563
+ const foundAgents = new Set(selected.map((t) => t.agent));
33564
+ const missing = uniqueAgents.filter((agent) => !foundAgents.has(agent));
33565
+ if (missing.length > 0) warnings.push(`No tasks found for agent(s): ${missing.join(", ")}`);
33566
+ if (selected.length === 0) warnings.push("No requested agent tasks found; falling back to default selection.");
33567
+ }
33568
+ } else warnings.push("No targets specified; selecting up to 3 agents automatically.");
33569
+ if (selected.length === 0) selected = selectFallbackWatchTasks(await loadAllTasks(options.db, 500), { agentLimit: 3 });
33570
+ const executeAgentMap = await getAgentExecuteAgentMap(options.db, selected);
33571
+ return {
33572
+ targets: selected.map((entry) => ({
33573
+ ...entry,
33574
+ executeAgent: executeAgentMap.get(`${entry.agent}|${entry.task.project_id}`)
33575
+ })),
33576
+ warnings
33577
+ };
33578
+ }
33579
+ function makeStreamUrl(streamId) {
33580
+ return `${PANTHEON_BASE_URL}/ai_stream_proxy/v2/streams/${encodeURIComponent(streamId)}/stream?format=opaque-stream-json`;
33581
+ }
33582
+ async function buildStepSnapshot(options) {
33583
+ const aggregator = new WatchStepAggregator();
33584
+ let inferredSource;
33585
+ let normalizer = void 0;
33586
+ const url = makeStreamUrl(options.streamId);
33587
+ const res = await fetch(url, { headers: {
33588
+ Authorization: `Bearer ${process.env.PANTHEON_API_KEY}`,
33589
+ Accept: "text/event-stream"
33590
+ } });
33591
+ if (!res.body) return { step: aggregator.snapshot() };
33592
+ await consumeOpaqueSseStream({
33593
+ stream: res.body,
33594
+ idleTimeoutMs: options.idleTimeoutMs,
33595
+ onWarning: (warning) => aggregator.pushUiChunk({
33596
+ type: "data-agent-unknown",
33597
+ data: { reason: warning }
33598
+ }),
33599
+ onData: (payload) => {
33600
+ if (!normalizer) {
33601
+ inferredSource = options.preferredSource ?? detectStreamSourceFromRawPayload(payload) ?? "codex";
33602
+ normalizer = createAgentStreamNormalizer({
33603
+ source: inferredSource,
33604
+ emitStartChunk: false,
33605
+ includeMetaEvents: false,
33606
+ unknownChunkPolicy: "emit"
33607
+ });
33608
+ }
33609
+ const chunks = normalizer.push(payload);
33610
+ aggregator.pushUiChunks(chunks);
33611
+ }
33612
+ });
33613
+ if (normalizer) aggregator.pushUiChunks(normalizer.finish());
33614
+ return {
33615
+ step: aggregator.snapshot(),
33616
+ inferredSource
33617
+ };
33618
+ }
33619
+ async function fetchBranchSnapshot(options) {
33620
+ const { task } = options;
33621
+ if (task.status !== "running" && task.status !== "completed" && task.status !== "failed") return {};
33622
+ const branchId = "branch_id" in task ? task.branch_id ?? void 0 : void 0;
33623
+ if (!branchId) return {};
33624
+ const branch = await getPantheonBranchInfo({
33625
+ projectId: task.project_id,
33626
+ branchId
33627
+ });
33628
+ return {
33629
+ branch,
33630
+ stepIndex: branch.latest_snap?.step_index,
33631
+ streamId: branch.latest_snap?.event_stream_id ?? void 0
33632
+ };
33633
+ }
33634
+ function printSnapshotLineBlock(lines) {
33635
+ lines.forEach((line) => console.log(line));
33636
+ }
33637
+ const ANSI = {
33638
+ reset: "\x1B[0m",
33639
+ bold: "\x1B[1m",
33640
+ dim: "\x1B[2m",
33641
+ red: "\x1B[31m",
33642
+ green: "\x1B[32m",
33643
+ yellow: "\x1B[33m",
33644
+ cyan: "\x1B[36m",
33645
+ gray: "\x1B[90m"
33646
+ };
33647
+ function useAnsiStyles() {
33648
+ if (!process.stdout.isTTY) return false;
33649
+ if (process.env.NO_COLOR != null) return false;
33650
+ return true;
33651
+ }
33652
+ function sgrWrap(text, code, enabled) {
33653
+ return enabled ? `${code}${text}${ANSI.reset}` : text;
33654
+ }
33655
+ function bold(text, enabled) {
33656
+ return sgrWrap(text, ANSI.bold, enabled);
33657
+ }
33658
+ function dim(text, enabled) {
33659
+ return sgrWrap(text, ANSI.dim, enabled);
33660
+ }
33661
+ function gray(text, enabled) {
33662
+ return sgrWrap(text, ANSI.gray, enabled);
33663
+ }
33664
+ function red(text, enabled) {
33665
+ return sgrWrap(text, ANSI.red, enabled);
33666
+ }
33667
+ function green(text, enabled) {
33668
+ return sgrWrap(text, ANSI.green, enabled);
33669
+ }
33670
+ function yellow(text, enabled) {
33671
+ return sgrWrap(text, ANSI.yellow, enabled);
33672
+ }
33673
+ function cyan(text, enabled) {
33674
+ return sgrWrap(text, ANSI.cyan, enabled);
33675
+ }
33676
+ function kv(label, value, style) {
33677
+ return `${dim(`${label}:`, style)} ${value}`;
33678
+ }
33679
+ function formatTaskStatus(status, style) {
33680
+ switch (status) {
33681
+ case "running": return yellow(status, style);
33682
+ case "completed": return green(status, style);
33683
+ case "failed": return red(status, style);
33684
+ case "pending": return cyan(status, style);
33685
+ case "cancelled": return gray(status, style);
33686
+ }
33687
+ }
33688
+ function formatBranchStatus(status, style) {
33689
+ if (!status) return gray("(no branch)", style);
33690
+ switch (status) {
33691
+ case "succeed": return green(status, style);
33692
+ case "failed": return red(status, style);
33693
+ case "running":
33694
+ case "pending": return yellow(status, style);
33695
+ case "manifesting":
33696
+ case "ready_for_manifest": return cyan(status, style);
33697
+ default: return gray(status, style);
33698
+ }
33699
+ }
33700
+ function formatToolLabel(tool, style) {
33701
+ const name = tool.toolName ?? "<tool>";
33702
+ if (name === "command_execution") {
33703
+ const title = typeof tool.title === "string" ? tool.title : "";
33704
+ const inputCommand = typeof tool.input?.command === "string" ? tool.input.command : "";
33705
+ const raw = title || inputCommand;
33706
+ const display = raw ? formatCommandExecutionDisplayCommand(raw) : "(unknown command)";
33707
+ return `${bold("$", style)} ${cyan(display, style)}`;
33708
+ }
33709
+ const renderedName = bold(name, style);
33710
+ if (!tool.title) return renderedName;
33711
+ return `${renderedName}: ${tool.title}`;
33712
+ }
33713
+ function formatToolSummaryLine(tool, style) {
33714
+ const label = formatToolLabel(tool, style);
33715
+ const id = gray(tool.toolCallId, style);
33716
+ switch (tool.status) {
33717
+ case "completed": return `${green("✓", style)} ${label} (${id})`;
33718
+ case "failed": return `${red("✗", style)} ${label} (${id})`;
33719
+ default: return `${yellow("…", style)} ${label} (${id})`;
33720
+ }
33721
+ }
33722
+ function toDisplayLines(text) {
33723
+ return text.replaceAll("\r\n", "\n").split("\n");
33724
+ }
33725
+ function wrapCollapsedWhitespaceToWidth(text, width) {
33726
+ const collapsed = text.trim().replaceAll(/\s+/g, " ");
33727
+ if (!collapsed) return [];
33728
+ if (width <= 0) return [collapsed];
33729
+ const words = collapsed.split(" ");
33730
+ const lines = [];
33731
+ let current = "";
33732
+ function pushLongWord(word) {
33733
+ for (let i = 0; i < word.length; i += width) {
33734
+ const chunk = word.slice(i, i + width);
33735
+ if (chunk.length === width) lines.push(chunk);
33736
+ else current = chunk;
33737
+ }
33738
+ }
33739
+ for (const word of words) {
33740
+ if (!current) {
33741
+ if (word.length <= width) current = word;
33742
+ else pushLongWord(word);
33743
+ continue;
33744
+ }
33745
+ if (current.length + 1 + word.length <= width) {
33746
+ current += ` ${word}`;
33747
+ continue;
33748
+ }
33749
+ lines.push(current);
33750
+ current = "";
33751
+ if (word.length <= width) current = word;
33752
+ else pushLongWord(word);
33753
+ }
33754
+ if (current) lines.push(current);
33755
+ return lines;
33756
+ }
33757
+ function formatWrappedPreviewLines(label, text, options) {
33758
+ const trimmed = text.trim();
33759
+ if (!trimmed) return [];
33760
+ const prefixVisible = visibleLength(`${label}: `);
33761
+ const kept = trimLinesWithEllipsis(wrapCollapsedWhitespaceToWidth(trimmed, Math.max(10, options.widthHint - prefixVisible)), options.maxLines);
33762
+ const indent = " ".repeat(prefixVisible);
33763
+ return kept.map((line, idx) => {
33764
+ const value = options.formatValue ? options.formatValue(line) : line;
33765
+ return idx === 0 ? `${label}: ${value}` : `${indent}${value}`;
33766
+ });
33767
+ }
33768
+ function trimLinesWithEllipsis(lines, maxLines) {
33769
+ if (maxLines <= 0) return [];
33770
+ if (lines.length <= maxLines) return lines;
33771
+ const kept = lines.slice(0, maxLines);
33772
+ const lastIndex = kept.length - 1;
33773
+ const last = kept[lastIndex]?.trimEnd() ?? "";
33774
+ kept[lastIndex] = last ? `${last}…` : "…";
33775
+ return kept;
33776
+ }
33777
+ function formatToolResultPreviewLines(tool, options) {
33778
+ if (tool.status === "in_progress") return [];
33779
+ if (options.maxLines <= 0) return [];
33780
+ if (tool.status === "failed") {
33781
+ const lines = trimLinesWithEllipsis(toDisplayLines(tool.errorText ?? "(no error text)"), options.maxLines);
33782
+ const prefix = dim("error:", options.style);
33783
+ return lines.map((line, idx) => idx === 0 ? `${prefix} ${line}` : ` ${line}`);
33784
+ }
33785
+ if (tool.output == null) return [`${dim("output:", options.style)} (none)`];
33786
+ if (tool.toolName === "command_execution") {
33787
+ const output = tool.output;
33788
+ const exitCode = output?.exit_code ?? null;
33789
+ const outLines = trimLinesWithEllipsis(toDisplayLines((typeof output?.aggregated_output === "string" ? output.aggregated_output : "").trimEnd()), options.maxLines);
33790
+ const exitCodeLabel = typeof exitCode === "number" ? exitCode === 0 ? green(String(exitCode), options.style) : red(String(exitCode), options.style) : gray(String(exitCode), options.style);
33791
+ const outputPrefix = dim("output:", options.style);
33792
+ if (outLines.length === 0) return [`${outputPrefix} exit_code=${exitCodeLabel}`];
33793
+ return outLines.map((line, idx) => idx === 0 ? `${outputPrefix} exit_code=${exitCodeLabel} ${line}` : ` ${line}`);
33794
+ }
33795
+ const lines = trimLinesWithEllipsis(toDisplayLines(inspect(tool.output, {
33796
+ depth: 6,
33797
+ maxArrayLength: 50,
33798
+ maxStringLength: 1e3,
33799
+ compact: true,
33800
+ breakLength: Math.max(20, options.widthHint)
33801
+ })), options.maxLines);
33802
+ const outputPrefix = dim("output:", options.style);
33803
+ return lines.map((line, idx) => idx === 0 ? `${outputPrefix} ${line}` : ` ${line}`);
33804
+ }
33805
+ function formatToolBlocks(step, options) {
33806
+ const tools = options.maxTools != null ? step.toolActions.slice(-options.maxTools) : step.toolActions;
33807
+ if (tools.length === 0) return [` ${gray("(none)", options.style)}`];
33808
+ const widthHint = Math.max(20, options.widthHint);
33809
+ const out = [];
33810
+ for (const tool of tools) {
33811
+ out.push(` ${formatToolSummaryLine(tool, options.style)}`);
33812
+ formatToolResultPreviewLines(tool, {
33813
+ maxLines: options.maxResultLines,
33814
+ widthHint: widthHint - 4,
33815
+ style: options.style
33816
+ }).forEach((line) => out.push(` ${line}`));
33817
+ }
33818
+ return out.map((line) => clip(line, widthHint));
33819
+ }
33820
+ const ANSI_SGR_REGEX = /\u001b\[[0-9;]*m/g;
33821
+ function visibleLength(value) {
33822
+ return value.replaceAll(ANSI_SGR_REGEX, "").length;
33823
+ }
33824
+ function sliceSgrByVisibleWidth(value, maxVisible) {
33825
+ if (maxVisible <= 0) return "";
33826
+ let out = "";
33827
+ let visible = 0;
33828
+ for (let i = 0; i < value.length; i++) {
33829
+ if (visible >= maxVisible) break;
33830
+ const ch = value[i];
33831
+ if (ch === "\x1B" && value[i + 1] === "[") {
33832
+ const end = value.indexOf("m", i);
33833
+ if (end === -1) break;
33834
+ out += value.slice(i, end + 1);
33835
+ i = end;
33836
+ continue;
33837
+ }
33838
+ out += ch;
33839
+ visible += 1;
33840
+ }
33841
+ return out;
33842
+ }
33843
+ function clip(value, maxVisible) {
33844
+ if (maxVisible <= 0) return "";
33845
+ if (visibleLength(value) <= maxVisible) return value;
33846
+ if (maxVisible === 1) return "…";
33847
+ const sliced = sliceSgrByVisibleWidth(value, maxVisible - 1);
33848
+ return `${sliced}…${sliced.includes("\x1B[") ? ANSI.reset : ""}`;
33849
+ }
33850
+ function createWatchCommand(version) {
33851
+ return createCommand("watch").version(version).description("Inspect task progress via live/near-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("--follow", "Follow mode: live updating TUI.", false).option("--idle-timeout-seconds <seconds>", "Snapshot mode: stop reading a stream after this many seconds with no new messages.", (val) => parseFloat(val), 3).action(async function() {
33852
+ ensureEnvOrExit(["PANTHEON_API_KEY", "DATABASE_URL"]);
33853
+ const options = this.opts();
33854
+ if (options.tasks.length > 0 && options.agents.length > 0) {
33855
+ console.error("Use either --tasks or --agents, not both.");
33856
+ process.exit(1);
33857
+ }
33858
+ const idleTimeoutMs = Math.max(0, options.idleTimeoutSeconds * 1e3);
33859
+ const db = createDb();
33860
+ try {
33861
+ const { targets, warnings } = await resolveWatchTargets({
33862
+ db,
33863
+ taskIds: options.tasks,
33864
+ agentNames: options.agents
33865
+ });
33866
+ warnings.forEach((w) => console.error(`warning: ${w}`));
33867
+ if (targets.length === 0) {
33868
+ console.error("No tasks found to watch.");
33869
+ process.exit(1);
33870
+ }
33871
+ if (!options.follow) {
33872
+ const style = useAnsiStyles();
33873
+ const widthHint = process.stdout.columns ?? 120;
33874
+ const now = /* @__PURE__ */ new Date();
33875
+ for (const target of targets) {
33876
+ const { task } = target;
33877
+ const elapsedMs = getTaskElapsedMs(task, now);
33878
+ let branchInfo = {};
33879
+ try {
33880
+ branchInfo = await fetchBranchSnapshot({ task });
33881
+ } catch (error) {
33882
+ console.error(`warning: failed to fetch branch info for task ${task.id}: ${error instanceof Error ? error.message : String(error)}`);
33883
+ }
33884
+ const preferredSource = toStreamSourceFromExecuteAgent(target.executeAgent);
33885
+ let stepSnapshot = void 0;
33886
+ let inferredSource = void 0;
33887
+ if (branchInfo.streamId) try {
33888
+ const result = await buildStepSnapshot({
33889
+ streamId: branchInfo.streamId,
33890
+ preferredSource,
33891
+ idleTimeoutMs
33892
+ });
33893
+ stepSnapshot = result.step;
33894
+ inferredSource = result.inferredSource;
33895
+ } catch (error) {
33896
+ console.error(`warning: failed to read stream for task ${task.id}: ${error instanceof Error ? error.message : String(error)}`);
33897
+ }
33898
+ const lines = [];
33899
+ const sep = gray(" • ", style);
33900
+ lines.push([
33901
+ kv("task", task.id, style),
33902
+ kv("status", formatTaskStatus(task.status, style), style),
33903
+ kv("agent", target.agent, style)
33904
+ ].join(sep));
33905
+ const branchId = "branch_id" in task ? task.branch_id ?? void 0 : void 0;
33906
+ const mergedBranchLine = [
33907
+ kv("project", task.project_id, style),
33908
+ branchId ? kv("branch", branchId, style) : void 0,
33909
+ branchId || branchInfo.branch?.status ? kv("branch_status", formatBranchStatus(branchInfo.branch?.status, style), style) : void 0,
33910
+ branchInfo.stepIndex != null ? kv("step", String(branchInfo.stepIndex), style) : void 0
33911
+ ].filter(Boolean).join(sep);
33912
+ if (mergedBranchLine) lines.push(mergedBranchLine);
33913
+ if (branchInfo.streamId) {
33914
+ const src = preferredSource ?? inferredSource;
33915
+ const mergedStreamLine = [kv("stream", branchInfo.streamId, style), src ? kv("source", src, style) : void 0].filter(Boolean).join(sep);
33916
+ if (mergedStreamLine) lines.push(mergedStreamLine);
33917
+ }
33918
+ const start = getTaskStartTime(task);
33919
+ const mergedTimingLine = [start ? kv("started", start.toISOString(), style) : void 0, kv("elapsed", formatDurationMs(elapsedMs), style)].filter(Boolean).join(sep);
33920
+ if (mergedTimingLine) lines.push(mergedTimingLine);
33921
+ if (stepSnapshot) {
33922
+ const reasoningLine = formatPreviewLine(dim("reasoning", style), stepSnapshot.leadingReasoning, { formatValue: (value) => gray(value, style) });
33923
+ if (reasoningLine) lines.push(reasoningLine);
33924
+ lines.push(bold("tools:", style));
33925
+ lines.push(...formatToolBlocks(stepSnapshot, {
33926
+ style,
33927
+ widthHint,
33928
+ maxResultLines: 3
33929
+ }));
33930
+ const messageLine = formatPreviewLine(dim("message", style), stepSnapshot.leadingText);
33931
+ if (messageLine) lines.push(messageLine);
33932
+ if (stepSnapshot.warnings.length > 0) lines.push(kv("warnings", yellow(`${stepSnapshot.warnings.length} (unknown=${stepSnapshot.unknownEventCount})`, style), style));
33933
+ } else lines.push(`${bold("tools:", style)} ${gray("(no stream)", style)}`);
33934
+ printSnapshotLineBlock(lines.map((line) => clip(line, widthHint)));
33935
+ console.log("");
33936
+ }
33937
+ return;
33938
+ }
33939
+ if (!process.stdout.isTTY) {
33940
+ console.error("--follow requires a TTY.");
33941
+ process.exit(1);
33942
+ }
33943
+ const abortController = new AbortController();
33944
+ const onSigInt = () => abortController.abort();
33945
+ process.on("SIGINT", onSigInt);
33946
+ const runtime = targets.map((target) => ({
33947
+ target,
33948
+ aggregator: new WatchStepAggregator({ maxLogLines: 120 }),
33949
+ streamDone: false
33950
+ }));
33951
+ function isTerminalBranchStatus(status) {
33952
+ return status === "succeed" || status === "failed";
33953
+ }
33954
+ async function startStream(rt, streamId) {
33955
+ rt.streamAbort?.abort();
33956
+ rt.streamAbort = new AbortController();
33957
+ rt.streamDone = false;
33958
+ const preferred = toStreamSourceFromExecuteAgent(rt.target.executeAgent);
33959
+ rt.source = preferred;
33960
+ const url = makeStreamUrl(streamId);
33961
+ (async () => {
33962
+ try {
33963
+ const res = await fetch(url, {
33964
+ headers: {
33965
+ Authorization: `Bearer ${process.env.PANTHEON_API_KEY}`,
33966
+ Accept: "text/event-stream"
33967
+ },
33968
+ signal: rt.streamAbort.signal
33969
+ });
33970
+ if (!res.body) {
33971
+ rt.lastError = "missing response body";
33972
+ rt.streamDone = true;
33973
+ return;
33974
+ }
33975
+ let normalizer;
33976
+ await consumeOpaqueSseStream({
33977
+ stream: res.body,
33978
+ signal: rt.streamAbort.signal,
33979
+ onWarning: (warning) => rt.aggregator.pushUiChunk({
33980
+ type: "data-agent-unknown",
33981
+ data: { reason: warning }
33982
+ }),
33983
+ onData: (payload) => {
33984
+ if (!normalizer) {
33985
+ rt.source = preferred ?? detectStreamSourceFromRawPayload(payload) ?? "codex";
33986
+ normalizer = createAgentStreamNormalizer({
33987
+ source: rt.source,
33988
+ emitStartChunk: false,
33989
+ includeMetaEvents: false,
33990
+ unknownChunkPolicy: "emit"
33991
+ });
33992
+ }
33993
+ rt.aggregator.pushUiChunks(normalizer.push(payload));
33994
+ }
33995
+ });
33996
+ if (normalizer) rt.aggregator.pushUiChunks(normalizer.finish());
33997
+ rt.streamDone = true;
33998
+ } catch (error) {
33999
+ if (rt.streamAbort?.signal.aborted) {
34000
+ rt.streamDone = true;
34001
+ return;
34002
+ }
34003
+ rt.lastError = error instanceof Error ? error.message : String(error);
34004
+ rt.streamDone = true;
34005
+ }
34006
+ })();
34007
+ }
34008
+ async function pollBranchesOnce() {
34009
+ await Promise.all(runtime.map(async (rt) => {
34010
+ const { task } = rt.target;
34011
+ if (task.status !== "running" && task.status !== "completed" && task.status !== "failed") return;
34012
+ const branchId = "branch_id" in task ? task.branch_id ?? void 0 : void 0;
34013
+ if (!branchId) return;
34014
+ try {
34015
+ const branch = await getPantheonBranchInfo({
34016
+ projectId: task.project_id,
34017
+ branchId
34018
+ });
34019
+ rt.branch = branch;
34020
+ rt.stepIndex = branch.latest_snap?.step_index;
34021
+ const nextStreamId = branch.latest_snap?.event_stream_id ?? void 0;
34022
+ if (nextStreamId && nextStreamId !== rt.streamId) {
34023
+ rt.streamId = nextStreamId;
34024
+ rt.aggregator = new WatchStepAggregator({ maxLogLines: 120 });
34025
+ await startStream(rt, nextStreamId);
34026
+ }
34027
+ } catch (error) {
34028
+ rt.lastError = error instanceof Error ? error.message : String(error);
34029
+ }
34030
+ }));
34031
+ }
34032
+ const screen = blessed.screen({
34033
+ smartCSR: true,
34034
+ title: "pantheon-agents watch"
34035
+ });
34036
+ screen.key(["q", "C-c"], () => abortController.abort());
34037
+ const footer = blessed.box({
34038
+ parent: screen,
34039
+ bottom: 0,
34040
+ left: 0,
34041
+ height: 1,
34042
+ width: "100%",
34043
+ tags: false,
34044
+ content: "Ctrl+C to exit • q to quit",
34045
+ style: { fg: "gray" }
34046
+ });
34047
+ const panes = runtime.map(() => blessed.box({
34048
+ parent: screen,
34049
+ top: 0,
34050
+ left: 0,
34051
+ height: "100%-1",
34052
+ width: "100%",
34053
+ border: "line",
34054
+ tags: false,
34055
+ scrollable: false,
34056
+ wrap: false,
34057
+ style: { border: { fg: "gray" } }
34058
+ }));
34059
+ let lastGlobalError;
34060
+ function layoutPanes(columns) {
34061
+ const n = panes.length;
34062
+ for (let i = 0; i < n; i++) {
34063
+ const left = Math.floor(i * columns / n);
34064
+ const right = Math.floor((i + 1) * columns / n);
34065
+ panes[i].left = left;
34066
+ panes[i].width = Math.max(1, right - left);
34067
+ }
34068
+ }
34069
+ const renderTimer = setInterval(() => {
34070
+ const style = useAnsiStyles();
34071
+ const columns = Math.max(40, screen.width ?? 120);
34072
+ const rows = Math.max(8, screen.height ?? 24);
34073
+ layoutPanes(columns);
34074
+ const paneWidth = Math.max(1, Math.floor(columns / runtime.length));
34075
+ const paneInnerWidth = Math.max(0, paneWidth - 2);
34076
+ const paneOuterHeight = Math.max(1, rows - 1);
34077
+ const maxContentLines = Math.max(0, paneOuterHeight - 2);
34078
+ const nextFooterParts = ["Ctrl+C to exit", "q to quit"];
34079
+ if (lastGlobalError) nextFooterParts.push(`error: ${lastGlobalError}`);
34080
+ footer.setContent(nextFooterParts.join(" • "));
34081
+ runtime.forEach((rt, idx) => {
34082
+ const { task } = rt.target;
34083
+ const step = rt.aggregator.snapshot();
34084
+ const elapsed = formatDurationMs(getTaskElapsedMs(task, /* @__PURE__ */ new Date()));
34085
+ const title = [
34086
+ rt.target.agent,
34087
+ `task ${task.id}`,
34088
+ formatTaskStatus(task.status, style),
34089
+ formatBranchStatus(rt.branch?.status, style),
34090
+ rt.stepIndex != null ? `step ${rt.stepIndex}` : void 0,
34091
+ `elapsed ${elapsed}`
34092
+ ].filter(Boolean).join(gray(" • ", style));
34093
+ const branchId = "branch_id" in task ? task.branch_id ?? void 0 : void 0;
34094
+ const headerLines = [kv("project", task.project_id, style), kv("branch", branchId ? branchId : gray("(no branch)", style), style)];
34095
+ const reasoningLines = formatWrappedPreviewLines(dim("reasoning", style), step.leadingReasoning, {
34096
+ maxLines: 4,
34097
+ widthHint: paneInnerWidth,
34098
+ formatValue: (value) => gray(value, style)
34099
+ });
34100
+ const messageLine = formatPreviewLine(dim("message", style), step.leadingText);
34101
+ const extraLines = [];
34102
+ if (rt.lastError) extraLines.push(kv("error", red(rt.lastError, style), style));
34103
+ if (step.warnings.length > 0) extraLines.push(kv("warnings", yellow(`${step.warnings.length} (unknown=${step.unknownEventCount})`, style), style));
34104
+ const toolLines = step.toolActions.filter((t) => t.toolName !== "command_execution").slice(-3).map((tool) => formatToolSummaryLine(tool, style));
34105
+ const baseLines = [
34106
+ ...headerLines,
34107
+ ...reasoningLines,
34108
+ ...toolLines,
34109
+ ...messageLine ? [messageLine] : [],
34110
+ ...extraLines
34111
+ ];
34112
+ const remainingForLogs = Math.max(0, maxContentLines - baseLines.length);
34113
+ const logLines = step.logLines.slice(-remainingForLogs);
34114
+ panes[idx].setLabel(title);
34115
+ panes[idx].setContent([...baseLines, ...logLines].map((line) => clip(line, paneInnerWidth)).join("\n"));
34116
+ });
34117
+ screen.render();
34118
+ }, 300);
34119
+ let pollTimer;
34120
+ let doneTimer;
34121
+ try {
34122
+ await pollBranchesOnce();
34123
+ if (abortController.signal.aborted) return;
34124
+ pollTimer = setInterval(() => {
34125
+ pollBranchesOnce().catch((e) => {
34126
+ lastGlobalError = e instanceof Error ? e.message : String(e);
34127
+ });
34128
+ }, 2e3);
34129
+ await new Promise((resolve) => {
34130
+ let resolved = false;
34131
+ const resolveOnce = () => {
34132
+ if (resolved) return;
34133
+ resolved = true;
34134
+ if (doneTimer) {
34135
+ clearInterval(doneTimer);
34136
+ doneTimer = void 0;
34137
+ }
34138
+ resolve();
34139
+ };
34140
+ abortController.signal.addEventListener("abort", resolveOnce, { once: true });
34141
+ if (abortController.signal.aborted) {
34142
+ resolveOnce();
34143
+ return;
34144
+ }
34145
+ const terminalGraceMs = Math.max(1e3, idleTimeoutMs);
34146
+ let terminalSince;
34147
+ doneTimer = setInterval(() => {
34148
+ const now = Date.now();
34149
+ if (!runtime.every((rt) => isTerminalBranchStatus(rt.branch?.status))) {
34150
+ terminalSince = void 0;
34151
+ return;
34152
+ }
34153
+ terminalSince ??= now;
34154
+ if (runtime.every((rt) => !rt.streamId || rt.streamDone)) {
34155
+ resolveOnce();
34156
+ return;
34157
+ }
34158
+ if (now - terminalSince >= terminalGraceMs) resolveOnce();
34159
+ }, 1e3);
34160
+ });
34161
+ } finally {
34162
+ process.off("SIGINT", onSigInt);
34163
+ clearInterval(renderTimer);
34164
+ if (pollTimer) clearInterval(pollTimer);
34165
+ if (doneTimer) clearInterval(doneTimer);
34166
+ runtime.forEach((rt) => rt.streamAbort?.abort());
34167
+ screen.destroy();
34168
+ }
34169
+ } finally {
34170
+ await db.destroy();
34171
+ }
34172
+ });
34173
+ }
34174
+
32248
34175
  //#endregion
32249
34176
  //#region src/cli/index.ts
32250
- const program = new Command().name("pantheon-agents").description("Pantheon agents CLI").version(version$1).showHelpAfterError().showSuggestionAfterError().addHelpCommand().addCommand(createAddTaskCommand(version$1)).addCommand(createConfigAgentCommand(version$1)).addCommand(createDeleteTaskCommand(version$1)).addCommand(createReconfigAgentCommand(version$1)).addCommand(createRunAgentCommand(version$1)).addCommand(createServerCommand(version$1)).addCommand(createShowConfigCommand(version$1)).addCommand(createShowTasksCommand(version$1));
34177
+ const program = new Command().name("pantheon-agents").description("Pantheon agents CLI").version(version$1).showHelpAfterError().showSuggestionAfterError().addHelpCommand().addCommand(createAddTaskCommand(version$1)).addCommand(createConfigAgentCommand(version$1)).addCommand(createDeleteTaskCommand(version$1)).addCommand(createReconfigAgentCommand(version$1)).addCommand(createRunAgentCommand(version$1)).addCommand(createServerCommand(version$1)).addCommand(createShowConfigCommand(version$1)).addCommand(createShowTasksCommand(version$1)).addCommand(createWatchCommand(version$1));
32251
34178
  async function main() {
32252
34179
  if (process$1.argv.length <= 2) {
32253
34180
  program.outputHelp();