@pantheon.ai/agents 0.0.10 → 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 (3) hide show
  1. package/README.md +43 -6
  2. package/dist/index.js +2311 -151
  3. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- import * as process$1 from "node:process";
4
- import { createCommand } from "commander";
3
+ import { Command, createCommand } from "commander";
4
+ import process$1 from "node:process";
5
5
  import * as fs from "node:fs";
6
6
  import path from "node:path";
7
7
  import { multistream, pino, transport } from "pino";
@@ -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.10";
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) {
@@ -9780,38 +10109,37 @@ async function runAgent(name, options, logger) {
9780
10109
  }
9781
10110
  async function configAgent(name, options) {
9782
10111
  const provider = new TaskListTidbProvider(name, pino());
9783
- const previousConfig = await provider.getAgentConfig(options.projectId);
9784
- if (previousConfig) if (previousConfig.role === options.role) {
9785
- console.log(`Agent ${name} already configured as ${options.role} for project ${options.projectId}.`);
9786
- console.log(`Base branch id: ${previousConfig.base_branch_id}`);
9787
- await provider.close();
9788
- return;
9789
- } else {
9790
- console.error(`Agent ${name} already configured as ${previousConfig.role} for project ${options.projectId}.`);
9791
- console.error(`Base branch id: ${previousConfig.base_branch_id}`);
9792
- console.error(`Cannot change role to ${options.role}`);
9793
- await provider.close();
9794
- process.exitCode = 1;
9795
- return;
9796
- }
9797
- console.log(`Configuring agent ${name} as ${options.role} for project ${options.projectId}.`);
9798
- if (!options.rootBranchId) {
9799
- console.log("No root branch id specified, using project root branch.");
9800
- const project = await getPantheonProjectInfo({ projectId: options.projectId });
9801
- if (!project.root_branch_id) {
9802
- console.error(`Project ${options.projectId} has no root branch. Project status is ${project.status}`);
9803
- await provider.close();
10112
+ try {
10113
+ const previousConfig = await provider.getAgentConfig(options.projectId);
10114
+ if (previousConfig) {
10115
+ if (previousConfig.role === options.role) {
10116
+ console.log(`Agent ${name} already configured as ${options.role} for project ${options.projectId}.`);
10117
+ console.log(`Base branch id: ${previousConfig.base_branch_id}`);
10118
+ return;
10119
+ }
10120
+ console.error(`Agent ${name} already configured as ${previousConfig.role} for project ${options.projectId}.`);
10121
+ console.error(`Base branch id: ${previousConfig.base_branch_id}`);
10122
+ console.error(`Cannot change role to ${options.role}`);
9804
10123
  process.exitCode = 1;
9805
10124
  return;
9806
10125
  }
9807
- options.rootBranchId = project.root_branch_id;
9808
- }
9809
- if (options.bootstrap) {
9810
- const branchId = await executeOnPantheon({
9811
- projectId: options.projectId,
9812
- branchId: options.rootBranchId,
9813
- agent: "codex",
9814
- prompt: `You must follow these instructions":
10126
+ console.log(`Configuring agent ${name} as ${options.role} for project ${options.projectId}.`);
10127
+ if (!options.rootBranchId) {
10128
+ console.log("No root branch id specified, using project root branch.");
10129
+ const project = await getPantheonProjectInfo({ projectId: options.projectId });
10130
+ if (!project.root_branch_id) {
10131
+ console.error(`Project ${options.projectId} has no root branch. Project status is ${project.status}`);
10132
+ process.exitCode = 1;
10133
+ return;
10134
+ }
10135
+ options.rootBranchId = project.root_branch_id;
10136
+ }
10137
+ if (options.bootstrap) {
10138
+ const branchId = await executeOnPantheon({
10139
+ projectId: options.projectId,
10140
+ branchId: options.rootBranchId,
10141
+ agent: "codex",
10142
+ prompt: `You must follow these instructions":
9815
10143
  1. Clone the main branch from ${options.prototypeUrl} to a temporary directory (<pantheon-agents> in follow instructions references to this directory).
9816
10144
  2. Copy the <pantheon-agents>/agents/${options.role}/AGENTS.md to \`<workspace>/AGENTS.md\`.
9817
10145
  3. Copy the <pantheon-agents>/agents/${options.role}/skills directory to \`<workspace>/.codex/skills\` if the source directory exists.
@@ -9825,58 +10153,61 @@ Validate <workspace>: check if files and directorys exists:
9825
10153
 
9826
10154
  Finally, outputs the first 5 lines of <workspace>/AGENTS.md and the skills list in <workspace>/.codex/skills
9827
10155
  `
9828
- });
9829
- let retried = 0;
9830
- const maxRetries = 3;
9831
- let i = 0;
9832
- console.log(`Bootstrap branch created: ${branchId}. Waiting for ready... [poll interval = 10s]`);
9833
- while (true) {
9834
- await new Promise((resolve) => {
9835
- setTimeout(resolve, 1e4);
9836
10156
  });
9837
- const result = await getPantheonBranch({
9838
- branchId,
9839
- projectId: options.projectId,
9840
- getOutputIfFinished: true
9841
- }).then((result) => {
9842
- retried = 0;
9843
- return result;
9844
- }).catch((reason) => {
9845
- if (retried < maxRetries) {
9846
- retried++;
9847
- return { state: "others" };
9848
- } else throw new Error(`Failed to get bootstrap branch status. Retry ${retried} times. Last error: ${getErrorMessage(reason)}`);
10157
+ let retried = 0;
10158
+ const maxRetries = 3;
10159
+ let i = 0;
10160
+ console.log(`Bootstrap branch created: ${branchId}. Waiting for ready... [poll interval = 10s]`);
10161
+ while (true) {
10162
+ await new Promise((resolve) => {
10163
+ setTimeout(resolve, 1e4);
10164
+ });
10165
+ const result = await getPantheonBranch({
10166
+ branchId,
10167
+ projectId: options.projectId,
10168
+ getOutputIfFinished: true
10169
+ }).then((result) => {
10170
+ retried = 0;
10171
+ return result;
10172
+ }).catch((reason) => {
10173
+ if (retried < maxRetries) {
10174
+ retried++;
10175
+ return { state: "others" };
10176
+ }
10177
+ throw new Error(`Failed to get bootstrap branch status. Retry ${retried} times. Last error: ${getErrorMessage(reason)}`);
10178
+ });
10179
+ if (result.state === "failed") {
10180
+ console.error("Bootstrap failed: " + result.error);
10181
+ process.exitCode = 1;
10182
+ return;
10183
+ }
10184
+ if (result.state === "succeed") {
10185
+ console.log("Bootstrap succeeded. Output is:");
10186
+ console.log(result.output);
10187
+ break;
10188
+ }
10189
+ console.log(`Bootstrap in progress... [${++i}]`);
10190
+ }
10191
+ await provider.setAgentConfig({
10192
+ project_id: options.projectId,
10193
+ base_branch_id: branchId,
10194
+ execute_agent: options.executeAgent,
10195
+ role: options.role,
10196
+ skills: options.skills,
10197
+ prototype_url: options.prototypeUrl
9849
10198
  });
9850
- if (result.state === "failed") {
9851
- console.error("Bootstrap failed: " + result.error);
9852
- await provider.close();
9853
- process.exit(1);
9854
- }
9855
- if (result.state === "succeed") {
9856
- console.log("Bootstrap succeeded. Output is:");
9857
- console.log(result.output);
9858
- break;
9859
- }
9860
- console.log(`Bootstrap in progress... [${++i}]`);
9861
- }
9862
- await provider.setAgentConfig({
10199
+ } else await provider.setAgentConfig({
9863
10200
  project_id: options.projectId,
9864
- base_branch_id: branchId,
10201
+ base_branch_id: options.rootBranchId,
9865
10202
  execute_agent: options.executeAgent,
9866
10203
  role: options.role,
9867
10204
  skills: options.skills,
9868
10205
  prototype_url: options.prototypeUrl
9869
10206
  });
9870
- } else await provider.setAgentConfig({
9871
- project_id: options.projectId,
9872
- base_branch_id: options.rootBranchId,
9873
- execute_agent: options.executeAgent,
9874
- role: options.role,
9875
- skills: options.skills,
9876
- prototype_url: options.prototypeUrl
9877
- });
9878
- console.log(`Agent ${name} configured successfully.`);
9879
- await provider.close();
10207
+ console.log(`Agent ${name} configured successfully.`);
10208
+ } finally {
10209
+ await provider.close();
10210
+ }
9880
10211
  }
9881
10212
  async function reconfigAgentWithDeps(name, options, deps) {
9882
10213
  const previousConfig = await deps.provider.getAgentConfig(options.projectId);
@@ -9939,15 +10270,18 @@ async function reconfigAgent(name, options) {
9939
10270
  }
9940
10271
  async function addTask(name, options) {
9941
10272
  const provider = new TaskListTidbProvider(name, pino());
9942
- const config = await provider.getAgentConfig(options.projectId);
9943
- if (!config) throw new Error(`Agent ${name} not configured for project ${options.projectId}`);
9944
- const task = await provider.createTask({
9945
- task: options.prompt,
9946
- project_id: options.projectId,
9947
- base_branch_id: config.base_branch_id
9948
- });
9949
- console.log(`Task ${task.task} queued successfully.`);
9950
- await provider.close();
10273
+ try {
10274
+ const config = await provider.getAgentConfig(options.projectId);
10275
+ if (!config) throw new Error(`Agent ${name} not configured for project ${options.projectId}`);
10276
+ const task = await provider.createTask({
10277
+ task: options.prompt,
10278
+ project_id: options.projectId,
10279
+ base_branch_id: config.base_branch_id
10280
+ });
10281
+ console.log(`Queued task ${task.id} successfully.`);
10282
+ } finally {
10283
+ await provider.close();
10284
+ }
9951
10285
  }
9952
10286
  async function deleteTask(agentName, taskId) {
9953
10287
  const provider = new TaskListTidbProvider(agentName, pino());
@@ -10102,11 +10436,22 @@ async function assertsSingleton(logger, pidFile) {
10102
10436
  }
10103
10437
  }
10104
10438
 
10439
+ //#endregion
10440
+ //#region src/cli/utils/env.ts
10441
+ function ensureEnv(keys) {
10442
+ const missing = keys.filter((key) => !process.env[key]);
10443
+ if (missing.length === 0) return true;
10444
+ for (const key of missing) console.error(`${key} environment variable is not set.`);
10445
+ process.exitCode = 1;
10446
+ return false;
10447
+ }
10448
+
10105
10449
  //#endregion
10106
10450
  //#region src/cli/commands/add-task.ts
10107
10451
  function createAddTaskCommand(version) {
10108
- return createCommand("pantheon-agents add-task").version(version).description("Add a task to an agent").argument("<name>", "The name of the agent.").argument("<project-id>", "The project id of the agent.").argument("<task-prompt>", "The prompt of the task.").action(async function() {
10452
+ return createCommand("add-task").version(version).description("Add a task to an agent").argument("<name>", "The name of the agent.").argument("<project-id>", "The project id of the agent.").argument("<task-prompt>", "The prompt of the task.").action(async function() {
10109
10453
  const [name, projectId, taskPrompt] = this.args;
10454
+ if (!ensureEnv(["DATABASE_URL"])) return;
10110
10455
  await addTask(name, {
10111
10456
  projectId,
10112
10457
  prompt: taskPrompt
@@ -10117,12 +10462,16 @@ function createAddTaskCommand(version) {
10117
10462
  //#endregion
10118
10463
  //#region src/cli/commands/config.ts
10119
10464
  function createConfigAgentCommand(version) {
10120
- return createCommand("pantheon-agents config").version(version).description("Configure agent for pantheon project").argument("<name>", "The name of the agent.").argument("<role>", "The role of the agent.").argument("<project-id>", "The project id of the agent.").option("--skills <skills>", "The skills of the agent. Multiple values are separated by comma.", (val) => val.split(",").map((s) => s.trim()).filter((s) => s !== ""), []).option("--execute-agent <agent>", "The execute agent of the agent.", "codex").option("--root-branch-id <branchId>", "The root branch id of the agent. Default to project root branch id.").option("--prototype-url <url>", "Role and skill definitions repo.", "https://github.com/pingcap-inc/pantheon-agents").option("--no-bootstrap", "Prevent bootstrap base branch for agent. Use the root branch as base branch.").action(async function() {
10465
+ return createCommand("config").version(version).description("Configure agent for pantheon project").argument("<name>", "The name of the agent.").argument("<role>", "The role of the agent.").argument("<project-id>", "The project id of the agent.").option("--skills <skills>", "The skills of the agent. Multiple values are separated by comma.", (val) => val.split(",").map((s) => s.trim()).filter((s) => s !== ""), []).option("--execute-agent <agent>", "The execute agent of the agent.", "codex").option("--root-branch-id <branchId>", "The root branch id of the agent. Default to project root branch id.").option("--prototype-url <url>", "Role and skill definitions repo.", "https://github.com/pingcap-inc/pantheon-agents").option("--no-bootstrap", "Prevent bootstrap base branch for agent. Use the root branch as base branch.").action(async function() {
10121
10466
  const [name, role, projectId] = this.args;
10467
+ const options = this.opts();
10468
+ const requiredEnvVars = ["DATABASE_URL"];
10469
+ if (options.bootstrap || !options.rootBranchId) requiredEnvVars.push("PANTHEON_API_KEY");
10470
+ if (!ensureEnv(requiredEnvVars)) return;
10122
10471
  await configAgent(name, {
10123
10472
  role,
10124
10473
  projectId,
10125
- ...this.opts()
10474
+ ...options
10126
10475
  });
10127
10476
  });
10128
10477
  }
@@ -10130,8 +10479,9 @@ function createConfigAgentCommand(version) {
10130
10479
  //#endregion
10131
10480
  //#region src/cli/commands/delete-task.ts
10132
10481
  function createDeleteTaskCommand(version) {
10133
- return createCommand("pantheon-agents delete-task").version(version).description("Delete a task for an agent").argument("<name>", "The name of the agent.").argument("<task-id>", "The id of the task.").action(async function() {
10482
+ return createCommand("delete-task").version(version).description("Delete a task for an agent").argument("<name>", "The name of the agent.").argument("<task-id>", "The id of the task.").action(async function() {
10134
10483
  const [name, taskId] = this.args;
10484
+ if (!ensureEnv(["DATABASE_URL"])) return;
10135
10485
  const rl = readline.createInterface({
10136
10486
  input: process$1.stdin,
10137
10487
  output: process$1.stdout
@@ -10139,16 +10489,19 @@ function createDeleteTaskCommand(version) {
10139
10489
  try {
10140
10490
  if ((await rl.question(`Type the task id (${taskId}) to confirm deletion: `)).trim() !== taskId) {
10141
10491
  console.error("Confirmation failed. Task id did not match.");
10142
- process$1.exit(1);
10492
+ process$1.exitCode = 1;
10493
+ return;
10143
10494
  }
10144
10495
  if ((await rl.question("Type DELETE to permanently remove this task: ")).trim() !== "DELETE") {
10145
10496
  console.error("Confirmation failed. Aborting deletion.");
10146
- process$1.exit(1);
10497
+ process$1.exitCode = 1;
10498
+ return;
10147
10499
  }
10148
10500
  const deletedTask = await deleteTask(name, taskId);
10149
10501
  if (!deletedTask) {
10150
10502
  console.error(`Task ${taskId} not found for agent ${name}.`);
10151
- process$1.exit(1);
10503
+ process$1.exitCode = 1;
10504
+ return;
10152
10505
  }
10153
10506
  console.log(`Deleted task ${taskId} for agent ${name}. Status was ${deletedTask.status}.`);
10154
10507
  } finally {
@@ -10177,33 +10530,31 @@ function parseUniqueCommaList(value) {
10177
10530
  //#endregion
10178
10531
  //#region src/cli/commands/reconfig.ts
10179
10532
  function createReconfigAgentCommand(version) {
10180
- return createCommand("pantheon-agents reconfig").version(version).description("Re-bootstrap an existing agent configuration for a project").argument("<name>", "The name of the agent.").argument("<project-id>", "The project id of the agent.").option("--role <role>", "Override role for the agent.").option("--skills <skills>", "Override skills for the agent (comma-separated, replaces existing list).", parseUniqueCommaList).action(async function() {
10533
+ return createCommand("reconfig").version(version).description("Re-bootstrap an existing agent configuration for a project").argument("<name>", "The name of the agent.").argument("<project-id>", "The project id of the agent.").option("--role <role>", "Override role for the agent.").option("--skills <skills>", "Override skills for the agent (comma-separated, replaces existing list).", parseUniqueCommaList).action(async function() {
10181
10534
  const [name, projectId] = this.args;
10182
10535
  const options = this.opts();
10536
+ if (!ensureEnv(["DATABASE_URL", "PANTHEON_API_KEY"])) return;
10183
10537
  const resolvedRole = options.role?.trim();
10184
10538
  if (options.role != null && !resolvedRole) {
10185
10539
  console.error("--role must be non-empty.");
10186
- process$1.exit(1);
10187
- }
10188
- try {
10189
- await reconfigAgent(name, {
10190
- projectId,
10191
- role: resolvedRole,
10192
- skills: options.skills
10193
- });
10194
- } catch (error) {
10195
- console.error(getErrorMessage(error));
10196
- process$1.exit(1);
10540
+ process$1.exitCode = 1;
10541
+ return;
10197
10542
  }
10543
+ await reconfigAgent(name, {
10544
+ projectId,
10545
+ role: resolvedRole,
10546
+ skills: options.skills
10547
+ });
10198
10548
  });
10199
10549
  }
10200
10550
 
10201
10551
  //#endregion
10202
10552
  //#region src/cli/commands/run.ts
10203
10553
  function createRunAgentCommand(version) {
10204
- return createCommand("pantheon-agents run").version(version).description("Start a pantheon agents").argument("<name>", "The name of the agent.").option("--data-dir [dir]", "Data directory.", expandTilde("~/.pantheon-agents")).option("--mcp-port", "The port of the MCP server. Defaults to a random port.").option("--loop-interval <seconds>", "The interval of the loop in seconds. Defaults to 5.", (val) => parseInt(val, 10), 5).action(async function() {
10554
+ return createCommand("run").version(version).description("Start a pantheon agent").argument("<name>", "The name of the agent.").option("--data-dir [dir]", "Data directory.", expandTilde("~/.pantheon-agents")).option("--loop-interval <seconds>", "The interval of the loop in seconds. Defaults to 5.", (val) => parseInt(val, 10), 5).action(async function() {
10205
10555
  const [name] = this.args;
10206
10556
  const options = this.opts();
10557
+ if (!ensureEnv(["DATABASE_URL", "PANTHEON_API_KEY"])) return;
10207
10558
  const logFileTransport = transport({
10208
10559
  target: "pino-roll",
10209
10560
  options: {
@@ -21793,6 +22144,141 @@ function taskToDTO(agent, task) {
21793
22144
  error: task.status === "failed" ? task.error : null
21794
22145
  };
21795
22146
  }
22147
+ function agentConfigToDTO(config) {
22148
+ return {
22149
+ agent: config.agent,
22150
+ project_id: config.project_id,
22151
+ base_branch_id: config.base_branch_id,
22152
+ role: config.role,
22153
+ skills: config.skills,
22154
+ prototype_url: config.prototype_url,
22155
+ execute_agent: config.execute_agent
22156
+ };
22157
+ }
22158
+
22159
+ //#endregion
22160
+ //#region src/server/agent-config.ts
22161
+ function assertPantheonApiKeyConfigured() {
22162
+ if (!process.env.PANTHEON_API_KEY?.trim()) throw new ApiError({
22163
+ status: 503,
22164
+ code: "pantheon_api_key_missing",
22165
+ message: "Missing PANTHEON_API_KEY. This endpoint requires Pantheon API access."
22166
+ });
22167
+ }
22168
+ async function getBranchOutputOrThrow(options) {
22169
+ let state;
22170
+ try {
22171
+ state = await options.getPantheonBranchFn({
22172
+ projectId: options.projectId,
22173
+ branchId: options.branchId,
22174
+ getOutputIfFinished: true,
22175
+ manifestingAsSucceed: true
22176
+ });
22177
+ } catch (error) {
22178
+ throw new ApiError({
22179
+ status: 502,
22180
+ code: "pantheon_api_error",
22181
+ message: `Failed to fetch Pantheon branch output for ${options.branchId}.`,
22182
+ details: {
22183
+ project_id: options.projectId,
22184
+ branch_id: options.branchId,
22185
+ error: getErrorMessage(error)
22186
+ }
22187
+ });
22188
+ }
22189
+ if (state.state === "succeed") return state.output ?? "";
22190
+ if (state.state === "failed") throw new ApiError({
22191
+ status: 502,
22192
+ code: "pantheon_branch_failed",
22193
+ message: `Pantheon branch ${options.branchId} failed.`,
22194
+ details: {
22195
+ project_id: options.projectId,
22196
+ branch_id: options.branchId,
22197
+ error: state.error
22198
+ }
22199
+ });
22200
+ throw new ApiError({
22201
+ status: 502,
22202
+ code: "pantheon_branch_not_ready",
22203
+ message: `Pantheon branch ${options.branchId} is not finished yet.`,
22204
+ details: {
22205
+ project_id: options.projectId,
22206
+ branch_id: options.branchId
22207
+ }
22208
+ });
22209
+ }
22210
+ async function getAgentConfigWithBootstrapOutput(options) {
22211
+ assertPantheonApiKeyConfigured();
22212
+ const config = await options.provider.getAgentConfig(options.projectId);
22213
+ if (!config) throw new ApiError({
22214
+ status: 404,
22215
+ code: "config_not_found",
22216
+ message: `No config found for agent ${options.agent} and project ${options.projectId}.`
22217
+ });
22218
+ const bootstrapOutput = await getBranchOutputOrThrow({
22219
+ projectId: config.project_id,
22220
+ branchId: config.base_branch_id,
22221
+ getPantheonBranchFn: options.getPantheonBranchFn ?? getPantheonBranch
22222
+ });
22223
+ return {
22224
+ config: agentConfigToDTO(config),
22225
+ bootstrap_output: bootstrapOutput
22226
+ };
22227
+ }
22228
+ async function reconfigAgentConfigWithBootstrapOutput(options) {
22229
+ assertPantheonApiKeyConfigured();
22230
+ const getPantheonBranchFn = options.getPantheonBranchFn ?? getPantheonBranch;
22231
+ const wrappedGetPantheonBranch = (args) => getPantheonBranchFn({
22232
+ ...args,
22233
+ manifestingAsSucceed: true
22234
+ });
22235
+ let result;
22236
+ try {
22237
+ result = await reconfigAgentWithDeps(options.agent, options.reconfig, {
22238
+ provider: options.provider,
22239
+ executeOnPantheonFn: options.executeOnPantheonFn ?? executeOnPantheon,
22240
+ getPantheonBranchFn: wrappedGetPantheonBranch,
22241
+ sleep: options.sleep,
22242
+ pollIntervalMs: options.pollIntervalMs,
22243
+ maxRetries: options.maxRetries
22244
+ });
22245
+ } catch (error) {
22246
+ if (error instanceof ApiError) throw error;
22247
+ const message = getErrorMessage(error);
22248
+ if (message.startsWith("No config found for agent ")) throw new ApiError({
22249
+ status: 404,
22250
+ code: "config_not_found",
22251
+ message
22252
+ });
22253
+ if (message === "--role must be non-empty.") throw new ApiError({
22254
+ status: 400,
22255
+ code: "validation_error",
22256
+ message
22257
+ });
22258
+ if (message.startsWith("Bootstrap failed:")) throw new ApiError({
22259
+ status: 502,
22260
+ code: "bootstrap_failed",
22261
+ message
22262
+ });
22263
+ throw new ApiError({
22264
+ status: 502,
22265
+ code: "reconfig_failed",
22266
+ message,
22267
+ details: { error: message }
22268
+ });
22269
+ }
22270
+ const updated = await options.provider.getAgentConfig(result.previousConfig.project_id);
22271
+ if (!updated) throw new ApiError({
22272
+ status: 500,
22273
+ code: "config_update_lost",
22274
+ message: "Config disappeared after reconfig update."
22275
+ });
22276
+ return {
22277
+ previous_config: agentConfigToDTO(result.previousConfig),
22278
+ config: agentConfigToDTO(updated),
22279
+ bootstrap_output: result.bootstrapOutput
22280
+ };
22281
+ }
21796
22282
 
21797
22283
  //#endregion
21798
22284
  //#region src/server/api.ts
@@ -21831,6 +22317,10 @@ const createTaskBodySchema = z$1.object({
21831
22317
  project_id: z$1.string().min(1),
21832
22318
  task: z$1.string().min(1)
21833
22319
  });
22320
+ const reconfigBodySchema = z$1.object({
22321
+ role: z$1.string().trim().min(1).optional(),
22322
+ skills: z$1.array(z$1.string().trim().min(1)).optional()
22323
+ });
21834
22324
  function getAgentParam(value) {
21835
22325
  if (typeof value !== "string" || value.trim().length === 0) throw new ApiError({
21836
22326
  status: 400,
@@ -21839,6 +22329,14 @@ function getAgentParam(value) {
21839
22329
  });
21840
22330
  return value;
21841
22331
  }
22332
+ function getProjectIdParam(value) {
22333
+ if (typeof value !== "string" || value.trim().length === 0) throw new ApiError({
22334
+ status: 400,
22335
+ code: "validation_error",
22336
+ message: "Invalid project_id parameter."
22337
+ });
22338
+ return value;
22339
+ }
21842
22340
  function getTaskIdParam(value) {
21843
22341
  if (typeof value !== "string" || value.trim().length === 0) throw new ApiError({
21844
22342
  status: 400,
@@ -21854,6 +22352,31 @@ function createApiRouter(options) {
21854
22352
  const agents = await new TaskListTidbProvider("server", logger, { db }).listAgentNames();
21855
22353
  res.json({ agents });
21856
22354
  }));
22355
+ router.get("/agents/:agent/configs/:project_id", asyncHandler(async (req, res) => {
22356
+ const agent = getAgentParam(req.params.agent);
22357
+ const result = await getAgentConfigWithBootstrapOutput({
22358
+ agent,
22359
+ projectId: getProjectIdParam(req.params.project_id),
22360
+ provider: new TaskListTidbProvider(agent, logger, { db })
22361
+ });
22362
+ res.json(result);
22363
+ }));
22364
+ router.post("/agents/:agent/configs/:project_id/reconfig", asyncHandler(async (req, res) => {
22365
+ const agent = getAgentParam(req.params.agent);
22366
+ const projectId = getProjectIdParam(req.params.project_id);
22367
+ const body = reconfigBodySchema.parse(req.body);
22368
+ const provider = new TaskListTidbProvider(agent, logger, { db });
22369
+ const result = await reconfigAgentConfigWithBootstrapOutput({
22370
+ agent,
22371
+ reconfig: {
22372
+ projectId,
22373
+ role: body.role,
22374
+ skills: body.skills
22375
+ },
22376
+ provider
22377
+ });
22378
+ res.json(result);
22379
+ }));
21857
22380
  router.get("/agents/:agent/tasks", asyncHandler(async (req, res) => {
21858
22381
  const agent = getAgentParam(req.params.agent);
21859
22382
  const query = listTasksQuerySchema.parse(req.query);
@@ -31721,6 +32244,51 @@ function createAgentsMcpServer(options) {
31721
32244
  structuredContent: { deleted: true }
31722
32245
  };
31723
32246
  });
32247
+ server.registerTool("configs.get", {
32248
+ description: "Get an agent's config for a project, including the bootstrap branch output.",
32249
+ inputSchema: {
32250
+ agent: z$1.string().min(1),
32251
+ project_id: z$1.string().min(1)
32252
+ }
32253
+ }, async ({ agent, project_id }) => {
32254
+ return {
32255
+ content: [{
32256
+ type: "text",
32257
+ text: "OK"
32258
+ }],
32259
+ structuredContent: await getAgentConfigWithBootstrapOutput({
32260
+ agent,
32261
+ projectId: project_id,
32262
+ provider: new TaskListTidbProvider(agent, options.logger, { db: options.db })
32263
+ })
32264
+ };
32265
+ });
32266
+ server.registerTool("configs.reconfig", {
32267
+ description: "Re-bootstrap an existing agent configuration for a project (like `pantheon-agents reconfig`).",
32268
+ inputSchema: {
32269
+ agent: z$1.string().min(1),
32270
+ project_id: z$1.string().min(1),
32271
+ role: z$1.string().trim().min(1).optional(),
32272
+ skills: z$1.array(z$1.string().trim().min(1)).optional()
32273
+ }
32274
+ }, async ({ agent, project_id, role, skills }) => {
32275
+ const provider = new TaskListTidbProvider(agent, options.logger, { db: options.db });
32276
+ return {
32277
+ content: [{
32278
+ type: "text",
32279
+ text: "OK"
32280
+ }],
32281
+ structuredContent: await reconfigAgentConfigWithBootstrapOutput({
32282
+ agent,
32283
+ reconfig: {
32284
+ projectId: project_id,
32285
+ role,
32286
+ skills
32287
+ },
32288
+ provider
32289
+ })
32290
+ };
32291
+ });
31724
32292
  return server;
31725
32293
  }
31726
32294
 
@@ -31831,11 +32399,13 @@ async function startAgentsServer(options, logger, overrides = {}) {
31831
32399
  //#endregion
31832
32400
  //#region src/cli/commands/server.ts
31833
32401
  function createServerCommand(version) {
31834
- return createCommand("pantheon-agents server").version(version).description("Start the task HTTP API + MCP server").option("--host <host>", "Bind host. Defaults to 127.0.0.1.", "127.0.0.1").option("--port <port>", "Bind port. Defaults to 8000.", (v) => parseInt(v, 10), 8e3).option("--base-path <path>", "Mount base path prefix. Defaults to /.", "/").option("--token <token>", "Bearer token for API auth. Defaults to env PANTHEON_AGENTS_API_TOKEN.").option("--no-auth", "Disable auth (NOT recommended).").action(async function() {
32402
+ return createCommand("server").version(version).description("Start the task HTTP API + MCP server").option("--host <host>", "Bind host. Defaults to 127.0.0.1.", "127.0.0.1").option("--port <port>", "Bind port. Defaults to 8000.", (v) => parseInt(v, 10), 8e3).option("--base-path <path>", "Mount base path prefix. Defaults to /.", "/").option("--token <token>", "Bearer token for API auth. Defaults to env PANTHEON_AGENTS_API_TOKEN.").option("--no-auth", "Disable auth (NOT recommended).").action(async function() {
31835
32403
  const options = this.opts();
32404
+ if (!ensureEnv(["DATABASE_URL"])) return;
31836
32405
  if (!Number.isInteger(options.port) || options.port <= 0) {
31837
32406
  console.error("Invalid --port value. Must be a positive integer.");
31838
- process$1.exit(1);
32407
+ process$1.exitCode = 1;
32408
+ return;
31839
32409
  }
31840
32410
  const logger = pino({
31841
32411
  timestamp: pino.stdTimeFunctions.isoTime,
@@ -31858,14 +32428,16 @@ function createServerCommand(version) {
31858
32428
  //#endregion
31859
32429
  //#region src/cli/commands/show-config.ts
31860
32430
  function createShowConfigCommand(version) {
31861
- return createCommand("pantheon-agents show-config").version(version).description("Show agent config for a project").argument("<name>", "The name of the agent.").argument("[project-id]", "The project id.").option("--json", "Output config as JSON.").action(async function() {
32431
+ return createCommand("show-config").version(version).description("Show agent config for a project").argument("<name>", "The name of the agent.").argument("[project-id]", "The project id.").option("--json", "Output config as JSON.").action(async function() {
31862
32432
  const [name, projectId] = this.args;
31863
32433
  const options = this.opts();
32434
+ if (!ensureEnv(["DATABASE_URL"])) return;
31864
32435
  if (projectId) {
31865
32436
  const config = await showAgentConfig(name, projectId);
31866
32437
  if (!config) {
31867
32438
  console.error(`No config found for agent ${name} and project ${projectId}.`);
31868
- process$1.exit(1);
32439
+ process$1.exitCode = 1;
32440
+ return;
31869
32441
  }
31870
32442
  if (options.json) {
31871
32443
  console.log(JSON.stringify(config, null, 2));
@@ -31885,7 +32457,8 @@ function createShowConfigCommand(version) {
31885
32457
  const configs = await showAgentConfigs(name);
31886
32458
  if (!configs.length) {
31887
32459
  console.error(`No configs found for agent ${name}.`);
31888
- process$1.exit(1);
32460
+ process$1.exitCode = 1;
32461
+ return;
31889
32462
  }
31890
32463
  if (options.json) {
31891
32464
  console.log(JSON.stringify(configs, null, 2));
@@ -31922,46 +32495,50 @@ const orderDirections = ["asc", "desc"];
31922
32495
  //#endregion
31923
32496
  //#region src/cli/commands/show-tasks.ts
31924
32497
  function createShowTasksCommand(version) {
31925
- return createCommand("pantheon-agents show-tasks").version(version).description("Show tasks for an agent").argument("[name]", "The name of the agent.").option("--agents <names>", "Comma-separated agent names to query in one call.", parseCommaList, []).option("--all", "Show tasks for all agents.").option("--status <status>", "Filter tasks by status. Multiple values are separated by comma.", parseCommaList, []).option("--order-by <field>", "Order by queued_at, started_at, or ended_at.", "queued_at").option("--order-direction <direction>", "Order direction: asc or desc.", "desc").option("--limit <number>", "Limit the number of tasks shown.", (val) => parseInt(val, 10)).option("--max-task-length <number>", "Maximum task length for table output.", (val) => parseInt(val, 10), 120).option("--full-task", "Do not truncate task text in output.").option("--concise", "Output concise one-line entries.", true).option("--no-color", "Disable colored output.").option("--json", "Output tasks as JSON.").action(async function() {
32498
+ return createCommand("show-tasks").version(version).description("Show tasks for an agent").argument("[name]", "The name of the agent.").option("--agents <names>", "Comma-separated agent names to query in one call.", parseCommaList, []).option("--all", "Show tasks for all agents.").option("--status <status>", "Filter tasks by status. Multiple values are separated by comma.", parseCommaList, []).option("--order-by <field>", "Order by queued_at, started_at, or ended_at.", "queued_at").option("--order-direction <direction>", "Order direction: asc or desc.", "desc").option("--limit <number>", "Limit the number of tasks shown.", (val) => parseInt(val, 10)).option("--max-task-length <number>", "Maximum task length for table output.", (val) => parseInt(val, 10), 120).option("--full-task", "Do not truncate task text in output.").option("--no-concise", "Disable concise one-line entries.").option("--no-color", "Disable colored output.").option("--json", "Output tasks as JSON.").action(async function() {
31926
32499
  const [name] = this.args;
31927
32500
  const options = this.opts();
32501
+ if (!ensureEnv(["DATABASE_URL"])) return;
31928
32502
  const agentNames = /* @__PURE__ */ new Set();
31929
32503
  if (name) agentNames.add(name);
31930
32504
  options.agents.forEach((agent) => agentNames.add(agent));
31931
32505
  if (options.all && agentNames.size > 0) {
31932
32506
  console.error("Use either a specific agent name or --all, not both.");
31933
- process$1.exit(1);
32507
+ process$1.exitCode = 1;
32508
+ return;
31934
32509
  }
31935
32510
  if (!options.all && agentNames.size === 0) {
31936
32511
  console.error("Provide an agent name, --agents, or --all.");
31937
- process$1.exit(1);
32512
+ process$1.exitCode = 1;
32513
+ return;
31938
32514
  }
31939
32515
  const invalidStatuses = options.status.filter((status) => !taskStatuses.includes(status));
31940
32516
  if (invalidStatuses.length > 0) {
31941
32517
  console.error(`Invalid status values: ${invalidStatuses.join(", ")}. Allowed: ${taskStatuses.join(", ")}.`);
31942
- process$1.exit(1);
32518
+ process$1.exitCode = 1;
32519
+ return;
31943
32520
  }
31944
32521
  if (!orderByFields.includes(options.orderBy)) {
31945
32522
  console.error(`Invalid order-by value: ${options.orderBy}. Allowed: ${orderByFields.join(", ")}.`);
31946
- process$1.exit(1);
32523
+ process$1.exitCode = 1;
32524
+ return;
31947
32525
  }
31948
32526
  if (!orderDirections.includes(options.orderDirection)) {
31949
32527
  console.error(`Invalid order-direction value: ${options.orderDirection}. Allowed: ${orderDirections.join(", ")}.`);
31950
- process$1.exit(1);
32528
+ process$1.exitCode = 1;
32529
+ return;
31951
32530
  }
31952
32531
  if (options.limit != null && Number.isNaN(options.limit)) {
31953
32532
  console.error("Invalid limit value. Must be a number.");
31954
- process$1.exit(1);
32533
+ process$1.exitCode = 1;
32534
+ return;
31955
32535
  }
31956
32536
  if (Number.isNaN(options.maxTaskLength) || options.maxTaskLength <= 0) {
31957
32537
  console.error("Invalid max-task-length value. Must be a positive number.");
31958
- process$1.exit(1);
32538
+ process$1.exitCode = 1;
32539
+ return;
31959
32540
  }
31960
32541
  if (options.fullTask && options.maxTaskLength) options.maxTaskLength = Number.POSITIVE_INFINITY;
31961
- if (options.json && options.concise) {
31962
- console.error("Use either --json or --concise, not both.");
31963
- process$1.exit(1);
31964
- }
31965
32542
  const limitedTasks = await showTasksForAgents({
31966
32543
  agents: Array.from(agentNames),
31967
32544
  allAgents: options.all,
@@ -31998,36 +32575,1619 @@ function createShowTasksCommand(version) {
31998
32575
  }
31999
32576
 
32000
32577
  //#endregion
32001
- //#region src/cli/utils/env.ts
32002
- function warnIfMissingEnv(keys) {
32003
- for (const key of keys) if (!process.env[key]) console.error(`${key} environment variable is not set.`);
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
+
34175
+ //#endregion
34176
+ //#region src/cli/index.ts
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));
34178
+ async function main() {
34179
+ if (process$1.argv.length <= 2) {
34180
+ program.outputHelp();
34181
+ return;
34182
+ }
34183
+ await program.parseAsync(process$1.argv);
34184
+ }
34185
+ try {
34186
+ await main();
34187
+ } catch (error) {
34188
+ console.error(getErrorMessage(error));
34189
+ process$1.exitCode = 1;
32004
34190
  }
32005
-
32006
- //#endregion
32007
- //#region src/cli/index.ts
32008
- warnIfMissingEnv(["PANTHEON_API_KEY", "DATABASE_URL"]);
32009
- const commands = {
32010
- "add-task": createAddTaskCommand(version$1),
32011
- config: createConfigAgentCommand(version$1),
32012
- "delete-task": createDeleteTaskCommand(version$1),
32013
- reconfig: createReconfigAgentCommand(version$1),
32014
- run: createRunAgentCommand(version$1),
32015
- server: createServerCommand(version$1),
32016
- "show-config": createShowConfigCommand(version$1),
32017
- "show-tasks": createShowTasksCommand(version$1)
32018
- };
32019
- function printCommandHelpAndExit(command) {
32020
- console.error(`Invalid command: ${command}. Supported commands: ${Object.keys(commands).join(", ")}.`);
32021
- console.error(" Run pantheon-agents help <command> for more information.");
32022
- process$1.exit(1);
32023
- }
32024
- if (process$1.argv[2] === "help") {
32025
- const command = process$1.argv[3];
32026
- if (command in commands) commands[command].help({ error: false });
32027
- else printCommandHelpAndExit(command);
32028
- }
32029
- if (!commands[process$1.argv[2]]) printCommandHelpAndExit(process$1.argv[2]);
32030
- commands[process$1.argv[2]].parse(process$1.argv.slice(3), { from: "user" });
32031
34191
 
32032
34192
  //#endregion
32033
34193
  export { };