@pantheon.ai/agents 0.0.17 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/index.js +1134 -647
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -17034,8 +17034,9 @@ async function getPantheonBranchInfo({ projectId, branchId }) {
|
|
|
17034
17034
|
}, null);
|
|
17035
17035
|
}
|
|
17036
17036
|
async function executeOnPantheon({ projectId, branchId, prompt, agent }) {
|
|
17037
|
+
const promptSequence = Array.isArray(prompt) ? prompt : [prompt];
|
|
17037
17038
|
return (await executor.execute(createProjectExploration, { projectId }, {
|
|
17038
|
-
shared_prompt_sequence:
|
|
17039
|
+
shared_prompt_sequence: promptSequence,
|
|
17039
17040
|
num_branches: 1,
|
|
17040
17041
|
agent,
|
|
17041
17042
|
parent_branch_id: branchId
|
|
@@ -17059,8 +17060,47 @@ function getTaskWorkingBranchId(task) {
|
|
|
17059
17060
|
return ("branch_id" in task ? task.branch_id : void 0) ?? task.base_branch_id;
|
|
17060
17061
|
}
|
|
17061
17062
|
|
|
17063
|
+
//#endregion
|
|
17064
|
+
//#region src/core/agent-config-utils.ts
|
|
17065
|
+
function normalizeRepoUrl(value) {
|
|
17066
|
+
return value.trim().replace(/\/+$/, "").replace(/\.git$/, "");
|
|
17067
|
+
}
|
|
17068
|
+
function toRawGitHubContentUrl(url) {
|
|
17069
|
+
if (!url.startsWith("https://github.com/")) return url;
|
|
17070
|
+
return url.replace("https://github.com/", "https://raw.githubusercontent.com/").replace("/blob/", "/");
|
|
17071
|
+
}
|
|
17072
|
+
function normalizeSkills(value) {
|
|
17073
|
+
if (Array.isArray(value)) return value.filter((item) => typeof item === "string");
|
|
17074
|
+
if (typeof value === "string") {
|
|
17075
|
+
try {
|
|
17076
|
+
const parsed = JSON.parse(value);
|
|
17077
|
+
if (Array.isArray(parsed)) return parsed.filter((item) => typeof item === "string");
|
|
17078
|
+
} catch {}
|
|
17079
|
+
return value.split(",").map((item) => item.trim()).filter((item) => item !== "");
|
|
17080
|
+
}
|
|
17081
|
+
return [];
|
|
17082
|
+
}
|
|
17083
|
+
function normalizeSetupScriptSlug(setupScript, fallback) {
|
|
17084
|
+
if (typeof setupScript === "string" && setupScript.trim() !== "") return setupScript.trim();
|
|
17085
|
+
return fallback.trim();
|
|
17086
|
+
}
|
|
17087
|
+
function buildSetupScriptStep(options) {
|
|
17088
|
+
const prototypeRepoUrl = normalizeRepoUrl(options.prototypeRepoUrl);
|
|
17089
|
+
const setupScriptUrl = toRawGitHubContentUrl(`${prototypeRepoUrl}/blob/main/scripts/${`setup-${options.setupScriptSlug}.sh`}`);
|
|
17090
|
+
const skillsArg = JSON.stringify(options.skills.join(","));
|
|
17091
|
+
return `execute shell ${setupScriptUrl} ${options.role.trim()} ${skillsArg} ${prototypeRepoUrl}`;
|
|
17092
|
+
}
|
|
17093
|
+
|
|
17062
17094
|
//#endregion
|
|
17063
17095
|
//#region src/core/task-list.ts
|
|
17096
|
+
function buildTaskPromptSequence(config, taskPrompt) {
|
|
17097
|
+
return [buildSetupScriptStep({
|
|
17098
|
+
prototypeRepoUrl: config.prototype_url,
|
|
17099
|
+
setupScriptSlug: normalizeSetupScriptSlug(config.setup_script, config.execute_agent),
|
|
17100
|
+
role: config.role,
|
|
17101
|
+
skills: normalizeSkills(config.skills)
|
|
17102
|
+
}), taskPrompt];
|
|
17103
|
+
}
|
|
17064
17104
|
async function startTaskListLoop(agentName, { loopInterval = 5 }, logger) {
|
|
17065
17105
|
logger.info("Starting task list loop...");
|
|
17066
17106
|
let i = 0;
|
|
@@ -17134,11 +17174,12 @@ async function startPendingTask(provider, task, logger) {
|
|
|
17134
17174
|
logger.warn("Agent configuration not found for project %s. Skip starting tasks.", taskToStart.project_id);
|
|
17135
17175
|
return false;
|
|
17136
17176
|
}
|
|
17177
|
+
const promptSequence = buildTaskPromptSequence(config, taskToStart.task);
|
|
17137
17178
|
const taskBranch = await provider.startTask(taskToStart, async () => {
|
|
17138
17179
|
return await executeOnPantheon({
|
|
17139
17180
|
projectId: taskToStart.project_id,
|
|
17140
17181
|
branchId: taskToStart.base_branch_id,
|
|
17141
|
-
prompt:
|
|
17182
|
+
prompt: promptSequence,
|
|
17142
17183
|
agent: config.execute_agent
|
|
17143
17184
|
});
|
|
17144
17185
|
});
|
|
@@ -17538,17 +17579,6 @@ var WatchStepAggregator = class {
|
|
|
17538
17579
|
|
|
17539
17580
|
//#endregion
|
|
17540
17581
|
//#region src/core/index.ts
|
|
17541
|
-
function normalizeSkills(value) {
|
|
17542
|
-
if (Array.isArray(value)) return value.filter((item) => typeof item === "string");
|
|
17543
|
-
if (typeof value === "string") {
|
|
17544
|
-
try {
|
|
17545
|
-
const parsed = JSON.parse(value);
|
|
17546
|
-
if (Array.isArray(parsed)) return parsed.filter((item) => typeof item === "string");
|
|
17547
|
-
} catch {}
|
|
17548
|
-
return value.split(",").map((item) => item.trim()).filter((item) => item !== "");
|
|
17549
|
-
}
|
|
17550
|
-
return [];
|
|
17551
|
-
}
|
|
17552
17582
|
function buildRebootstrapDiffPrompt(options) {
|
|
17553
17583
|
return `You must follow these instructions":
|
|
17554
17584
|
1. Clone the main branch from ${options.prototypeUrl} to a temporary directory (<pantheon-agents> in follow instructions references to this directory).
|
|
@@ -17635,75 +17665,21 @@ async function configAgent(name, options) {
|
|
|
17635
17665
|
}
|
|
17636
17666
|
options.rootBranchId = project.root_branch_id;
|
|
17637
17667
|
}
|
|
17638
|
-
|
|
17639
|
-
|
|
17640
|
-
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
3. Copy the <pantheon-agents>/agents/${options.role}/skills directory to \`<workspace>/.codex/skills\` if the source directory exists.
|
|
17647
|
-
${options.skills.length > 0 ? `4. Copy the pantheon-agents/skills/\{${options.skills.join(",")}} directory to \`<workspace>/.codex/skills/\`` : ""}
|
|
17648
|
-
|
|
17649
|
-
Validate <workspace>: check if files and directorys exists:
|
|
17650
|
-
- AGENTS.md
|
|
17651
|
-
- .codex/skills
|
|
17652
|
-
|
|
17653
|
-
**You MUST NOT generate AGENTS.md and skills by yourself if clone failed.**
|
|
17654
|
-
|
|
17655
|
-
Finally, outputs the first 5 lines of <workspace>/AGENTS.md and the skills list in <workspace>/.codex/skills
|
|
17656
|
-
`
|
|
17657
|
-
});
|
|
17658
|
-
let retried = 0;
|
|
17659
|
-
const maxRetries = 3;
|
|
17660
|
-
let i = 0;
|
|
17661
|
-
console.log(`Bootstrap branch created: ${branchId} ${branchLatestSnapId}. Waiting for ready... [poll interval = 10s]`);
|
|
17662
|
-
while (true) {
|
|
17663
|
-
await new Promise((resolve) => {
|
|
17664
|
-
setTimeout(resolve, 1e4);
|
|
17665
|
-
});
|
|
17666
|
-
const result = await getPantheonBranch({
|
|
17667
|
-
branchId,
|
|
17668
|
-
projectId: options.projectId,
|
|
17669
|
-
getOutputIfFinished: true
|
|
17670
|
-
}).then((result) => {
|
|
17671
|
-
retried = 0;
|
|
17672
|
-
return result;
|
|
17673
|
-
}).catch((reason) => {
|
|
17674
|
-
if (retried < maxRetries) {
|
|
17675
|
-
retried++;
|
|
17676
|
-
return { state: "others" };
|
|
17677
|
-
}
|
|
17678
|
-
throw new Error(`Failed to get bootstrap branch status. Retry ${retried} times. Last error: ${getErrorMessage$2(reason)}`);
|
|
17679
|
-
});
|
|
17680
|
-
if (result.state === "failed") {
|
|
17681
|
-
console.error("Bootstrap failed: " + result.error);
|
|
17682
|
-
process.exitCode = 1;
|
|
17683
|
-
return;
|
|
17684
|
-
}
|
|
17685
|
-
if (result.state === "succeed") {
|
|
17686
|
-
console.log("Bootstrap succeeded. Output is:");
|
|
17687
|
-
console.log(result.output);
|
|
17688
|
-
break;
|
|
17689
|
-
}
|
|
17690
|
-
console.log(`Bootstrap in progress... [${++i}]`);
|
|
17691
|
-
}
|
|
17692
|
-
await provider.setAgentConfig({
|
|
17693
|
-
project_id: options.projectId,
|
|
17694
|
-
base_branch_id: branchId,
|
|
17695
|
-
execute_agent: options.executeAgent,
|
|
17696
|
-
role: options.role,
|
|
17697
|
-
skills: options.skills,
|
|
17698
|
-
prototype_url: options.prototypeUrl
|
|
17699
|
-
});
|
|
17700
|
-
} else await provider.setAgentConfig({
|
|
17668
|
+
const rootBranchId = options.rootBranchId;
|
|
17669
|
+
if (!rootBranchId) {
|
|
17670
|
+
console.error("Unable to resolve root branch id.");
|
|
17671
|
+
process.exitCode = 1;
|
|
17672
|
+
return;
|
|
17673
|
+
}
|
|
17674
|
+
const setupScript = normalizeSetupScriptSlug(options.setupScript, options.executeAgent);
|
|
17675
|
+
await provider.setAgentConfig({
|
|
17701
17676
|
project_id: options.projectId,
|
|
17702
|
-
base_branch_id:
|
|
17677
|
+
base_branch_id: rootBranchId,
|
|
17703
17678
|
execute_agent: options.executeAgent,
|
|
17704
17679
|
role: options.role,
|
|
17705
17680
|
skills: options.skills,
|
|
17706
|
-
prototype_url: options.prototypeUrl
|
|
17681
|
+
prototype_url: options.prototypeUrl,
|
|
17682
|
+
setup_script: setupScript
|
|
17707
17683
|
});
|
|
17708
17684
|
console.log(`Agent ${name} configured successfully.`);
|
|
17709
17685
|
} finally {
|
|
@@ -17716,6 +17692,9 @@ async function reconfigAgentWithDeps(name, options, deps) {
|
|
|
17716
17692
|
const resolvedRole = options.role?.trim() || previousConfig.role;
|
|
17717
17693
|
if (options.role != null && !options.role.trim()) throw new Error("--role must be non-empty.");
|
|
17718
17694
|
const resolvedSkills = options.skills ?? normalizeSkills(previousConfig.skills);
|
|
17695
|
+
const previousSetupScript = normalizeSetupScriptSlug(previousConfig.setup_script, previousConfig.execute_agent);
|
|
17696
|
+
const resolvedSetupScript = options.setupScript?.trim() || previousSetupScript;
|
|
17697
|
+
if (options.setupScript != null && !options.setupScript.trim()) throw new Error("--setup-script must be non-empty.");
|
|
17719
17698
|
const { branch_id: nextBaseBranchId } = await deps.executeOnPantheonFn({
|
|
17720
17699
|
projectId: options.projectId,
|
|
17721
17700
|
branchId: previousConfig.base_branch_id,
|
|
@@ -17742,7 +17721,8 @@ async function reconfigAgentWithDeps(name, options, deps) {
|
|
|
17742
17721
|
execute_agent: previousConfig.execute_agent,
|
|
17743
17722
|
role: resolvedRole,
|
|
17744
17723
|
skills: resolvedSkills,
|
|
17745
|
-
prototype_url: previousConfig.prototype_url
|
|
17724
|
+
prototype_url: previousConfig.prototype_url,
|
|
17725
|
+
setup_script: resolvedSetupScript
|
|
17746
17726
|
});
|
|
17747
17727
|
return {
|
|
17748
17728
|
previousConfig,
|
|
@@ -17963,15 +17943,32 @@ function ensureEnv(keys) {
|
|
|
17963
17943
|
process.exitCode = 1;
|
|
17964
17944
|
return false;
|
|
17965
17945
|
}
|
|
17946
|
+
function normalizeOptional(value) {
|
|
17947
|
+
if (value == null) return void 0;
|
|
17948
|
+
const trimmed = value.trim();
|
|
17949
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
17950
|
+
}
|
|
17951
|
+
function resolvePantheonProjectId(projectIdArg) {
|
|
17952
|
+
return normalizeOptional(projectIdArg) ?? normalizeOptional(process.env.DEFAULT_PANTHEON_PROJECT_ID);
|
|
17953
|
+
}
|
|
17954
|
+
function resolvePantheonRootBranchId(rootBranchIdArg) {
|
|
17955
|
+
return normalizeOptional(rootBranchIdArg) ?? normalizeOptional(process.env.DEFAULT_PANTHEON_ROOT_BRANCH_ID);
|
|
17956
|
+
}
|
|
17966
17957
|
|
|
17967
17958
|
//#endregion
|
|
17968
17959
|
//#region src/cli/commands/add-task.ts
|
|
17969
|
-
function createAddTaskCommand(version) {
|
|
17970
|
-
return createCommand("add-task").version(version).description("Add a task to an agent").argument("<name>", "The name of the agent.").argument("<
|
|
17971
|
-
const [name,
|
|
17960
|
+
function createAddTaskCommand(version, deps = {}) {
|
|
17961
|
+
return createCommand("add-task").version(version).description("Add a task to an agent").argument("<name>", "The name of the agent.").argument("<task-prompt>", "The prompt of the task.").option("--project-id <project-id>", "The project id of the agent. Defaults to DEFAULT_PANTHEON_PROJECT_ID.").option("--parent-task-id <task-id>", "Parent task id for dependent tasks.").action(async function() {
|
|
17962
|
+
const [name, taskPrompt] = this.args;
|
|
17972
17963
|
const options = this.opts();
|
|
17964
|
+
const projectId = resolvePantheonProjectId(options.projectId);
|
|
17965
|
+
if (!projectId) {
|
|
17966
|
+
console.error("project-id is required (--project-id or DEFAULT_PANTHEON_PROJECT_ID).");
|
|
17967
|
+
process$1.exitCode = 1;
|
|
17968
|
+
return;
|
|
17969
|
+
}
|
|
17973
17970
|
if (!ensureEnv(["DATABASE_URL"])) return;
|
|
17974
|
-
await addTask(name, {
|
|
17971
|
+
await (deps.addTask ?? addTask)(name, {
|
|
17975
17972
|
projectId,
|
|
17976
17973
|
prompt: taskPrompt,
|
|
17977
17974
|
parentTaskId: options.parentTaskId
|
|
@@ -18024,19 +18021,103 @@ function createCancelTaskCommand(version) {
|
|
|
18024
18021
|
});
|
|
18025
18022
|
}
|
|
18026
18023
|
|
|
18024
|
+
//#endregion
|
|
18025
|
+
//#region src/cli/utils/parse.ts
|
|
18026
|
+
function parseCommaList(value) {
|
|
18027
|
+
return value.split(",").map((item) => item.trim()).filter((item) => item !== "");
|
|
18028
|
+
}
|
|
18029
|
+
function parseUniqueCommaList(value) {
|
|
18030
|
+
const items = parseCommaList(value);
|
|
18031
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18032
|
+
const result = [];
|
|
18033
|
+
for (const item of items) {
|
|
18034
|
+
if (seen.has(item)) continue;
|
|
18035
|
+
seen.add(item);
|
|
18036
|
+
result.push(item);
|
|
18037
|
+
}
|
|
18038
|
+
return result;
|
|
18039
|
+
}
|
|
18040
|
+
function isLeapYear(year) {
|
|
18041
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
18042
|
+
}
|
|
18043
|
+
function daysInMonth(year, month) {
|
|
18044
|
+
switch (month) {
|
|
18045
|
+
case 2: return isLeapYear(year) ? 29 : 28;
|
|
18046
|
+
case 4:
|
|
18047
|
+
case 6:
|
|
18048
|
+
case 9:
|
|
18049
|
+
case 11: return 30;
|
|
18050
|
+
default: return 31;
|
|
18051
|
+
}
|
|
18052
|
+
}
|
|
18053
|
+
function parseIsoTimestamp(value) {
|
|
18054
|
+
const invalid = (detail) => ({
|
|
18055
|
+
ok: false,
|
|
18056
|
+
error: `Invalid timestamp: ${JSON.stringify(value)}. ` + (detail ? `${detail} ` : "") + "Expected ISO-8601 date-time with timezone, e.g. 2026-02-12T00:00:00Z."
|
|
18057
|
+
});
|
|
18058
|
+
const input = value.trim();
|
|
18059
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?(Z|([+-])(\d{2}):(\d{2}))$/.exec(input);
|
|
18060
|
+
if (!match) return invalid();
|
|
18061
|
+
const year = Number(match[1]);
|
|
18062
|
+
const month = Number(match[2]);
|
|
18063
|
+
const day = Number(match[3]);
|
|
18064
|
+
const hour = Number(match[4]);
|
|
18065
|
+
const minute = Number(match[5]);
|
|
18066
|
+
const second = Number(match[6]);
|
|
18067
|
+
const fraction = match[7];
|
|
18068
|
+
if (month < 1 || month > 12) return invalid();
|
|
18069
|
+
const dim = daysInMonth(year, month);
|
|
18070
|
+
if (day < 1 || day > dim) return invalid("Day is out of range for month.");
|
|
18071
|
+
if (hour < 0 || hour > 23) return invalid("Hour must be between 00 and 23.");
|
|
18072
|
+
if (minute < 0 || minute > 59) return invalid("Minute must be between 00 and 59.");
|
|
18073
|
+
if (second < 0 || second > 59) return invalid("Second must be between 00 and 59.");
|
|
18074
|
+
const millis = fraction ? Number(fraction.padEnd(3, "0")) : 0;
|
|
18075
|
+
if (!Number.isInteger(millis) || millis < 0 || millis > 999) return invalid("Fractional seconds must have 1-3 digits.");
|
|
18076
|
+
const timezone = match[8];
|
|
18077
|
+
let offsetMinutes = 0;
|
|
18078
|
+
if (timezone !== "Z") {
|
|
18079
|
+
const sign = match[9];
|
|
18080
|
+
const offsetHours = Number(match[10]);
|
|
18081
|
+
const offsetMins = Number(match[11]);
|
|
18082
|
+
if (sign !== "+" && sign !== "-" || offsetHours < 0 || offsetHours > 23 || offsetMins < 0 || offsetMins > 59) return invalid("Timezone offset must be between -23:59 and +23:59.");
|
|
18083
|
+
offsetMinutes = (sign === "+" ? 1 : -1) * (offsetHours * 60 + offsetMins);
|
|
18084
|
+
}
|
|
18085
|
+
const utcMillis = Date.UTC(year, month - 1, day, hour, minute, second, millis) - offsetMinutes * 6e4;
|
|
18086
|
+
const date = new Date(utcMillis);
|
|
18087
|
+
if (Number.isNaN(date.getTime())) return invalid();
|
|
18088
|
+
return {
|
|
18089
|
+
ok: true,
|
|
18090
|
+
value: date
|
|
18091
|
+
};
|
|
18092
|
+
}
|
|
18093
|
+
|
|
18027
18094
|
//#endregion
|
|
18028
18095
|
//#region src/cli/commands/config.ts
|
|
18096
|
+
function parseSetupScriptSlug(value) {
|
|
18097
|
+
const slug = value.trim();
|
|
18098
|
+
if (!slug) throw new InvalidArgumentError("setup-script slug must be non-empty.");
|
|
18099
|
+
return slug;
|
|
18100
|
+
}
|
|
18029
18101
|
function createConfigAgentCommand(version) {
|
|
18030
|
-
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.").
|
|
18031
|
-
const [name, role
|
|
18102
|
+
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.").option("--project-id <project-id>", "The project id of the agent. Defaults to DEFAULT_PANTHEON_PROJECT_ID.").option("--skills <skills>", "The skills of the agent. Multiple values are separated by comma.", parseUniqueCommaList, []).option("--execute-agent <agent>", "The execute agent of the agent.", "codex").option("--root-branch-id <branchId>", "The root branch id of the agent. Defaults to DEFAULT_PANTHEON_ROOT_BRANCH_ID, then project root branch id.").option("--prototype-url <url>", "Role and skill definitions repo.", "https://github.com/pingcap-inc/pantheon-agents").option("--setup-script <slug>", "Setup script slug. CLI resolves it to setup-<slug>.sh.", parseSetupScriptSlug).action(async function() {
|
|
18103
|
+
const [name, role] = this.args;
|
|
18032
18104
|
const options = this.opts();
|
|
18105
|
+
const resolvedProjectId = resolvePantheonProjectId(options.projectId);
|
|
18106
|
+
if (!resolvedProjectId) {
|
|
18107
|
+
console.error("project-id is required (--project-id or DEFAULT_PANTHEON_PROJECT_ID).");
|
|
18108
|
+
process$1.exitCode = 1;
|
|
18109
|
+
return;
|
|
18110
|
+
}
|
|
18111
|
+
const resolvedRootBranchId = resolvePantheonRootBranchId(options.rootBranchId);
|
|
18033
18112
|
const requiredEnvVars = ["DATABASE_URL"];
|
|
18034
|
-
if (
|
|
18113
|
+
if (!resolvedRootBranchId) requiredEnvVars.push("PANTHEON_API_KEY");
|
|
18035
18114
|
if (!ensureEnv(requiredEnvVars)) return;
|
|
18036
18115
|
await configAgent(name, {
|
|
18037
18116
|
role,
|
|
18038
|
-
projectId,
|
|
18039
|
-
...options
|
|
18117
|
+
projectId: resolvedProjectId,
|
|
18118
|
+
...options,
|
|
18119
|
+
rootBranchId: resolvedRootBranchId,
|
|
18120
|
+
setupScript: options.setupScript ?? options.executeAgent
|
|
18040
18121
|
});
|
|
18041
18122
|
});
|
|
18042
18123
|
}
|
|
@@ -18156,82 +18237,18 @@ function createLlmExplainCommand(version) {
|
|
|
18156
18237
|
});
|
|
18157
18238
|
}
|
|
18158
18239
|
|
|
18159
|
-
//#endregion
|
|
18160
|
-
//#region src/cli/utils/parse.ts
|
|
18161
|
-
function parseCommaList(value) {
|
|
18162
|
-
return value.split(",").map((item) => item.trim()).filter((item) => item !== "");
|
|
18163
|
-
}
|
|
18164
|
-
function parseUniqueCommaList(value) {
|
|
18165
|
-
const items = parseCommaList(value);
|
|
18166
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18167
|
-
const result = [];
|
|
18168
|
-
for (const item of items) {
|
|
18169
|
-
if (seen.has(item)) continue;
|
|
18170
|
-
seen.add(item);
|
|
18171
|
-
result.push(item);
|
|
18172
|
-
}
|
|
18173
|
-
return result;
|
|
18174
|
-
}
|
|
18175
|
-
function isLeapYear(year) {
|
|
18176
|
-
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
18177
|
-
}
|
|
18178
|
-
function daysInMonth(year, month) {
|
|
18179
|
-
switch (month) {
|
|
18180
|
-
case 2: return isLeapYear(year) ? 29 : 28;
|
|
18181
|
-
case 4:
|
|
18182
|
-
case 6:
|
|
18183
|
-
case 9:
|
|
18184
|
-
case 11: return 30;
|
|
18185
|
-
default: return 31;
|
|
18186
|
-
}
|
|
18187
|
-
}
|
|
18188
|
-
function parseIsoTimestamp(value) {
|
|
18189
|
-
const invalid = (detail) => ({
|
|
18190
|
-
ok: false,
|
|
18191
|
-
error: `Invalid timestamp: ${JSON.stringify(value)}. ` + (detail ? `${detail} ` : "") + "Expected ISO-8601 date-time with timezone, e.g. 2026-02-12T00:00:00Z."
|
|
18192
|
-
});
|
|
18193
|
-
const input = value.trim();
|
|
18194
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?(Z|([+-])(\d{2}):(\d{2}))$/.exec(input);
|
|
18195
|
-
if (!match) return invalid();
|
|
18196
|
-
const year = Number(match[1]);
|
|
18197
|
-
const month = Number(match[2]);
|
|
18198
|
-
const day = Number(match[3]);
|
|
18199
|
-
const hour = Number(match[4]);
|
|
18200
|
-
const minute = Number(match[5]);
|
|
18201
|
-
const second = Number(match[6]);
|
|
18202
|
-
const fraction = match[7];
|
|
18203
|
-
if (month < 1 || month > 12) return invalid();
|
|
18204
|
-
const dim = daysInMonth(year, month);
|
|
18205
|
-
if (day < 1 || day > dim) return invalid("Day is out of range for month.");
|
|
18206
|
-
if (hour < 0 || hour > 23) return invalid("Hour must be between 00 and 23.");
|
|
18207
|
-
if (minute < 0 || minute > 59) return invalid("Minute must be between 00 and 59.");
|
|
18208
|
-
if (second < 0 || second > 59) return invalid("Second must be between 00 and 59.");
|
|
18209
|
-
const millis = fraction ? Number(fraction.padEnd(3, "0")) : 0;
|
|
18210
|
-
if (!Number.isInteger(millis) || millis < 0 || millis > 999) return invalid("Fractional seconds must have 1-3 digits.");
|
|
18211
|
-
const timezone = match[8];
|
|
18212
|
-
let offsetMinutes = 0;
|
|
18213
|
-
if (timezone !== "Z") {
|
|
18214
|
-
const sign = match[9];
|
|
18215
|
-
const offsetHours = Number(match[10]);
|
|
18216
|
-
const offsetMins = Number(match[11]);
|
|
18217
|
-
if (sign !== "+" && sign !== "-" || offsetHours < 0 || offsetHours > 23 || offsetMins < 0 || offsetMins > 59) return invalid("Timezone offset must be between -23:59 and +23:59.");
|
|
18218
|
-
offsetMinutes = (sign === "+" ? 1 : -1) * (offsetHours * 60 + offsetMins);
|
|
18219
|
-
}
|
|
18220
|
-
const utcMillis = Date.UTC(year, month - 1, day, hour, minute, second, millis) - offsetMinutes * 6e4;
|
|
18221
|
-
const date = new Date(utcMillis);
|
|
18222
|
-
if (Number.isNaN(date.getTime())) return invalid();
|
|
18223
|
-
return {
|
|
18224
|
-
ok: true,
|
|
18225
|
-
value: date
|
|
18226
|
-
};
|
|
18227
|
-
}
|
|
18228
|
-
|
|
18229
18240
|
//#endregion
|
|
18230
18241
|
//#region src/cli/commands/reconfig.ts
|
|
18231
18242
|
function createReconfigAgentCommand(version) {
|
|
18232
|
-
return createCommand("reconfig").version(version).description("Re-bootstrap an existing agent configuration for a project").argument("<name>", "The name of the agent.").
|
|
18233
|
-
const [name
|
|
18243
|
+
return createCommand("reconfig").version(version).description("Re-bootstrap an existing agent configuration for a project").argument("<name>", "The name of the agent.").option("--project-id <project-id>", "The project id of the agent. Defaults to DEFAULT_PANTHEON_PROJECT_ID.").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() {
|
|
18244
|
+
const [name] = this.args;
|
|
18234
18245
|
const options = this.opts();
|
|
18246
|
+
const projectId = resolvePantheonProjectId(options.projectId);
|
|
18247
|
+
if (!projectId) {
|
|
18248
|
+
console.error("project-id is required (--project-id or DEFAULT_PANTHEON_PROJECT_ID).");
|
|
18249
|
+
process$1.exitCode = 1;
|
|
18250
|
+
return;
|
|
18251
|
+
}
|
|
18235
18252
|
if (!ensureEnv(["DATABASE_URL", "PANTHEON_API_KEY"])) return;
|
|
18236
18253
|
const resolvedRole = options.role?.trim();
|
|
18237
18254
|
if (options.role != null && !resolvedRole) {
|
|
@@ -20843,6 +20860,7 @@ function agentConfigToDTO(config) {
|
|
|
20843
20860
|
role: config.role,
|
|
20844
20861
|
skills: config.skills,
|
|
20845
20862
|
prototype_url: config.prototype_url,
|
|
20863
|
+
setup_script: config.setup_script,
|
|
20846
20864
|
execute_agent: config.execute_agent
|
|
20847
20865
|
};
|
|
20848
20866
|
}
|
|
@@ -20856,67 +20874,16 @@ function assertPantheonApiKeyConfigured() {
|
|
|
20856
20874
|
message: "Missing PANTHEON_API_KEY. This endpoint requires Pantheon API access."
|
|
20857
20875
|
});
|
|
20858
20876
|
}
|
|
20859
|
-
async function
|
|
20860
|
-
let state;
|
|
20861
|
-
try {
|
|
20862
|
-
state = await options.getPantheonBranchFn({
|
|
20863
|
-
projectId: options.projectId,
|
|
20864
|
-
branchId: options.branchId,
|
|
20865
|
-
getOutputIfFinished: true,
|
|
20866
|
-
manifestingAsSucceed: true
|
|
20867
|
-
});
|
|
20868
|
-
} catch (error) {
|
|
20869
|
-
throw new ApiError({
|
|
20870
|
-
status: 502,
|
|
20871
|
-
code: "pantheon_api_error",
|
|
20872
|
-
message: `Failed to fetch Pantheon branch output for ${options.branchId}.`,
|
|
20873
|
-
details: {
|
|
20874
|
-
project_id: options.projectId,
|
|
20875
|
-
branch_id: options.branchId,
|
|
20876
|
-
error: getErrorMessage$2(error)
|
|
20877
|
-
}
|
|
20878
|
-
});
|
|
20879
|
-
}
|
|
20880
|
-
if (state.state === "succeed") return state.output ?? "";
|
|
20881
|
-
if (state.state === "failed") throw new ApiError({
|
|
20882
|
-
status: 502,
|
|
20883
|
-
code: "pantheon_branch_failed",
|
|
20884
|
-
message: `Pantheon branch ${options.branchId} failed.`,
|
|
20885
|
-
details: {
|
|
20886
|
-
project_id: options.projectId,
|
|
20887
|
-
branch_id: options.branchId,
|
|
20888
|
-
error: state.error
|
|
20889
|
-
}
|
|
20890
|
-
});
|
|
20891
|
-
throw new ApiError({
|
|
20892
|
-
status: 502,
|
|
20893
|
-
code: "pantheon_branch_not_ready",
|
|
20894
|
-
message: `Pantheon branch ${options.branchId} is not finished yet.`,
|
|
20895
|
-
details: {
|
|
20896
|
-
project_id: options.projectId,
|
|
20897
|
-
branch_id: options.branchId
|
|
20898
|
-
}
|
|
20899
|
-
});
|
|
20900
|
-
}
|
|
20901
|
-
async function getAgentConfigWithBootstrapOutput(options) {
|
|
20902
|
-
assertPantheonApiKeyConfigured();
|
|
20877
|
+
async function getAgentConfig(options) {
|
|
20903
20878
|
const config = await options.provider.getAgentConfig(options.projectId);
|
|
20904
20879
|
if (!config) throw new ApiError({
|
|
20905
20880
|
status: 404,
|
|
20906
20881
|
code: "config_not_found",
|
|
20907
20882
|
message: `No config found for agent ${options.agent} and project ${options.projectId}.`
|
|
20908
20883
|
});
|
|
20909
|
-
|
|
20910
|
-
projectId: config.project_id,
|
|
20911
|
-
branchId: config.base_branch_id,
|
|
20912
|
-
getPantheonBranchFn: options.getPantheonBranchFn ?? getPantheonBranch
|
|
20913
|
-
});
|
|
20914
|
-
return {
|
|
20915
|
-
config: agentConfigToDTO(config),
|
|
20916
|
-
bootstrap_output: bootstrapOutput
|
|
20917
|
-
};
|
|
20884
|
+
return { config: agentConfigToDTO(config) };
|
|
20918
20885
|
}
|
|
20919
|
-
async function
|
|
20886
|
+
async function reconfigAgentConfig(options) {
|
|
20920
20887
|
assertPantheonApiKeyConfigured();
|
|
20921
20888
|
const getPantheonBranchFn = options.getPantheonBranchFn ?? getPantheonBranch;
|
|
20922
20889
|
const wrappedGetPantheonBranch = (args) => getPantheonBranchFn({
|
|
@@ -20941,7 +20908,7 @@ async function reconfigAgentConfigWithBootstrapOutput(options) {
|
|
|
20941
20908
|
code: "config_not_found",
|
|
20942
20909
|
message
|
|
20943
20910
|
});
|
|
20944
|
-
if (message === "--role must be non-empty.") throw new ApiError({
|
|
20911
|
+
if (message === "--role must be non-empty." || message === "--setup-script must be non-empty.") throw new ApiError({
|
|
20945
20912
|
status: 400,
|
|
20946
20913
|
code: "validation_error",
|
|
20947
20914
|
message
|
|
@@ -20966,8 +20933,7 @@ async function reconfigAgentConfigWithBootstrapOutput(options) {
|
|
|
20966
20933
|
});
|
|
20967
20934
|
return {
|
|
20968
20935
|
previous_config: agentConfigToDTO(result.previousConfig),
|
|
20969
|
-
config: agentConfigToDTO(updated)
|
|
20970
|
-
bootstrap_output: result.bootstrapOutput
|
|
20936
|
+
config: agentConfigToDTO(updated)
|
|
20971
20937
|
};
|
|
20972
20938
|
}
|
|
20973
20939
|
|
|
@@ -21011,7 +20977,8 @@ const createTaskBodySchema = z$1.object({
|
|
|
21011
20977
|
});
|
|
21012
20978
|
const reconfigBodySchema = z$1.object({
|
|
21013
20979
|
role: z$1.string().trim().min(1).optional(),
|
|
21014
|
-
skills: z$1.array(z$1.string().trim().min(1)).optional()
|
|
20980
|
+
skills: z$1.array(z$1.string().trim().min(1)).optional(),
|
|
20981
|
+
setup_script: z$1.string().trim().min(1).optional()
|
|
21015
20982
|
});
|
|
21016
20983
|
function getAgentParam(value) {
|
|
21017
20984
|
if (typeof value !== "string" || value.trim().length === 0) throw new ApiError({
|
|
@@ -21046,7 +21013,7 @@ function createApiRouter(options) {
|
|
|
21046
21013
|
}));
|
|
21047
21014
|
router.get("/agents/:agent/configs/:project_id", asyncHandler(async (req, res) => {
|
|
21048
21015
|
const agent = getAgentParam(req.params.agent);
|
|
21049
|
-
const result = await
|
|
21016
|
+
const result = await getAgentConfig({
|
|
21050
21017
|
agent,
|
|
21051
21018
|
projectId: getProjectIdParam(req.params.project_id),
|
|
21052
21019
|
provider: new TaskListTidbProvider(agent, logger, { db })
|
|
@@ -21058,12 +21025,13 @@ function createApiRouter(options) {
|
|
|
21058
21025
|
const projectId = getProjectIdParam(req.params.project_id);
|
|
21059
21026
|
const body = reconfigBodySchema.parse(req.body);
|
|
21060
21027
|
const provider = new TaskListTidbProvider(agent, logger, { db });
|
|
21061
|
-
const result = await
|
|
21028
|
+
const result = await reconfigAgentConfig({
|
|
21062
21029
|
agent,
|
|
21063
21030
|
reconfig: {
|
|
21064
21031
|
projectId,
|
|
21065
21032
|
role: body.role,
|
|
21066
|
-
skills: body.skills
|
|
21033
|
+
skills: body.skills,
|
|
21034
|
+
setupScript: body.setup_script
|
|
21067
21035
|
},
|
|
21068
21036
|
provider
|
|
21069
21037
|
});
|
|
@@ -30958,7 +30926,7 @@ function createAgentsMcpServer(options) {
|
|
|
30958
30926
|
};
|
|
30959
30927
|
});
|
|
30960
30928
|
server.registerTool("configs.get", {
|
|
30961
|
-
description: "Get an agent's config for a project
|
|
30929
|
+
description: "Get an agent's config for a project.",
|
|
30962
30930
|
inputSchema: {
|
|
30963
30931
|
agent: z$1.string().min(1),
|
|
30964
30932
|
project_id: z$1.string().min(1)
|
|
@@ -30969,7 +30937,7 @@ function createAgentsMcpServer(options) {
|
|
|
30969
30937
|
type: "text",
|
|
30970
30938
|
text: "OK"
|
|
30971
30939
|
}],
|
|
30972
|
-
structuredContent: await
|
|
30940
|
+
structuredContent: await getAgentConfig({
|
|
30973
30941
|
agent,
|
|
30974
30942
|
projectId: project_id,
|
|
30975
30943
|
provider: new TaskListTidbProvider(agent, options.logger, { db: options.db })
|
|
@@ -30982,21 +30950,23 @@ function createAgentsMcpServer(options) {
|
|
|
30982
30950
|
agent: z$1.string().min(1),
|
|
30983
30951
|
project_id: z$1.string().min(1),
|
|
30984
30952
|
role: z$1.string().trim().min(1).optional(),
|
|
30985
|
-
skills: z$1.array(z$1.string().trim().min(1)).optional()
|
|
30953
|
+
skills: z$1.array(z$1.string().trim().min(1)).optional(),
|
|
30954
|
+
setup_script: z$1.string().trim().min(1).optional()
|
|
30986
30955
|
}
|
|
30987
|
-
}, async ({ agent, project_id, role, skills }) => {
|
|
30956
|
+
}, async ({ agent, project_id, role, skills, setup_script }) => {
|
|
30988
30957
|
const provider = new TaskListTidbProvider(agent, options.logger, { db: options.db });
|
|
30989
30958
|
return {
|
|
30990
30959
|
content: [{
|
|
30991
30960
|
type: "text",
|
|
30992
30961
|
text: "OK"
|
|
30993
30962
|
}],
|
|
30994
|
-
structuredContent: await
|
|
30963
|
+
structuredContent: await reconfigAgentConfig({
|
|
30995
30964
|
agent,
|
|
30996
30965
|
reconfig: {
|
|
30997
30966
|
projectId: project_id,
|
|
30998
30967
|
role,
|
|
30999
|
-
skills
|
|
30968
|
+
skills,
|
|
30969
|
+
setupScript: setup_script
|
|
31000
30970
|
},
|
|
31001
30971
|
provider
|
|
31002
30972
|
})
|
|
@@ -31121,9 +31091,10 @@ function createServerCommand(version) {
|
|
|
31121
31091
|
//#endregion
|
|
31122
31092
|
//#region src/cli/commands/show-config.ts
|
|
31123
31093
|
function createShowConfigCommand(version) {
|
|
31124
|
-
return createCommand("show-config").version(version).description("Show agent config for a project").argument("<name>", "The name of the agent.").
|
|
31125
|
-
const [name
|
|
31094
|
+
return createCommand("show-config").version(version).description("Show agent config for a project").argument("<name>", "The name of the agent.").option("--project-id <project-id>", "The project id. Defaults to DEFAULT_PANTHEON_PROJECT_ID.").option("--json", "Output config as JSON.").action(async function() {
|
|
31095
|
+
const [name] = this.args;
|
|
31126
31096
|
const options = this.opts();
|
|
31097
|
+
const projectId = resolvePantheonProjectId(options.projectId);
|
|
31127
31098
|
if (!ensureEnv(["DATABASE_URL"])) return;
|
|
31128
31099
|
if (projectId) {
|
|
31129
31100
|
const config = await showAgentConfig(name, projectId);
|
|
@@ -31143,6 +31114,7 @@ function createShowConfigCommand(version) {
|
|
|
31143
31114
|
role: config.role,
|
|
31144
31115
|
execute_agent: config.execute_agent,
|
|
31145
31116
|
prototype_url: config.prototype_url,
|
|
31117
|
+
setup_script: config.setup_script,
|
|
31146
31118
|
skills: Array.isArray(config.skills) ? config.skills.join(", ") : String(config.skills)
|
|
31147
31119
|
}]);
|
|
31148
31120
|
return;
|
|
@@ -31164,6 +31136,7 @@ function createShowConfigCommand(version) {
|
|
|
31164
31136
|
role: config.role,
|
|
31165
31137
|
execute_agent: config.execute_agent,
|
|
31166
31138
|
prototype_url: config.prototype_url,
|
|
31139
|
+
setup_script: config.setup_script,
|
|
31167
31140
|
skills: Array.isArray(config.skills) ? config.skills.join(", ") : String(config.skills)
|
|
31168
31141
|
})));
|
|
31169
31142
|
});
|
|
@@ -31370,8 +31343,8 @@ const mcpToolCallItemSchema = z$1.object({
|
|
|
31370
31343
|
result: z$1.object({
|
|
31371
31344
|
content: z$1.array(z$1.any()),
|
|
31372
31345
|
structured_content: z$1.any()
|
|
31373
|
-
}).optional(),
|
|
31374
|
-
error: z$1.object({ message: z$1.string() }).optional(),
|
|
31346
|
+
}).nullable().transform((v) => v ?? void 0).optional(),
|
|
31347
|
+
error: z$1.object({ message: z$1.string() }).nullable().transform((v) => v ?? void 0).optional(),
|
|
31375
31348
|
status: z$1.enum([
|
|
31376
31349
|
"in_progress",
|
|
31377
31350
|
"completed",
|
|
@@ -31760,16 +31733,40 @@ function createCodexNormalizer(options = {}) {
|
|
|
31760
31733
|
|
|
31761
31734
|
//#endregion
|
|
31762
31735
|
//#region ../agent-stream-parser/src/claude.ts
|
|
31763
|
-
|
|
31764
|
-
|
|
31765
|
-
|
|
31766
|
-
|
|
31767
|
-
|
|
31736
|
+
function toContentBlockEnvelope(value) {
|
|
31737
|
+
if (!isRecord(value) || typeof value.type !== "string") return null;
|
|
31738
|
+
return {
|
|
31739
|
+
type: value.type,
|
|
31740
|
+
text: typeof value.text === "string" ? value.text : void 0,
|
|
31741
|
+
id: typeof value.id === "string" ? value.id : void 0,
|
|
31742
|
+
name: typeof value.name === "string" ? value.name : void 0,
|
|
31743
|
+
input: value.input
|
|
31744
|
+
};
|
|
31745
|
+
}
|
|
31746
|
+
function toToolResultEnvelope(value) {
|
|
31747
|
+
if (!isRecord(value) || value.type !== "tool_result") return null;
|
|
31748
|
+
return {
|
|
31749
|
+
type: "tool_result",
|
|
31750
|
+
tool_use_id: typeof value.tool_use_id === "string" ? value.tool_use_id : void 0,
|
|
31751
|
+
content: value.content,
|
|
31752
|
+
is_error: typeof value.is_error === "boolean" ? value.is_error : void 0
|
|
31753
|
+
};
|
|
31754
|
+
}
|
|
31755
|
+
function getMessageContentBlocks(value) {
|
|
31756
|
+
if (!isRecord(value) || !Array.isArray(value.content)) return [];
|
|
31757
|
+
return value.content;
|
|
31758
|
+
}
|
|
31759
|
+
function isToolUseLikeType(type) {
|
|
31760
|
+
return type === "tool_use" || type === "mcp_tool_use" || type === "server_tool_use";
|
|
31761
|
+
}
|
|
31768
31762
|
function createClaudeCodeNormalizer(options = {}) {
|
|
31769
31763
|
const includeMetaEvents = options.includeMetaEvents ?? false;
|
|
31770
31764
|
const textBlocks = /* @__PURE__ */ new Map();
|
|
31771
31765
|
const toolBlocks = /* @__PURE__ */ new Map();
|
|
31772
|
-
|
|
31766
|
+
const assistantTextBlocks = /* @__PURE__ */ new Map();
|
|
31767
|
+
const knownToolCallIds = /* @__PURE__ */ new Set();
|
|
31768
|
+
let currentAssistantMessageId;
|
|
31769
|
+
let assistantFallbackMessageSeq = 0;
|
|
31773
31770
|
function maybeMeta(event) {
|
|
31774
31771
|
if (!includeMetaEvents) return [];
|
|
31775
31772
|
return [{
|
|
@@ -31777,145 +31774,50 @@ function createClaudeCodeNormalizer(options = {}) {
|
|
|
31777
31774
|
data: event
|
|
31778
31775
|
}];
|
|
31779
31776
|
}
|
|
31780
|
-
function
|
|
31781
|
-
const
|
|
31782
|
-
if (
|
|
31783
|
-
const id = existing?.id ?? `claude-text-${index}`;
|
|
31784
|
-
textBlocks.set(index, {
|
|
31785
|
-
id,
|
|
31786
|
-
open: true
|
|
31787
|
-
});
|
|
31788
|
-
return [{
|
|
31789
|
-
type: "text-start",
|
|
31790
|
-
id
|
|
31791
|
-
}];
|
|
31792
|
-
}
|
|
31793
|
-
function ensureToolBlock(index, block) {
|
|
31794
|
-
const existing = toolBlocks.get(index);
|
|
31795
|
-
if (existing?.open) return [];
|
|
31796
|
-
const toolCallId = block?.id ?? existing?.toolCallId ?? `claude-tool-${index}`;
|
|
31797
|
-
const toolName = block?.name ?? existing?.toolName ?? "tool";
|
|
31798
|
-
toolBlocks.set(index, {
|
|
31799
|
-
toolCallId,
|
|
31800
|
-
toolName,
|
|
31801
|
-
json: "",
|
|
31802
|
-
open: true
|
|
31803
|
-
});
|
|
31804
|
-
return [{
|
|
31805
|
-
type: "tool-input-start",
|
|
31806
|
-
toolCallId,
|
|
31807
|
-
toolName,
|
|
31808
|
-
dynamic: true
|
|
31809
|
-
}];
|
|
31810
|
-
}
|
|
31811
|
-
function handleStreamEvent(event) {
|
|
31812
|
-
if (!isRecord(event) || typeof event.type !== "string") return [];
|
|
31777
|
+
function handleAssistantMessage(message) {
|
|
31778
|
+
const resolvedMessageId = getAssistantMessageId(message);
|
|
31779
|
+
if (!resolvedMessageId) return [];
|
|
31813
31780
|
const out = [];
|
|
31814
|
-
|
|
31815
|
-
|
|
31816
|
-
|
|
31817
|
-
|
|
31818
|
-
|
|
31819
|
-
|
|
31820
|
-
|
|
31821
|
-
|
|
31822
|
-
|
|
31823
|
-
|
|
31824
|
-
|
|
31825
|
-
|
|
31826
|
-
|
|
31827
|
-
|
|
31828
|
-
|
|
31829
|
-
|
|
31830
|
-
|
|
31831
|
-
|
|
31832
|
-
|
|
31833
|
-
if (delta.type === "text_delta") {
|
|
31834
|
-
const text = typeof delta.text === "string" ? delta.text : "";
|
|
31835
|
-
if (!text) return [];
|
|
31836
|
-
out.push(...ensureTextBlock(index));
|
|
31837
|
-
const id = textBlocks.get(index).id;
|
|
31838
|
-
out.push({
|
|
31839
|
-
type: "text-delta",
|
|
31840
|
-
id,
|
|
31841
|
-
delta: text
|
|
31842
|
-
});
|
|
31843
|
-
return out;
|
|
31844
|
-
}
|
|
31845
|
-
if (delta.type === "input_json_delta") {
|
|
31846
|
-
const partialJson = typeof delta.partial_json === "string" ? delta.partial_json : "";
|
|
31847
|
-
if (!partialJson) return [];
|
|
31848
|
-
out.push(...ensureToolBlock(index));
|
|
31849
|
-
const tool = toolBlocks.get(index);
|
|
31850
|
-
tool.json += partialJson;
|
|
31851
|
-
out.push({
|
|
31852
|
-
type: "tool-input-delta",
|
|
31853
|
-
toolCallId: tool.toolCallId,
|
|
31854
|
-
inputTextDelta: partialJson
|
|
31855
|
-
});
|
|
31856
|
-
return out;
|
|
31857
|
-
}
|
|
31858
|
-
return [];
|
|
31859
|
-
}
|
|
31860
|
-
case "content_block_stop": {
|
|
31861
|
-
if (index == null) return [];
|
|
31862
|
-
sawStreamEvents = true;
|
|
31863
|
-
const text = textBlocks.get(index);
|
|
31864
|
-
if (text?.open) {
|
|
31865
|
-
text.open = false;
|
|
31781
|
+
if (currentAssistantMessageId && currentAssistantMessageId !== resolvedMessageId) out.push(...closeAssistantTextBlocksForMessage(currentAssistantMessageId));
|
|
31782
|
+
currentAssistantMessageId = resolvedMessageId;
|
|
31783
|
+
const blocks = getMessageContentBlocks(message);
|
|
31784
|
+
const seenTextBlockKeys = /* @__PURE__ */ new Set();
|
|
31785
|
+
blocks.forEach((block, index) => {
|
|
31786
|
+
const contentBlock = toContentBlockEnvelope(block);
|
|
31787
|
+
if (!contentBlock) return;
|
|
31788
|
+
if (contentBlock.type === "text") {
|
|
31789
|
+
const key = `${resolvedMessageId}:${index}`;
|
|
31790
|
+
seenTextBlockKeys.add(key);
|
|
31791
|
+
let state = assistantTextBlocks.get(key);
|
|
31792
|
+
if (!state || !state.open) {
|
|
31793
|
+
state = {
|
|
31794
|
+
id: state?.id ?? `claude-assistant-text-${resolvedMessageId}-${index}`,
|
|
31795
|
+
messageId: resolvedMessageId,
|
|
31796
|
+
lastText: state?.lastText ?? "",
|
|
31797
|
+
open: true
|
|
31798
|
+
};
|
|
31799
|
+
assistantTextBlocks.set(key, state);
|
|
31866
31800
|
out.push({
|
|
31867
|
-
type: "text-
|
|
31868
|
-
id:
|
|
31801
|
+
type: "text-start",
|
|
31802
|
+
id: state.id
|
|
31869
31803
|
});
|
|
31870
31804
|
}
|
|
31871
|
-
const
|
|
31872
|
-
|
|
31873
|
-
|
|
31874
|
-
let input = tool.json ? tool.json : {};
|
|
31875
|
-
if (typeof input === "string") {
|
|
31876
|
-
const parsed = safeJsonParse(input);
|
|
31877
|
-
if (parsed.ok) input = parsed.value;
|
|
31878
|
-
}
|
|
31805
|
+
const fullText = contentBlock.text ?? "";
|
|
31806
|
+
const { delta, reset } = computeAppendDelta(state.lastText, fullText);
|
|
31807
|
+
if (delta) {
|
|
31879
31808
|
out.push({
|
|
31880
|
-
type: "
|
|
31881
|
-
|
|
31882
|
-
|
|
31883
|
-
input,
|
|
31884
|
-
dynamic: true
|
|
31809
|
+
type: "text-delta",
|
|
31810
|
+
id: state.id,
|
|
31811
|
+
delta
|
|
31885
31812
|
});
|
|
31813
|
+
state.lastText = reset ? fullText : state.lastText + delta;
|
|
31886
31814
|
}
|
|
31887
|
-
return out;
|
|
31888
|
-
}
|
|
31889
|
-
default: return [];
|
|
31890
|
-
}
|
|
31891
|
-
}
|
|
31892
|
-
function handleAssistantMessage(message) {
|
|
31893
|
-
if (sawStreamEvents) return [];
|
|
31894
|
-
const blocks = Array.isArray(message.content) ? message.content : [];
|
|
31895
|
-
const out = [];
|
|
31896
|
-
blocks.forEach((block, index) => {
|
|
31897
|
-
if (!isRecord(block) || typeof block.type !== "string") return;
|
|
31898
|
-
if (block.type === "text") {
|
|
31899
|
-
const id = `claude-assistant-text-${index}`;
|
|
31900
|
-
const text = typeof block.text === "string" ? block.text : "";
|
|
31901
|
-
out.push({
|
|
31902
|
-
type: "text-start",
|
|
31903
|
-
id
|
|
31904
|
-
});
|
|
31905
|
-
if (text) out.push({
|
|
31906
|
-
type: "text-delta",
|
|
31907
|
-
id,
|
|
31908
|
-
delta: text
|
|
31909
|
-
});
|
|
31910
|
-
out.push({
|
|
31911
|
-
type: "text-end",
|
|
31912
|
-
id
|
|
31913
|
-
});
|
|
31914
31815
|
}
|
|
31915
|
-
if (
|
|
31916
|
-
const toolCallId =
|
|
31917
|
-
const toolName =
|
|
31918
|
-
const input =
|
|
31816
|
+
if (isToolUseLikeType(contentBlock.type)) {
|
|
31817
|
+
const toolCallId = contentBlock.id ?? `claude-assistant-tool-${index}`;
|
|
31818
|
+
const toolName = contentBlock.name ?? "tool";
|
|
31819
|
+
const input = isRecord(contentBlock.input) ? contentBlock.input : contentBlock.input;
|
|
31820
|
+
knownToolCallIds.add(toolCallId);
|
|
31919
31821
|
out.push({
|
|
31920
31822
|
type: "tool-input-available",
|
|
31921
31823
|
toolCallId,
|
|
@@ -31925,6 +31827,33 @@ function createClaudeCodeNormalizer(options = {}) {
|
|
|
31925
31827
|
});
|
|
31926
31828
|
}
|
|
31927
31829
|
});
|
|
31830
|
+
for (const [key, state] of assistantTextBlocks) {
|
|
31831
|
+
if (state.messageId !== resolvedMessageId) continue;
|
|
31832
|
+
if (!state.open) continue;
|
|
31833
|
+
if (seenTextBlockKeys.has(key)) continue;
|
|
31834
|
+
state.open = false;
|
|
31835
|
+
out.push({
|
|
31836
|
+
type: "text-end",
|
|
31837
|
+
id: state.id
|
|
31838
|
+
});
|
|
31839
|
+
}
|
|
31840
|
+
return out;
|
|
31841
|
+
}
|
|
31842
|
+
function getAssistantMessageId(message) {
|
|
31843
|
+
if (isRecord(message) && typeof message.id === "string") return message.id;
|
|
31844
|
+
assistantFallbackMessageSeq += 1;
|
|
31845
|
+
return `claude-assistant-fallback-${assistantFallbackMessageSeq}`;
|
|
31846
|
+
}
|
|
31847
|
+
function closeAssistantTextBlocksForMessage(messageId) {
|
|
31848
|
+
const out = [];
|
|
31849
|
+
for (const state of assistantTextBlocks.values()) {
|
|
31850
|
+
if (state.messageId !== messageId || !state.open) continue;
|
|
31851
|
+
state.open = false;
|
|
31852
|
+
out.push({
|
|
31853
|
+
type: "text-end",
|
|
31854
|
+
id: state.id
|
|
31855
|
+
});
|
|
31856
|
+
}
|
|
31928
31857
|
return out;
|
|
31929
31858
|
}
|
|
31930
31859
|
function formatToolResultOutput(content, toolUseResult) {
|
|
@@ -31948,14 +31877,26 @@ function createClaudeCodeNormalizer(options = {}) {
|
|
|
31948
31877
|
return "Tool execution failed";
|
|
31949
31878
|
}
|
|
31950
31879
|
function handleUserMessage(message, toolUseResult) {
|
|
31951
|
-
const blocks =
|
|
31880
|
+
const blocks = getMessageContentBlocks(message);
|
|
31952
31881
|
const out = [];
|
|
31953
31882
|
blocks.forEach((block, index) => {
|
|
31954
|
-
|
|
31955
|
-
|
|
31956
|
-
const
|
|
31883
|
+
const toolResult = toToolResultEnvelope(block);
|
|
31884
|
+
if (!toolResult) return;
|
|
31885
|
+
const toolCallId = toolResult.tool_use_id ?? `claude-tool-result-${index}`;
|
|
31886
|
+
const content = toolResult.content;
|
|
31957
31887
|
const interrupted = isRecord(toolUseResult) && toolUseResult.interrupted === true;
|
|
31958
|
-
|
|
31888
|
+
const isError = toolResult.is_error === true || interrupted;
|
|
31889
|
+
if (!knownToolCallIds.has(toolCallId)) {
|
|
31890
|
+
knownToolCallIds.add(toolCallId);
|
|
31891
|
+
out.push({
|
|
31892
|
+
type: "tool-input-available",
|
|
31893
|
+
toolCallId,
|
|
31894
|
+
toolName: "tool",
|
|
31895
|
+
input: {},
|
|
31896
|
+
dynamic: true
|
|
31897
|
+
});
|
|
31898
|
+
}
|
|
31899
|
+
if (isError) {
|
|
31959
31900
|
out.push({
|
|
31960
31901
|
type: "tool-output-error",
|
|
31961
31902
|
toolCallId,
|
|
@@ -31974,12 +31915,11 @@ function createClaudeCodeNormalizer(options = {}) {
|
|
|
31974
31915
|
return out;
|
|
31975
31916
|
}
|
|
31976
31917
|
function push(chunk) {
|
|
31977
|
-
|
|
31978
|
-
if (!parsed.success) return {
|
|
31918
|
+
if (!isRecord(chunk) || typeof chunk.type !== "string") return {
|
|
31979
31919
|
recognized: false,
|
|
31980
31920
|
chunks: []
|
|
31981
31921
|
};
|
|
31982
|
-
const msg =
|
|
31922
|
+
const msg = chunk;
|
|
31983
31923
|
const out = [];
|
|
31984
31924
|
switch (msg.type) {
|
|
31985
31925
|
case "system": {
|
|
@@ -32003,39 +31943,28 @@ function createClaudeCodeNormalizer(options = {}) {
|
|
|
32003
31943
|
chunks: out
|
|
32004
31944
|
};
|
|
32005
31945
|
}
|
|
32006
|
-
case "stream_event": {
|
|
32007
|
-
|
|
32008
|
-
|
|
32009
|
-
|
|
32010
|
-
|
|
32011
|
-
|
|
32012
|
-
return {
|
|
32013
|
-
recognized: true,
|
|
32014
|
-
chunks: handleStreamEvent(event.data)
|
|
32015
|
-
};
|
|
32016
|
-
}
|
|
32017
|
-
case "assistant": {
|
|
32018
|
-
const message = msg.message;
|
|
32019
|
-
if (!isRecord(message)) return {
|
|
31946
|
+
case "stream_event": return {
|
|
31947
|
+
recognized: true,
|
|
31948
|
+
chunks: []
|
|
31949
|
+
};
|
|
31950
|
+
case "assistant":
|
|
31951
|
+
if (!isRecord(msg.message)) return {
|
|
32020
31952
|
recognized: false,
|
|
32021
31953
|
chunks: []
|
|
32022
31954
|
};
|
|
32023
31955
|
return {
|
|
32024
31956
|
recognized: true,
|
|
32025
|
-
chunks: handleAssistantMessage(message)
|
|
31957
|
+
chunks: handleAssistantMessage(msg.message)
|
|
32026
31958
|
};
|
|
32027
|
-
|
|
32028
|
-
|
|
32029
|
-
const message = msg.message;
|
|
32030
|
-
if (!isRecord(message)) return {
|
|
31959
|
+
case "user":
|
|
31960
|
+
if (!isRecord(msg.message)) return {
|
|
32031
31961
|
recognized: false,
|
|
32032
31962
|
chunks: []
|
|
32033
31963
|
};
|
|
32034
31964
|
return {
|
|
32035
31965
|
recognized: true,
|
|
32036
|
-
chunks: handleUserMessage(message, msg.tool_use_result)
|
|
31966
|
+
chunks: handleUserMessage(msg.message, msg.tool_use_result)
|
|
32037
31967
|
};
|
|
32038
|
-
}
|
|
32039
31968
|
case "result": return {
|
|
32040
31969
|
recognized: true,
|
|
32041
31970
|
chunks: maybeMeta({
|
|
@@ -32071,6 +32000,14 @@ function createClaudeCodeNormalizer(options = {}) {
|
|
|
32071
32000
|
dynamic: true
|
|
32072
32001
|
});
|
|
32073
32002
|
}
|
|
32003
|
+
for (const state of assistantTextBlocks.values()) {
|
|
32004
|
+
if (!state.open) continue;
|
|
32005
|
+
state.open = false;
|
|
32006
|
+
out.push({
|
|
32007
|
+
type: "text-end",
|
|
32008
|
+
id: state.id
|
|
32009
|
+
});
|
|
32010
|
+
}
|
|
32074
32011
|
return out;
|
|
32075
32012
|
}
|
|
32076
32013
|
return {
|
|
@@ -32198,7 +32135,7 @@ function commandBasename(value) {
|
|
|
32198
32135
|
const lastSlash = value.lastIndexOf("/");
|
|
32199
32136
|
return lastSlash === -1 ? value : value.slice(lastSlash + 1);
|
|
32200
32137
|
}
|
|
32201
|
-
function parseShellEntries(line) {
|
|
32138
|
+
function parseShellEntries$1(line) {
|
|
32202
32139
|
try {
|
|
32203
32140
|
return parse(line);
|
|
32204
32141
|
} catch {
|
|
@@ -32241,7 +32178,7 @@ function pickLastNonOptionArg(tokens) {
|
|
|
32241
32178
|
return values.length > 0 ? values[values.length - 1] : void 0;
|
|
32242
32179
|
}
|
|
32243
32180
|
function parseExploredItem(line) {
|
|
32244
|
-
const entries = parseShellEntries(normalizeCommand(line));
|
|
32181
|
+
const entries = parseShellEntries$1(normalizeCommand(line));
|
|
32245
32182
|
if (!entries) return void 0;
|
|
32246
32183
|
const tokens = takeMainTokens(entries);
|
|
32247
32184
|
if (tokens.length === 0) return void 0;
|
|
@@ -32320,128 +32257,8 @@ function formatCommandExecutionDisplayCommand(command) {
|
|
|
32320
32257
|
}
|
|
32321
32258
|
|
|
32322
32259
|
//#endregion
|
|
32323
|
-
//#region src/cli/commands/watch.ts
|
|
32324
|
-
const
|
|
32325
|
-
function parseListWidth(value) {
|
|
32326
|
-
const width = Number(value);
|
|
32327
|
-
if (!Number.isInteger(width) || width <= 0) throw new InvalidArgumentError("list-width requires a positive integer, e.g. 32");
|
|
32328
|
-
return width;
|
|
32329
|
-
}
|
|
32330
|
-
function ensureEnvOrExit(keys) {
|
|
32331
|
-
const missing = keys.filter((key) => !process.env[key]);
|
|
32332
|
-
if (missing.length === 0) return;
|
|
32333
|
-
for (const key of missing) console.error(`${key} environment variable is not set.`);
|
|
32334
|
-
process.exit(1);
|
|
32335
|
-
}
|
|
32336
|
-
function toStreamSourceFromExecuteAgent(executeAgent) {
|
|
32337
|
-
if (!executeAgent) return void 0;
|
|
32338
|
-
const normalized = executeAgent.toLowerCase();
|
|
32339
|
-
if (normalized.includes("claude")) return "claude-code";
|
|
32340
|
-
if (normalized.includes("codex")) return "codex";
|
|
32341
|
-
}
|
|
32342
|
-
function detectStreamSourceFromRawPayload(payload) {
|
|
32343
|
-
if (payload.includes("\"type\":\"thread.") || payload.includes("\"type\":\"turn.") || payload.includes("\"type\":\"item.")) return "codex";
|
|
32344
|
-
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";
|
|
32345
|
-
}
|
|
32346
|
-
async function getAgentExecuteAgentMap(db, targets) {
|
|
32347
|
-
const agents = Array.from(new Set(targets.map((t) => t.agent)));
|
|
32348
|
-
if (agents.length === 0) return /* @__PURE__ */ new Map();
|
|
32349
|
-
const configs = await db.selectFrom("agent_project_config").select([
|
|
32350
|
-
"agent",
|
|
32351
|
-
"project_id",
|
|
32352
|
-
"execute_agent"
|
|
32353
|
-
]).where("agent", "in", agents).execute();
|
|
32354
|
-
const map = /* @__PURE__ */ new Map();
|
|
32355
|
-
for (const row of configs) map.set(`${row.agent}|${row.project_id}`, row.execute_agent);
|
|
32356
|
-
return map;
|
|
32357
|
-
}
|
|
32358
|
-
async function loadTasksByIds(db, ids) {
|
|
32359
|
-
if (ids.length === 0) return [];
|
|
32360
|
-
const rows = await db.selectFrom("task").selectAll().where("id", "in", ids).execute();
|
|
32361
|
-
const out = [];
|
|
32362
|
-
for (const row of rows) {
|
|
32363
|
-
const parsed = taskItemSchema.safeParse(row);
|
|
32364
|
-
if (!parsed.success) {
|
|
32365
|
-
console.error(`Failed to parse task row id=${row.id} agent=${row.agent} status=${row.status}: ${parsed.error.message}`);
|
|
32366
|
-
continue;
|
|
32367
|
-
}
|
|
32368
|
-
out.push({
|
|
32369
|
-
agent: row.agent,
|
|
32370
|
-
task: parsed.data
|
|
32371
|
-
});
|
|
32372
|
-
}
|
|
32373
|
-
return out;
|
|
32374
|
-
}
|
|
32375
|
-
async function loadTasksForAgent(db, agent) {
|
|
32376
|
-
const rows = await db.selectFrom("task").selectAll().where("agent", "=", agent).execute();
|
|
32377
|
-
const out = [];
|
|
32378
|
-
for (const row of rows) {
|
|
32379
|
-
const parsed = taskItemSchema.safeParse(row);
|
|
32380
|
-
if (!parsed.success) continue;
|
|
32381
|
-
out.push(parsed.data);
|
|
32382
|
-
}
|
|
32383
|
-
return out;
|
|
32384
|
-
}
|
|
32385
|
-
async function loadAllTasks(db, limit) {
|
|
32386
|
-
const rows = await db.selectFrom("task").selectAll().orderBy("queued_at", "desc").limit(limit).execute();
|
|
32387
|
-
const out = [];
|
|
32388
|
-
for (const row of rows) {
|
|
32389
|
-
const parsed = taskItemSchema.safeParse(row);
|
|
32390
|
-
if (!parsed.success) continue;
|
|
32391
|
-
out.push({
|
|
32392
|
-
agent: row.agent,
|
|
32393
|
-
task: parsed.data
|
|
32394
|
-
});
|
|
32395
|
-
}
|
|
32396
|
-
return out;
|
|
32397
|
-
}
|
|
32398
|
-
async function resolveWatchTargets(options) {
|
|
32399
|
-
const warnings = [];
|
|
32400
|
-
let selected = [];
|
|
32401
|
-
if (options.taskIds.length > 0) {
|
|
32402
|
-
const uniqueTaskIds = Array.from(new Set(options.taskIds));
|
|
32403
|
-
const found = await loadTasksByIds(options.db, uniqueTaskIds);
|
|
32404
|
-
const foundIds = new Set(found.map((t) => t.task.id));
|
|
32405
|
-
const missing = uniqueTaskIds.filter((id) => !foundIds.has(id));
|
|
32406
|
-
if (missing.length > 0) warnings.push(`Requested task IDs not found: ${missing.join(", ")}`);
|
|
32407
|
-
const byId = new Map(found.map((t) => [t.task.id, t]));
|
|
32408
|
-
selected = uniqueTaskIds.map((id) => byId.get(id)).filter(Boolean);
|
|
32409
|
-
if (selected.length === 0) warnings.push("No requested tasks found; falling back to default selection.");
|
|
32410
|
-
} else if (options.agentNames.length > 0) {
|
|
32411
|
-
const uniqueAgents = Array.from(new Set(options.agentNames));
|
|
32412
|
-
if (uniqueAgents.length === 1) {
|
|
32413
|
-
selected = selectSingleAgentWatchTasks(await loadTasksForAgent(options.db, uniqueAgents[0]), { finishedLimit: 3 }).map((task) => ({
|
|
32414
|
-
agent: uniqueAgents[0],
|
|
32415
|
-
task
|
|
32416
|
-
}));
|
|
32417
|
-
if (selected.length === 0) warnings.push(`No tasks found for agent ${uniqueAgents[0]}; falling back to default selection.`);
|
|
32418
|
-
} else {
|
|
32419
|
-
selected = selectMultiAgentWatchTasks(await Promise.all(uniqueAgents.map(async (agent) => {
|
|
32420
|
-
return (await loadTasksForAgent(options.db, agent)).map((task) => ({
|
|
32421
|
-
agent,
|
|
32422
|
-
task
|
|
32423
|
-
}));
|
|
32424
|
-
})).then((groups) => groups.flat()), uniqueAgents);
|
|
32425
|
-
const foundAgents = new Set(selected.map((t) => t.agent));
|
|
32426
|
-
const missing = uniqueAgents.filter((agent) => !foundAgents.has(agent));
|
|
32427
|
-
if (missing.length > 0) warnings.push(`No tasks found for agent(s): ${missing.join(", ")}`);
|
|
32428
|
-
if (selected.length === 0) warnings.push("No requested agent tasks found; falling back to default selection.");
|
|
32429
|
-
}
|
|
32430
|
-
} else warnings.push("No targets specified; selecting up to 3 agents automatically.");
|
|
32431
|
-
if (selected.length === 0) selected = selectFallbackWatchTasks(await loadAllTasks(options.db, 500), { agentLimit: 3 });
|
|
32432
|
-
const executeAgentMap = await getAgentExecuteAgentMap(options.db, selected);
|
|
32433
|
-
return {
|
|
32434
|
-
targets: selected.map((entry) => ({
|
|
32435
|
-
...entry,
|
|
32436
|
-
executeAgent: executeAgentMap.get(`${entry.agent}|${entry.task.project_id}`)
|
|
32437
|
-
})),
|
|
32438
|
-
warnings
|
|
32439
|
-
};
|
|
32440
|
-
}
|
|
32441
|
-
function makeStreamUrl(streamId) {
|
|
32442
|
-
return `${PANTHEON_BASE_URL}/ai_stream_proxy/v2/streams/${encodeURIComponent(streamId)}/stream?format=opaque-stream-json`;
|
|
32443
|
-
}
|
|
32444
|
-
const ANSI = {
|
|
32260
|
+
//#region src/cli/commands/watch/log-output.ts
|
|
32261
|
+
const ANSI$1 = {
|
|
32445
32262
|
reset: "\x1B[0m",
|
|
32446
32263
|
bold: "\x1B[1m",
|
|
32447
32264
|
dim: "\x1B[2m",
|
|
@@ -32451,67 +32268,280 @@ const ANSI = {
|
|
|
32451
32268
|
cyan: "\x1B[36m",
|
|
32452
32269
|
gray: "\x1B[90m"
|
|
32453
32270
|
};
|
|
32454
|
-
function
|
|
32455
|
-
|
|
32456
|
-
if (process.env.NO_COLOR != null) return false;
|
|
32457
|
-
return true;
|
|
32458
|
-
}
|
|
32459
|
-
function sgrWrap(text, code, enabled) {
|
|
32460
|
-
return enabled ? `${code}${text}${ANSI.reset}` : text;
|
|
32271
|
+
function sgrWrap$1(text, code, enabled) {
|
|
32272
|
+
return enabled ? `${code}${text}${ANSI$1.reset}` : text;
|
|
32461
32273
|
}
|
|
32462
|
-
function bold(text, enabled) {
|
|
32463
|
-
return sgrWrap(text, ANSI.bold, enabled);
|
|
32274
|
+
function bold$1(text, enabled) {
|
|
32275
|
+
return sgrWrap$1(text, ANSI$1.bold, enabled);
|
|
32464
32276
|
}
|
|
32465
32277
|
function dim(text, enabled) {
|
|
32466
|
-
return sgrWrap(text, ANSI.dim, enabled);
|
|
32278
|
+
return sgrWrap$1(text, ANSI$1.dim, enabled);
|
|
32467
32279
|
}
|
|
32468
32280
|
function gray(text, enabled) {
|
|
32469
|
-
return sgrWrap(text, ANSI.gray, enabled);
|
|
32281
|
+
return sgrWrap$1(text, ANSI$1.gray, enabled);
|
|
32470
32282
|
}
|
|
32471
32283
|
function red(text, enabled) {
|
|
32472
|
-
return sgrWrap(text, ANSI.red, enabled);
|
|
32284
|
+
return sgrWrap$1(text, ANSI$1.red, enabled);
|
|
32473
32285
|
}
|
|
32474
32286
|
function green(text, enabled) {
|
|
32475
|
-
return sgrWrap(text, ANSI.green, enabled);
|
|
32287
|
+
return sgrWrap$1(text, ANSI$1.green, enabled);
|
|
32476
32288
|
}
|
|
32477
32289
|
function yellow(text, enabled) {
|
|
32478
|
-
return sgrWrap(text, ANSI.yellow, enabled);
|
|
32290
|
+
return sgrWrap$1(text, ANSI$1.yellow, enabled);
|
|
32479
32291
|
}
|
|
32480
32292
|
function cyan(text, enabled) {
|
|
32481
|
-
return sgrWrap(text, ANSI.cyan, enabled);
|
|
32293
|
+
return sgrWrap$1(text, ANSI$1.cyan, enabled);
|
|
32482
32294
|
}
|
|
32483
|
-
function dimGray(text, enabled) {
|
|
32484
|
-
return sgrWrap(text, `${ANSI.dim}${ANSI.gray}`, enabled);
|
|
32295
|
+
function dimGray$1(text, enabled) {
|
|
32296
|
+
return sgrWrap$1(text, `${ANSI$1.dim}${ANSI$1.gray}`, enabled);
|
|
32485
32297
|
}
|
|
32486
32298
|
function kv(label, value, style) {
|
|
32487
32299
|
return `${dim(`${label}:`, style)} ${value}`;
|
|
32488
32300
|
}
|
|
32301
|
+
function getCommandExecutionRawCommand(tool) {
|
|
32302
|
+
const title = typeof tool.title === "string" ? tool.title : "";
|
|
32303
|
+
const inputCommand = typeof tool.input?.command === "string" ? tool.input.command : "";
|
|
32304
|
+
return title || inputCommand || void 0;
|
|
32305
|
+
}
|
|
32489
32306
|
function getCommandExecutionDisplayCommand(tool) {
|
|
32490
32307
|
const raw = getCommandExecutionRawCommand(tool);
|
|
32491
32308
|
if (!raw) return void 0;
|
|
32492
32309
|
return formatCommandExecutionDisplayCommand(raw) || void 0;
|
|
32493
32310
|
}
|
|
32494
|
-
function
|
|
32495
|
-
|
|
32496
|
-
|
|
32497
|
-
|
|
32498
|
-
|
|
32311
|
+
function isCommandLikeTool(toolName) {
|
|
32312
|
+
if (!toolName) return false;
|
|
32313
|
+
return toolName === "command_execution" || toolName.toLowerCase() === "bash";
|
|
32314
|
+
}
|
|
32315
|
+
function isClaudeExplorationTool(toolName) {
|
|
32316
|
+
if (!toolName) return false;
|
|
32317
|
+
const normalized = toolName.toLowerCase();
|
|
32318
|
+
return normalized === "read" || normalized === "glob" || normalized === "grep";
|
|
32319
|
+
}
|
|
32320
|
+
function isWriteTool(toolName) {
|
|
32321
|
+
if (!toolName) return false;
|
|
32322
|
+
return toolName.toLowerCase() === "write";
|
|
32323
|
+
}
|
|
32324
|
+
function isEditTool(toolName) {
|
|
32325
|
+
if (!toolName) return false;
|
|
32326
|
+
return toolName.toLowerCase() === "edit";
|
|
32327
|
+
}
|
|
32328
|
+
function toRecord(value) {
|
|
32329
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
32330
|
+
}
|
|
32331
|
+
function toStringValue(value) {
|
|
32332
|
+
return typeof value === "string" ? value : void 0;
|
|
32333
|
+
}
|
|
32334
|
+
function toStringOrUndefined(value) {
|
|
32335
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
32336
|
+
}
|
|
32337
|
+
function extractWritePath(input) {
|
|
32338
|
+
const record = toRecord(input);
|
|
32339
|
+
if (!record) return void 0;
|
|
32340
|
+
return toStringOrUndefined(record.file_path) ?? toStringOrUndefined(record.path) ?? toStringOrUndefined(record.filePath) ?? toStringOrUndefined(record.filepath) ?? toStringOrUndefined(record.filename);
|
|
32341
|
+
}
|
|
32342
|
+
function countContentLines(content) {
|
|
32343
|
+
const normalized = content.replaceAll("\r\n", "\n");
|
|
32344
|
+
if (!normalized) return 0;
|
|
32345
|
+
const lines = normalized.split("\n");
|
|
32346
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
32347
|
+
return lines.length;
|
|
32348
|
+
}
|
|
32349
|
+
function extractWriteAddedLineCount(input) {
|
|
32350
|
+
const record = toRecord(input);
|
|
32351
|
+
if (!record) return void 0;
|
|
32352
|
+
const content = toStringValue(record.content);
|
|
32353
|
+
if (content == null) return void 0;
|
|
32354
|
+
return countContentLines(content);
|
|
32355
|
+
}
|
|
32356
|
+
function extractEditAddedLineCount(input) {
|
|
32357
|
+
const record = toRecord(input);
|
|
32358
|
+
if (!record) return void 0;
|
|
32359
|
+
const oldText = toStringValue(record.old_string) ?? toStringValue(record.oldString) ?? "";
|
|
32360
|
+
const newText = toStringValue(record.new_string) ?? toStringValue(record.newString);
|
|
32361
|
+
if (newText == null) return void 0;
|
|
32362
|
+
const oldLines = countContentLines(oldText);
|
|
32363
|
+
const newLines = countContentLines(newText);
|
|
32364
|
+
return Math.max(0, newLines - oldLines);
|
|
32365
|
+
}
|
|
32366
|
+
function formatWriteToolLabel(tool, style) {
|
|
32367
|
+
const renderedName = bold$1(tool.toolName ?? "Write", style);
|
|
32368
|
+
const path = extractWritePath(tool.input);
|
|
32369
|
+
const addedLines = extractWriteAddedLineCount(tool.input);
|
|
32370
|
+
const chunks = [renderedName];
|
|
32371
|
+
if (path) chunks.push(path);
|
|
32372
|
+
if (addedLines != null) {
|
|
32373
|
+
const unit = addedLines === 1 ? "line" : "lines";
|
|
32374
|
+
chunks.push(`(${green(`+${addedLines} ${unit}`, style)})`);
|
|
32375
|
+
}
|
|
32376
|
+
if (!path && addedLines == null && tool.title) chunks.push(`: ${tool.title}`);
|
|
32377
|
+
return chunks.join(" ");
|
|
32378
|
+
}
|
|
32379
|
+
function formatEditToolLabel(tool, style) {
|
|
32380
|
+
const renderedName = bold$1(tool.toolName ?? "Edit", style);
|
|
32381
|
+
const path = extractWritePath(tool.input);
|
|
32382
|
+
const addedLines = extractEditAddedLineCount(tool.input);
|
|
32383
|
+
const chunks = [renderedName];
|
|
32384
|
+
if (path) chunks.push(path);
|
|
32385
|
+
if (addedLines != null) {
|
|
32386
|
+
const unit = addedLines === 1 ? "line" : "lines";
|
|
32387
|
+
chunks.push(`(${green(`+${addedLines} ${unit}`, style)})`);
|
|
32388
|
+
}
|
|
32389
|
+
if (!path && addedLines == null && tool.title) chunks.push(`: ${tool.title}`);
|
|
32390
|
+
return chunks.join(" ");
|
|
32391
|
+
}
|
|
32392
|
+
function stripOuterQuotes(token) {
|
|
32393
|
+
if (token.length < 2) return token;
|
|
32394
|
+
const first = token[0];
|
|
32395
|
+
const last = token[token.length - 1];
|
|
32396
|
+
if (first === "'" && last === "'" || first === "\"" && last === "\"") return token.slice(1, -1);
|
|
32397
|
+
return token;
|
|
32499
32398
|
}
|
|
32500
|
-
function
|
|
32501
|
-
const
|
|
32502
|
-
const
|
|
32503
|
-
|
|
32399
|
+
function isEnvAssignmentToken(token) {
|
|
32400
|
+
const normalized = stripOuterQuotes(token);
|
|
32401
|
+
const equalsAt = normalized.indexOf("=");
|
|
32402
|
+
if (equalsAt <= 0) return false;
|
|
32403
|
+
const key = normalized.slice(0, equalsAt);
|
|
32404
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
|
|
32405
|
+
}
|
|
32406
|
+
function isExecPrefixToken(token) {
|
|
32407
|
+
const normalized = stripOuterQuotes(token);
|
|
32408
|
+
return normalized === "env" || normalized === "sudo" || normalized === "builtin" || normalized === "time" || normalized === "nohup";
|
|
32409
|
+
}
|
|
32410
|
+
function parseShellEntries(line) {
|
|
32411
|
+
try {
|
|
32412
|
+
return parse(line);
|
|
32413
|
+
} catch {
|
|
32414
|
+
return;
|
|
32415
|
+
}
|
|
32416
|
+
}
|
|
32417
|
+
function colorizeExecToken(token, style) {
|
|
32418
|
+
if (!token) return token;
|
|
32419
|
+
const core = token;
|
|
32420
|
+
if (!core) return token;
|
|
32421
|
+
const lastSlash = core.lastIndexOf("/");
|
|
32422
|
+
if (lastSlash === -1 || lastSlash === core.length - 1) return bold$1(core, style);
|
|
32423
|
+
return `${core.slice(0, lastSlash + 1)}${bold$1(core.slice(lastSlash + 1), style)}`;
|
|
32424
|
+
}
|
|
32425
|
+
function isShellOperatorEntry(entry) {
|
|
32426
|
+
return typeof entry === "object" && entry != null && "op" in entry && typeof entry.op === "string";
|
|
32427
|
+
}
|
|
32428
|
+
function isShellCommentEntry(entry) {
|
|
32429
|
+
return typeof entry === "object" && entry != null && "comment" in entry && typeof entry.comment === "string";
|
|
32430
|
+
}
|
|
32431
|
+
function renderShellToken(rawToken, styledToken) {
|
|
32432
|
+
if (rawToken.length === 0) return `""`;
|
|
32433
|
+
if (!/\s/.test(rawToken)) return styledToken;
|
|
32434
|
+
return `"${styledToken.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"")}"`;
|
|
32435
|
+
}
|
|
32436
|
+
function findCommandSubstitutionEnd(text, openAt) {
|
|
32437
|
+
let depth = 1;
|
|
32438
|
+
let i = openAt;
|
|
32439
|
+
let escaped = false;
|
|
32440
|
+
while (i < text.length) {
|
|
32441
|
+
const ch = text[i] ?? "";
|
|
32442
|
+
if (escaped) {
|
|
32443
|
+
escaped = false;
|
|
32444
|
+
i += 1;
|
|
32445
|
+
continue;
|
|
32446
|
+
}
|
|
32447
|
+
if (ch === "\\") {
|
|
32448
|
+
escaped = true;
|
|
32449
|
+
i += 1;
|
|
32450
|
+
continue;
|
|
32451
|
+
}
|
|
32452
|
+
if (ch === "$" && text[i + 1] === "(") {
|
|
32453
|
+
depth += 1;
|
|
32454
|
+
i += 2;
|
|
32455
|
+
continue;
|
|
32456
|
+
}
|
|
32457
|
+
if (ch === ")") {
|
|
32458
|
+
depth -= 1;
|
|
32459
|
+
if (depth === 0) return i;
|
|
32460
|
+
}
|
|
32461
|
+
i += 1;
|
|
32462
|
+
}
|
|
32463
|
+
return -1;
|
|
32464
|
+
}
|
|
32465
|
+
function colorizeCommandSubstitutions(token, style) {
|
|
32466
|
+
if (!token.includes("$(")) return token;
|
|
32467
|
+
let out = "";
|
|
32468
|
+
let i = 0;
|
|
32469
|
+
let cursor = 0;
|
|
32470
|
+
while (i < token.length) {
|
|
32471
|
+
if (token[i] === "$" && token[i + 1] === "(") {
|
|
32472
|
+
out += token.slice(cursor, i);
|
|
32473
|
+
const closeAt = findCommandSubstitutionEnd(token, i + 2);
|
|
32474
|
+
if (closeAt < 0) {
|
|
32475
|
+
out += token.slice(i);
|
|
32476
|
+
return out;
|
|
32477
|
+
}
|
|
32478
|
+
const innerColorized = colorizeCommandLine(token.slice(i + 2, closeAt), style);
|
|
32479
|
+
out += `$(${innerColorized})`;
|
|
32480
|
+
i = closeAt + 1;
|
|
32481
|
+
cursor = i;
|
|
32482
|
+
continue;
|
|
32483
|
+
}
|
|
32484
|
+
i += 1;
|
|
32485
|
+
}
|
|
32486
|
+
out += token.slice(cursor);
|
|
32487
|
+
return out;
|
|
32488
|
+
}
|
|
32489
|
+
const SEGMENT_BREAK_OPERATORS = new Set([
|
|
32490
|
+
"|",
|
|
32491
|
+
"|&",
|
|
32492
|
+
"||",
|
|
32493
|
+
"&&",
|
|
32494
|
+
";",
|
|
32495
|
+
"&"
|
|
32496
|
+
]);
|
|
32497
|
+
const GRAY_CONNECTORS = new Set([
|
|
32498
|
+
"|",
|
|
32499
|
+
"|&",
|
|
32500
|
+
"||",
|
|
32501
|
+
"&&"
|
|
32502
|
+
]);
|
|
32503
|
+
function colorizeCommandLine(line, style) {
|
|
32504
|
+
if (!line) return line;
|
|
32505
|
+
const entries = parseShellEntries(line);
|
|
32506
|
+
if (!entries || entries.length === 0) return line;
|
|
32507
|
+
const rendered = [];
|
|
32508
|
+
let shouldHighlightExec = true;
|
|
32509
|
+
for (const entry of entries) {
|
|
32510
|
+
if (typeof entry === "string") {
|
|
32511
|
+
const token = entry;
|
|
32512
|
+
const isExecToken = shouldHighlightExec && !isEnvAssignmentToken(token) && !isExecPrefixToken(token);
|
|
32513
|
+
let styledToken = token;
|
|
32514
|
+
if (isExecToken) {
|
|
32515
|
+
styledToken = colorizeExecToken(token, style);
|
|
32516
|
+
shouldHighlightExec = false;
|
|
32517
|
+
} else styledToken = colorizeCommandSubstitutions(token, style);
|
|
32518
|
+
rendered.push(renderShellToken(token, styledToken));
|
|
32519
|
+
continue;
|
|
32520
|
+
}
|
|
32521
|
+
if (isShellCommentEntry(entry)) {
|
|
32522
|
+
rendered.push(`#${entry.comment}`);
|
|
32523
|
+
break;
|
|
32524
|
+
}
|
|
32525
|
+
if (!isShellOperatorEntry(entry)) continue;
|
|
32526
|
+
rendered.push(GRAY_CONNECTORS.has(entry.op) ? gray(entry.op, style) : entry.op);
|
|
32527
|
+
if (SEGMENT_BREAK_OPERATORS.has(entry.op)) shouldHighlightExec = true;
|
|
32528
|
+
}
|
|
32529
|
+
return rendered.join(" ");
|
|
32530
|
+
}
|
|
32531
|
+
function colorizeCommandProgram(display, style) {
|
|
32532
|
+
return display.replaceAll("\r\n", "\n").split("\n").map((line) => colorizeCommandLine(line, style)).join("\n");
|
|
32504
32533
|
}
|
|
32505
32534
|
function formatToolLabel(tool, style) {
|
|
32506
32535
|
const name = tool.toolName ?? "<tool>";
|
|
32507
|
-
if (
|
|
32536
|
+
if (isWriteTool(tool.toolName)) return formatWriteToolLabel(tool, style);
|
|
32537
|
+
if (isEditTool(tool.toolName)) return formatEditToolLabel(tool, style);
|
|
32538
|
+
if (isCommandLikeTool(tool.toolName)) {
|
|
32508
32539
|
const rawCommand = getCommandExecutionRawCommand(tool);
|
|
32509
32540
|
const exploredLines = rawCommand ? getExploredCommandLines(rawCommand) : void 0;
|
|
32510
32541
|
if (exploredLines && exploredLines.length > 1) return cyan(exploredLines[0] ?? "Explored", style);
|
|
32511
|
-
|
|
32512
|
-
return `${bold("$", style)} ${colorizeCommandProgram(display, style)}`;
|
|
32542
|
+
return colorizeCommandProgram(getCommandExecutionDisplayCommand(tool) ?? "(unknown command)", style);
|
|
32513
32543
|
}
|
|
32514
|
-
const renderedName = bold(name, style);
|
|
32544
|
+
const renderedName = bold$1(name, style);
|
|
32515
32545
|
if (!tool.title) return renderedName;
|
|
32516
32546
|
return `${renderedName}: ${tool.title}`;
|
|
32517
32547
|
}
|
|
@@ -32542,12 +32572,37 @@ function formatToolStatusIcon(status, style) {
|
|
|
32542
32572
|
}
|
|
32543
32573
|
}
|
|
32544
32574
|
function getExploredSubCommandLines(tool) {
|
|
32545
|
-
if (tool.toolName
|
|
32546
|
-
|
|
32547
|
-
|
|
32548
|
-
|
|
32549
|
-
|
|
32550
|
-
|
|
32575
|
+
if (isCommandLikeTool(tool.toolName)) {
|
|
32576
|
+
const rawCommand = getCommandExecutionRawCommand(tool);
|
|
32577
|
+
if (!rawCommand) return void 0;
|
|
32578
|
+
const exploredLines = getExploredCommandLines(rawCommand);
|
|
32579
|
+
if (!exploredLines || exploredLines.length <= 1) return void 0;
|
|
32580
|
+
return exploredLines.slice(1);
|
|
32581
|
+
}
|
|
32582
|
+
if (!isClaudeExplorationTool(tool.toolName)) return void 0;
|
|
32583
|
+
const input = toRecord(tool.input) ?? {};
|
|
32584
|
+
const toolName = (tool.toolName ?? "").toLowerCase();
|
|
32585
|
+
if (toolName === "read") {
|
|
32586
|
+
const path = toStringOrUndefined(input.file_path) ?? toStringOrUndefined(input.path) ?? toStringOrUndefined(input.filePath);
|
|
32587
|
+
if (!path) return ["Read"];
|
|
32588
|
+
return [`Read ${path}`];
|
|
32589
|
+
}
|
|
32590
|
+
if (toolName === "glob") {
|
|
32591
|
+
const pattern = toStringOrUndefined(input.pattern);
|
|
32592
|
+
const path = toStringOrUndefined(input.path);
|
|
32593
|
+
if (path && pattern) return [`List ${path} (glob: ${pattern})`];
|
|
32594
|
+
if (path) return [`List ${path}`];
|
|
32595
|
+
if (pattern) return [`List (glob: ${pattern})`];
|
|
32596
|
+
return ["List"];
|
|
32597
|
+
}
|
|
32598
|
+
if (toolName === "grep") {
|
|
32599
|
+
const pattern = toStringOrUndefined(input.pattern);
|
|
32600
|
+
const path = toStringOrUndefined(input.path);
|
|
32601
|
+
if (pattern && path) return [`Search ${pattern} in ${path}`];
|
|
32602
|
+
if (pattern) return [`Search ${pattern}`];
|
|
32603
|
+
if (path) return [`Search in ${path}`];
|
|
32604
|
+
return ["Search"];
|
|
32605
|
+
}
|
|
32551
32606
|
}
|
|
32552
32607
|
function formatExploredSubCommandLine(line, style) {
|
|
32553
32608
|
if (line.startsWith("Search ")) {
|
|
@@ -32556,7 +32611,7 @@ function formatExploredSubCommandLine(line, style) {
|
|
|
32556
32611
|
if (at !== -1) {
|
|
32557
32612
|
const terms = payload.slice(0, at);
|
|
32558
32613
|
const file = payload.slice(at + 4);
|
|
32559
|
-
return `${cyan("Search", style)} ${terms} ${dimGray("in", style)} ${file}`;
|
|
32614
|
+
return `${cyan("Search", style)} ${terms} ${dimGray$1("in", style)} ${file}`;
|
|
32560
32615
|
}
|
|
32561
32616
|
return `${cyan("Search", style)} ${payload}`;
|
|
32562
32617
|
}
|
|
@@ -32568,7 +32623,7 @@ function formatExploredSubCommandLine(line, style) {
|
|
|
32568
32623
|
function toDisplayLines(text) {
|
|
32569
32624
|
return text.replaceAll("\r\n", "\n").split("\n");
|
|
32570
32625
|
}
|
|
32571
|
-
function wrapRawLineToWidth(line, width) {
|
|
32626
|
+
function wrapRawLineToWidth$1(line, width) {
|
|
32572
32627
|
if (width <= 0) return [line];
|
|
32573
32628
|
if (line.length === 0) return [""];
|
|
32574
32629
|
const out = [];
|
|
@@ -32595,21 +32650,33 @@ function trimCommandOutputTopBottom(lines) {
|
|
|
32595
32650
|
lines[lines.length - 1]
|
|
32596
32651
|
];
|
|
32597
32652
|
}
|
|
32653
|
+
function getCommandLikeOutputText(output) {
|
|
32654
|
+
const value = output;
|
|
32655
|
+
const aggregated = typeof value?.aggregated_output === "string" ? value.aggregated_output : "";
|
|
32656
|
+
if (aggregated) return aggregated;
|
|
32657
|
+
const nestedToolResult = value?.tool_use_result;
|
|
32658
|
+
const stdout = typeof nestedToolResult?.stdout === "string" ? nestedToolResult.stdout : typeof value?.stdout === "string" ? value.stdout : "";
|
|
32659
|
+
const stderr = typeof nestedToolResult?.stderr === "string" ? nestedToolResult.stderr : typeof value?.stderr === "string" ? value.stderr : "";
|
|
32660
|
+
if (stdout || stderr) {
|
|
32661
|
+
if (stdout && stderr) return `${stdout}${stdout.endsWith("\n") ? "" : "\n"}${stderr}`;
|
|
32662
|
+
return stdout || stderr;
|
|
32663
|
+
}
|
|
32664
|
+
if (typeof value?.content === "string") return value.content;
|
|
32665
|
+
}
|
|
32598
32666
|
function formatToolResultPreviewLines(tool, options) {
|
|
32599
32667
|
if (tool.status === "in_progress") return [];
|
|
32600
32668
|
if (options.maxLines <= 0) return [];
|
|
32601
|
-
if (tool.toolName
|
|
32669
|
+
if (isCommandLikeTool(tool.toolName)) {
|
|
32602
32670
|
const rawCommand = getCommandExecutionRawCommand(tool);
|
|
32603
32671
|
if (rawCommand && isExploredCommandExecution(rawCommand)) return [];
|
|
32604
32672
|
}
|
|
32605
32673
|
if (tool.status === "failed") {
|
|
32606
32674
|
const lines = toDisplayLines(tool.errorText ?? "(no error text)");
|
|
32607
|
-
return trimLinesWithEllipsis(tool.toolName
|
|
32675
|
+
return trimLinesWithEllipsis(isCommandLikeTool(tool.toolName) ? trimCommandOutputTopBottom(lines) : lines, options.maxLines);
|
|
32608
32676
|
}
|
|
32609
32677
|
if (tool.output == null) return ["(none)"];
|
|
32610
|
-
if (tool.toolName
|
|
32611
|
-
const
|
|
32612
|
-
const allLines = toDisplayLines((typeof output?.aggregated_output === "string" ? output.aggregated_output : "").trimEnd());
|
|
32678
|
+
if (isCommandLikeTool(tool.toolName)) {
|
|
32679
|
+
const allLines = toDisplayLines((getCommandLikeOutputText(tool.output) ?? "").trimEnd());
|
|
32613
32680
|
if (!allLines.some((line) => line.length > 0)) return ["(none)"];
|
|
32614
32681
|
return trimLinesWithEllipsis(trimCommandOutputTopBottom(allLines), options.maxLines);
|
|
32615
32682
|
}
|
|
@@ -32621,7 +32688,124 @@ function formatToolResultPreviewLines(tool, options) {
|
|
|
32621
32688
|
breakLength: Math.max(20, options.widthHint)
|
|
32622
32689
|
})), options.maxLines);
|
|
32623
32690
|
}
|
|
32691
|
+
function formatWatchLogLines(options) {
|
|
32692
|
+
const blocks = [];
|
|
32693
|
+
const reasoningWrapWidth = Math.max(1, options.widthHint);
|
|
32694
|
+
const messageWrapWidth = Math.max(1, options.widthHint);
|
|
32695
|
+
const toolById = new Map(options.snapshot.toolActions.map((tool) => [tool.toolCallId, tool]));
|
|
32696
|
+
function pushBlock(order, lines) {
|
|
32697
|
+
if (lines.length === 0) return;
|
|
32698
|
+
blocks.push({
|
|
32699
|
+
order: order ?? Number.MAX_SAFE_INTEGER,
|
|
32700
|
+
lines
|
|
32701
|
+
});
|
|
32702
|
+
}
|
|
32703
|
+
for (let timelineIndex = 0; timelineIndex < options.snapshot.timeline.length; timelineIndex++) {
|
|
32704
|
+
const entry = options.snapshot.timeline[timelineIndex];
|
|
32705
|
+
if (entry.kind === "reasoning") {
|
|
32706
|
+
const reasoningBlock = [];
|
|
32707
|
+
const hasTrailingLineFeed = entry.text.endsWith("\n");
|
|
32708
|
+
const rawReasoningLines = toDisplayLines(entry.text);
|
|
32709
|
+
for (const rawLine of rawReasoningLines) wrapRawLineToWidth$1(rawLine, reasoningWrapWidth).forEach((chunk) => reasoningBlock.push(gray(chunk, options.style)));
|
|
32710
|
+
if (!hasTrailingLineFeed) reasoningBlock.push("");
|
|
32711
|
+
pushBlock(entry.order, reasoningBlock);
|
|
32712
|
+
continue;
|
|
32713
|
+
}
|
|
32714
|
+
if (entry.kind === "message") {
|
|
32715
|
+
const messageBlock = [];
|
|
32716
|
+
const rawMessageLines = toDisplayLines(entry.text);
|
|
32717
|
+
for (const rawLine of rawMessageLines) wrapRawLineToWidth$1(rawLine, messageWrapWidth).forEach((chunk) => messageBlock.push(chunk));
|
|
32718
|
+
pushBlock(entry.order, messageBlock);
|
|
32719
|
+
continue;
|
|
32720
|
+
}
|
|
32721
|
+
if (entry.kind === "warning") {
|
|
32722
|
+
pushBlock(entry.order, [kv("warning", yellow(entry.message, options.style), options.style)]);
|
|
32723
|
+
continue;
|
|
32724
|
+
}
|
|
32725
|
+
const tool = toolById.get(entry.toolCallId);
|
|
32726
|
+
if (!tool) continue;
|
|
32727
|
+
const exploredSubLines = getExploredSubCommandLines(tool);
|
|
32728
|
+
if (exploredSubLines != null) {
|
|
32729
|
+
const groupedTools = [tool];
|
|
32730
|
+
const groupedSubLines = [...exploredSubLines];
|
|
32731
|
+
let lookahead = timelineIndex + 1;
|
|
32732
|
+
while (lookahead < options.snapshot.timeline.length) {
|
|
32733
|
+
const next = options.snapshot.timeline[lookahead];
|
|
32734
|
+
if (next.kind !== "tool") break;
|
|
32735
|
+
const nextTool = toolById.get(next.toolCallId);
|
|
32736
|
+
if (!nextTool) break;
|
|
32737
|
+
const nextSubLines = getExploredSubCommandLines(nextTool);
|
|
32738
|
+
if (nextSubLines == null) break;
|
|
32739
|
+
groupedTools.push(nextTool);
|
|
32740
|
+
groupedSubLines.push(...nextSubLines);
|
|
32741
|
+
lookahead += 1;
|
|
32742
|
+
}
|
|
32743
|
+
const groupedBlock = [` ${[
|
|
32744
|
+
formatToolStatusIcon(combineToolStatuses(groupedTools.map((groupedTool) => groupedTool.status)), options.style),
|
|
32745
|
+
cyan("Explored", options.style),
|
|
32746
|
+
groupedTools.length > 1 ? gray(`x${groupedTools.length}`, options.style) : void 0
|
|
32747
|
+
].filter(Boolean).join(" ")}`];
|
|
32748
|
+
groupedSubLines.forEach((subLine, subIndex) => groupedBlock.push(subIndex === 0 ? ` ${dimGray$1("└", options.style)} ${formatExploredSubCommandLine(subLine, options.style)}` : ` ${formatExploredSubCommandLine(subLine, options.style)}`));
|
|
32749
|
+
pushBlock(entry.order, groupedBlock);
|
|
32750
|
+
timelineIndex = lookahead - 1;
|
|
32751
|
+
continue;
|
|
32752
|
+
}
|
|
32753
|
+
const toolBlock = [];
|
|
32754
|
+
const summaryLines = toDisplayLines(formatToolSummaryLine(tool, options.style));
|
|
32755
|
+
const summaryContinuationIndent = isCommandLikeTool(tool.toolName) ? " " : " ";
|
|
32756
|
+
summaryLines.forEach((line, index) => toolBlock.push(index === 0 ? ` ${line}` : `${summaryContinuationIndent}${line}`));
|
|
32757
|
+
if (isCommandLikeTool(tool.toolName)) formatToolResultPreviewLines(tool, {
|
|
32758
|
+
maxLines: Number.POSITIVE_INFINITY,
|
|
32759
|
+
widthHint: Math.max(20, options.widthHint - 10)
|
|
32760
|
+
}).forEach((line, index) => toolBlock.push(index === 0 ? ` ${dimGray$1("└", options.style)} ${dimGray$1(line, options.style)}` : ` ${dimGray$1(line, options.style)}`));
|
|
32761
|
+
pushBlock(entry.order, toolBlock);
|
|
32762
|
+
}
|
|
32763
|
+
if (options.lastError) pushBlock(void 0, [kv("error", red(options.lastError, options.style), options.style)]);
|
|
32764
|
+
blocks.sort((a, b) => a.order - b.order);
|
|
32765
|
+
const lines = [];
|
|
32766
|
+
for (const block of blocks) {
|
|
32767
|
+
if (lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
|
|
32768
|
+
lines.push(...block.lines);
|
|
32769
|
+
}
|
|
32770
|
+
if (lines.length === 0) lines.push(gray("(waiting for formatted stream output)", options.style));
|
|
32771
|
+
return lines;
|
|
32772
|
+
}
|
|
32773
|
+
|
|
32774
|
+
//#endregion
|
|
32775
|
+
//#region src/cli/commands/watch/source.ts
|
|
32776
|
+
function toStreamSourceFromExecuteAgent(executeAgent) {
|
|
32777
|
+
if (!executeAgent) return void 0;
|
|
32778
|
+
const normalized = executeAgent.toLowerCase();
|
|
32779
|
+
if (normalized.includes("claude")) return "claude-code";
|
|
32780
|
+
if (normalized.includes("codex")) return "codex";
|
|
32781
|
+
}
|
|
32782
|
+
function detectStreamSourceFromRawPayload(payload) {
|
|
32783
|
+
if (payload.includes("\"type\":\"thread.") || payload.includes("\"type\":\"turn.") || payload.includes("\"type\":\"item.")) return "codex";
|
|
32784
|
+
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";
|
|
32785
|
+
}
|
|
32786
|
+
function parseAgentStreamSourceOption(value) {
|
|
32787
|
+
const normalized = value.trim().toLowerCase();
|
|
32788
|
+
if (normalized === "codex") return "codex";
|
|
32789
|
+
if (normalized === "claude-code" || normalized === "claude") return "claude-code";
|
|
32790
|
+
throw new Error(`Invalid stream source: ${value}. Allowed: codex, claude-code`);
|
|
32791
|
+
}
|
|
32792
|
+
|
|
32793
|
+
//#endregion
|
|
32794
|
+
//#region src/cli/commands/watch/stream-url.ts
|
|
32795
|
+
const PANTHEON_BASE_URL = "https://pantheon-ai.tidb.ai";
|
|
32796
|
+
function makeOpaqueStreamUrl(streamId) {
|
|
32797
|
+
return `${PANTHEON_BASE_URL}/ai_stream_proxy/v2/streams/${encodeURIComponent(streamId)}/stream?format=opaque-stream-json`;
|
|
32798
|
+
}
|
|
32799
|
+
|
|
32800
|
+
//#endregion
|
|
32801
|
+
//#region src/cli/commands/watch/tui.ts
|
|
32802
|
+
const ANSI_RESET = "\x1B[0m";
|
|
32624
32803
|
const ANSI_SGR_REGEX = /\u001b\[[0-9;]*m/g;
|
|
32804
|
+
function useAnsiStyles() {
|
|
32805
|
+
if (!process$1.stdout.isTTY) return false;
|
|
32806
|
+
if (process$1.env.NO_COLOR != null) return false;
|
|
32807
|
+
return true;
|
|
32808
|
+
}
|
|
32625
32809
|
function visibleLength(value) {
|
|
32626
32810
|
return value.replaceAll(ANSI_SGR_REGEX, "").length;
|
|
32627
32811
|
}
|
|
@@ -32649,7 +32833,142 @@ function clip(value, maxVisible) {
|
|
|
32649
32833
|
if (visibleLength(value) <= maxVisible) return value;
|
|
32650
32834
|
if (maxVisible === 1) return "…";
|
|
32651
32835
|
const sliced = sliceSgrByVisibleWidth(value, maxVisible - 1);
|
|
32652
|
-
return `${sliced}…${sliced.includes("\x1B[") ?
|
|
32836
|
+
return `${sliced}…${sliced.includes("\x1B[") ? ANSI_RESET : ""}`;
|
|
32837
|
+
}
|
|
32838
|
+
|
|
32839
|
+
//#endregion
|
|
32840
|
+
//#region src/cli/commands/watch.ts
|
|
32841
|
+
function parseListWidth(value) {
|
|
32842
|
+
const width = Number(value);
|
|
32843
|
+
if (!Number.isInteger(width) || width <= 0) throw new InvalidArgumentError("list-width requires a positive integer, e.g. 32");
|
|
32844
|
+
return width;
|
|
32845
|
+
}
|
|
32846
|
+
function ensureEnvOrExit(keys) {
|
|
32847
|
+
const missing = keys.filter((key) => !process.env[key]);
|
|
32848
|
+
if (missing.length === 0) return;
|
|
32849
|
+
for (const key of missing) console.error(`${key} environment variable is not set.`);
|
|
32850
|
+
process.exit(1);
|
|
32851
|
+
}
|
|
32852
|
+
async function getAgentExecuteAgentMap(db, targets) {
|
|
32853
|
+
const agents = Array.from(new Set(targets.map((t) => t.agent)));
|
|
32854
|
+
if (agents.length === 0) return /* @__PURE__ */ new Map();
|
|
32855
|
+
const configs = await db.selectFrom("agent_project_config").select([
|
|
32856
|
+
"agent",
|
|
32857
|
+
"project_id",
|
|
32858
|
+
"execute_agent"
|
|
32859
|
+
]).where("agent", "in", agents).execute();
|
|
32860
|
+
const map = /* @__PURE__ */ new Map();
|
|
32861
|
+
for (const row of configs) map.set(`${row.agent}|${row.project_id}`, row.execute_agent);
|
|
32862
|
+
return map;
|
|
32863
|
+
}
|
|
32864
|
+
async function loadTasksByIds(db, ids) {
|
|
32865
|
+
if (ids.length === 0) return [];
|
|
32866
|
+
const rows = await db.selectFrom("task").selectAll().where("id", "in", ids).execute();
|
|
32867
|
+
const out = [];
|
|
32868
|
+
for (const row of rows) {
|
|
32869
|
+
const parsed = taskItemSchema.safeParse(row);
|
|
32870
|
+
if (!parsed.success) {
|
|
32871
|
+
console.error(`Failed to parse task row id=${row.id} agent=${row.agent} status=${row.status}: ${parsed.error.message}`);
|
|
32872
|
+
continue;
|
|
32873
|
+
}
|
|
32874
|
+
out.push({
|
|
32875
|
+
agent: row.agent,
|
|
32876
|
+
task: parsed.data
|
|
32877
|
+
});
|
|
32878
|
+
}
|
|
32879
|
+
return out;
|
|
32880
|
+
}
|
|
32881
|
+
async function loadTasksForAgent(db, agent) {
|
|
32882
|
+
const rows = await db.selectFrom("task").selectAll().where("agent", "=", agent).execute();
|
|
32883
|
+
const out = [];
|
|
32884
|
+
for (const row of rows) {
|
|
32885
|
+
const parsed = taskItemSchema.safeParse(row);
|
|
32886
|
+
if (!parsed.success) continue;
|
|
32887
|
+
out.push(parsed.data);
|
|
32888
|
+
}
|
|
32889
|
+
return out;
|
|
32890
|
+
}
|
|
32891
|
+
async function loadAllTasks(db, limit) {
|
|
32892
|
+
const rows = await db.selectFrom("task").selectAll().orderBy("queued_at", "desc").limit(limit).execute();
|
|
32893
|
+
const out = [];
|
|
32894
|
+
for (const row of rows) {
|
|
32895
|
+
const parsed = taskItemSchema.safeParse(row);
|
|
32896
|
+
if (!parsed.success) continue;
|
|
32897
|
+
out.push({
|
|
32898
|
+
agent: row.agent,
|
|
32899
|
+
task: parsed.data
|
|
32900
|
+
});
|
|
32901
|
+
}
|
|
32902
|
+
return out;
|
|
32903
|
+
}
|
|
32904
|
+
async function resolveWatchTargets(options) {
|
|
32905
|
+
const warnings = [];
|
|
32906
|
+
let selected = [];
|
|
32907
|
+
if (options.taskIds.length > 0) {
|
|
32908
|
+
const uniqueTaskIds = Array.from(new Set(options.taskIds));
|
|
32909
|
+
const found = await loadTasksByIds(options.db, uniqueTaskIds);
|
|
32910
|
+
const foundIds = new Set(found.map((t) => t.task.id));
|
|
32911
|
+
const missing = uniqueTaskIds.filter((id) => !foundIds.has(id));
|
|
32912
|
+
if (missing.length > 0) warnings.push(`Requested task IDs not found: ${missing.join(", ")}`);
|
|
32913
|
+
const byId = new Map(found.map((t) => [t.task.id, t]));
|
|
32914
|
+
selected = uniqueTaskIds.map((id) => byId.get(id)).filter(Boolean);
|
|
32915
|
+
if (selected.length === 0) warnings.push("No requested tasks found; falling back to default selection.");
|
|
32916
|
+
} else if (options.agentNames.length > 0) {
|
|
32917
|
+
const uniqueAgents = Array.from(new Set(options.agentNames));
|
|
32918
|
+
if (uniqueAgents.length === 1) {
|
|
32919
|
+
selected = selectSingleAgentWatchTasks(await loadTasksForAgent(options.db, uniqueAgents[0]), { finishedLimit: 3 }).map((task) => ({
|
|
32920
|
+
agent: uniqueAgents[0],
|
|
32921
|
+
task
|
|
32922
|
+
}));
|
|
32923
|
+
if (selected.length === 0) warnings.push(`No tasks found for agent ${uniqueAgents[0]}; falling back to default selection.`);
|
|
32924
|
+
} else {
|
|
32925
|
+
selected = selectMultiAgentWatchTasks(await Promise.all(uniqueAgents.map(async (agent) => {
|
|
32926
|
+
return (await loadTasksForAgent(options.db, agent)).map((task) => ({
|
|
32927
|
+
agent,
|
|
32928
|
+
task
|
|
32929
|
+
}));
|
|
32930
|
+
})).then((groups) => groups.flat()), uniqueAgents);
|
|
32931
|
+
const foundAgents = new Set(selected.map((t) => t.agent));
|
|
32932
|
+
const missing = uniqueAgents.filter((agent) => !foundAgents.has(agent));
|
|
32933
|
+
if (missing.length > 0) warnings.push(`No tasks found for agent(s): ${missing.join(", ")}`);
|
|
32934
|
+
if (selected.length === 0) warnings.push("No requested agent tasks found; falling back to default selection.");
|
|
32935
|
+
}
|
|
32936
|
+
} else warnings.push("No targets specified; selecting up to 3 agents automatically.");
|
|
32937
|
+
if (selected.length === 0) selected = selectFallbackWatchTasks(await loadAllTasks(options.db, 500), { agentLimit: 3 });
|
|
32938
|
+
const executeAgentMap = await getAgentExecuteAgentMap(options.db, selected);
|
|
32939
|
+
return {
|
|
32940
|
+
targets: selected.map((entry) => ({
|
|
32941
|
+
...entry,
|
|
32942
|
+
executeAgent: executeAgentMap.get(`${entry.agent}|${entry.task.project_id}`)
|
|
32943
|
+
})),
|
|
32944
|
+
warnings
|
|
32945
|
+
};
|
|
32946
|
+
}
|
|
32947
|
+
const ANSI = {
|
|
32948
|
+
reset: "\x1B[0m",
|
|
32949
|
+
bold: "\x1B[1m",
|
|
32950
|
+
dim: "\x1B[2m",
|
|
32951
|
+
red: "\x1B[31m",
|
|
32952
|
+
green: "\x1B[32m",
|
|
32953
|
+
yellow: "\x1B[33m",
|
|
32954
|
+
cyan: "\x1B[36m",
|
|
32955
|
+
gray: "\x1B[90m"
|
|
32956
|
+
};
|
|
32957
|
+
function sgrWrap(text, code, enabled) {
|
|
32958
|
+
return enabled ? `${code}${text}${ANSI.reset}` : text;
|
|
32959
|
+
}
|
|
32960
|
+
function bold(text, enabled) {
|
|
32961
|
+
return sgrWrap(text, ANSI.bold, enabled);
|
|
32962
|
+
}
|
|
32963
|
+
function dimGray(text, enabled) {
|
|
32964
|
+
return sgrWrap(text, `${ANSI.dim}${ANSI.gray}`, enabled);
|
|
32965
|
+
}
|
|
32966
|
+
function wrapRawLineToWidth(line, width) {
|
|
32967
|
+
if (width <= 0) return [line];
|
|
32968
|
+
if (line.length === 0) return [""];
|
|
32969
|
+
const out = [];
|
|
32970
|
+
for (let i = 0; i < line.length; i += width) out.push(line.slice(i, i + width));
|
|
32971
|
+
return out;
|
|
32653
32972
|
}
|
|
32654
32973
|
const TODO_PREVIEW_MAX_ITEMS = 3;
|
|
32655
32974
|
const TODO_PREVIEW_MAX_PENDING = 2;
|
|
@@ -32751,7 +33070,7 @@ function createWatchCommand(version) {
|
|
|
32751
33070
|
rt.streamDone = false;
|
|
32752
33071
|
const preferred = toStreamSourceFromExecuteAgent(rt.target.executeAgent);
|
|
32753
33072
|
rt.source = preferred;
|
|
32754
|
-
const url =
|
|
33073
|
+
const url = makeOpaqueStreamUrl(streamId);
|
|
32755
33074
|
(async () => {
|
|
32756
33075
|
try {
|
|
32757
33076
|
const res = await fetch(url, {
|
|
@@ -32914,86 +33233,12 @@ function createWatchCommand(version) {
|
|
|
32914
33233
|
return runtime[selectedIndex];
|
|
32915
33234
|
}
|
|
32916
33235
|
function getFormattedLogLines(rt, options) {
|
|
32917
|
-
|
|
32918
|
-
|
|
32919
|
-
|
|
32920
|
-
|
|
32921
|
-
|
|
32922
|
-
|
|
32923
|
-
if (lines.length === 0) return;
|
|
32924
|
-
blocks.push({
|
|
32925
|
-
order: order ?? Number.MAX_SAFE_INTEGER,
|
|
32926
|
-
lines
|
|
32927
|
-
});
|
|
32928
|
-
}
|
|
32929
|
-
for (let timelineIndex = 0; timelineIndex < step.timeline.length; timelineIndex++) {
|
|
32930
|
-
const entry = step.timeline[timelineIndex];
|
|
32931
|
-
if (entry.kind === "reasoning") {
|
|
32932
|
-
const reasoningBlock = [];
|
|
32933
|
-
const hasTrailingLineFeed = entry.text.endsWith("\n");
|
|
32934
|
-
const rawReasoningLines = toDisplayLines(entry.text);
|
|
32935
|
-
for (const rawLine of rawReasoningLines) wrapRawLineToWidth(rawLine, reasoningWrapWidth).forEach((chunk) => reasoningBlock.push(gray(chunk, options.style)));
|
|
32936
|
-
if (!hasTrailingLineFeed) reasoningBlock.push("");
|
|
32937
|
-
pushBlock(entry.order, reasoningBlock);
|
|
32938
|
-
continue;
|
|
32939
|
-
}
|
|
32940
|
-
if (entry.kind === "message") {
|
|
32941
|
-
const messageBlock = [];
|
|
32942
|
-
const rawMessageLines = toDisplayLines(entry.text);
|
|
32943
|
-
for (const rawLine of rawMessageLines) wrapRawLineToWidth(rawLine, messageWrapWidth).forEach((chunk) => messageBlock.push(chunk));
|
|
32944
|
-
pushBlock(entry.order, messageBlock);
|
|
32945
|
-
continue;
|
|
32946
|
-
}
|
|
32947
|
-
if (entry.kind === "warning") {
|
|
32948
|
-
pushBlock(entry.order, [kv("warning", yellow(entry.message, options.style), options.style)]);
|
|
32949
|
-
continue;
|
|
32950
|
-
}
|
|
32951
|
-
const tool = toolById.get(entry.toolCallId);
|
|
32952
|
-
if (!tool) continue;
|
|
32953
|
-
const exploredSubLines = getExploredSubCommandLines(tool);
|
|
32954
|
-
if (exploredSubLines != null) {
|
|
32955
|
-
const groupedTools = [tool];
|
|
32956
|
-
const groupedSubLines = [...exploredSubLines];
|
|
32957
|
-
let lookahead = timelineIndex + 1;
|
|
32958
|
-
while (lookahead < step.timeline.length) {
|
|
32959
|
-
const next = step.timeline[lookahead];
|
|
32960
|
-
if (next.kind !== "tool") break;
|
|
32961
|
-
const nextTool = toolById.get(next.toolCallId);
|
|
32962
|
-
if (!nextTool) break;
|
|
32963
|
-
const nextSubLines = getExploredSubCommandLines(nextTool);
|
|
32964
|
-
if (nextSubLines == null) break;
|
|
32965
|
-
groupedTools.push(nextTool);
|
|
32966
|
-
groupedSubLines.push(...nextSubLines);
|
|
32967
|
-
lookahead += 1;
|
|
32968
|
-
}
|
|
32969
|
-
const groupedBlock = [` ${[
|
|
32970
|
-
formatToolStatusIcon(combineToolStatuses(groupedTools.map((groupedTool) => groupedTool.status)), options.style),
|
|
32971
|
-
cyan("Explored", options.style),
|
|
32972
|
-
groupedTools.length > 1 ? gray(`x${groupedTools.length}`, options.style) : void 0
|
|
32973
|
-
].filter(Boolean).join(" ")}`];
|
|
32974
|
-
groupedSubLines.forEach((subLine, subIndex) => groupedBlock.push(subIndex === 0 ? ` ${dimGray("└", options.style)} ${formatExploredSubCommandLine(subLine, options.style)}` : ` ${formatExploredSubCommandLine(subLine, options.style)}`));
|
|
32975
|
-
pushBlock(entry.order, groupedBlock);
|
|
32976
|
-
timelineIndex = lookahead - 1;
|
|
32977
|
-
continue;
|
|
32978
|
-
}
|
|
32979
|
-
const toolBlock = [];
|
|
32980
|
-
toDisplayLines(formatToolSummaryLine(tool, options.style)).forEach((line, index) => toolBlock.push(index === 0 ? ` ${line}` : ` ${line}`));
|
|
32981
|
-
if (tool.toolName === "command_execution") formatToolResultPreviewLines(tool, {
|
|
32982
|
-
maxLines: Number.MAX_SAFE_INTEGER,
|
|
32983
|
-
widthHint: Math.max(20, options.widthHint - 10),
|
|
32984
|
-
style: options.style
|
|
32985
|
-
}).forEach((line, index) => toolBlock.push(index === 0 ? ` ${dimGray("└", options.style)} ${dimGray(line, options.style)}` : ` ${dimGray(line, options.style)}`));
|
|
32986
|
-
pushBlock(entry.order, toolBlock);
|
|
32987
|
-
}
|
|
32988
|
-
if (rt.lastError) pushBlock(void 0, [kv("error", red(rt.lastError, options.style), options.style)]);
|
|
32989
|
-
blocks.sort((a, b) => a.order - b.order);
|
|
32990
|
-
const lines = [];
|
|
32991
|
-
for (const block of blocks) {
|
|
32992
|
-
if (lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
|
|
32993
|
-
lines.push(...block.lines);
|
|
32994
|
-
}
|
|
32995
|
-
if (lines.length === 0) lines.push(gray("(waiting for formatted stream output)", options.style));
|
|
32996
|
-
return lines;
|
|
33236
|
+
return formatWatchLogLines({
|
|
33237
|
+
snapshot: rt.aggregator.snapshot(),
|
|
33238
|
+
lastError: rt.lastError,
|
|
33239
|
+
style: options.style,
|
|
33240
|
+
widthHint: options.widthHint
|
|
33241
|
+
});
|
|
32997
33242
|
}
|
|
32998
33243
|
function moveTaskSelection(delta) {
|
|
32999
33244
|
if (runtime.length === 0) return;
|
|
@@ -33189,9 +33434,251 @@ function createWatchCommand(version) {
|
|
|
33189
33434
|
});
|
|
33190
33435
|
}
|
|
33191
33436
|
|
|
33437
|
+
//#endregion
|
|
33438
|
+
//#region src/cli/commands/watch-stream.ts
|
|
33439
|
+
function parseSourceOption(value) {
|
|
33440
|
+
try {
|
|
33441
|
+
return parseAgentStreamSourceOption(value);
|
|
33442
|
+
} catch (error) {
|
|
33443
|
+
throw new InvalidArgumentError(error instanceof Error ? error.message : String(error));
|
|
33444
|
+
}
|
|
33445
|
+
}
|
|
33446
|
+
function createWatchStreamCommand(version) {
|
|
33447
|
+
return createCommand("watch-stream").version(version).description("Watch a single stream and show formatted live logs.").argument("<stream-id>", "The stream id to watch.").option("--source <source>", "Force stream source (codex or claude-code).", parseSourceOption).action(async function() {
|
|
33448
|
+
if (!ensureEnv(["PANTHEON_API_KEY"])) return;
|
|
33449
|
+
const [streamId] = this.args;
|
|
33450
|
+
const options = this.opts();
|
|
33451
|
+
if (!process$1.stdout.isTTY) {
|
|
33452
|
+
console.error("watch-stream requires a TTY.");
|
|
33453
|
+
process$1.exit(1);
|
|
33454
|
+
}
|
|
33455
|
+
const aggregator = new WatchStepAggregator({ maxLogLines: Number.POSITIVE_INFINITY });
|
|
33456
|
+
let source = options.source;
|
|
33457
|
+
let streamEnded = false;
|
|
33458
|
+
let abortedByIdleTimeout = false;
|
|
33459
|
+
let lastError;
|
|
33460
|
+
const abortController = new AbortController();
|
|
33461
|
+
const onSigInt = () => abortController.abort();
|
|
33462
|
+
process$1.on("SIGINT", onSigInt);
|
|
33463
|
+
const screen = blessed.screen({
|
|
33464
|
+
smartCSR: true,
|
|
33465
|
+
title: "pantheon-agents watch-stream"
|
|
33466
|
+
});
|
|
33467
|
+
screen.key(["q", "C-c"], () => abortController.abort());
|
|
33468
|
+
const pane = blessed.box({
|
|
33469
|
+
parent: screen,
|
|
33470
|
+
top: 0,
|
|
33471
|
+
left: 0,
|
|
33472
|
+
height: "100%-1",
|
|
33473
|
+
width: "100%",
|
|
33474
|
+
border: "line",
|
|
33475
|
+
tags: false,
|
|
33476
|
+
wrap: false,
|
|
33477
|
+
style: { border: { fg: "cyan" } }
|
|
33478
|
+
});
|
|
33479
|
+
const header = blessed.box({
|
|
33480
|
+
parent: pane,
|
|
33481
|
+
top: 0,
|
|
33482
|
+
left: 1,
|
|
33483
|
+
height: 2,
|
|
33484
|
+
width: "100%-2",
|
|
33485
|
+
tags: false,
|
|
33486
|
+
wrap: false
|
|
33487
|
+
});
|
|
33488
|
+
const body = blessed.box({
|
|
33489
|
+
parent: pane,
|
|
33490
|
+
top: 2,
|
|
33491
|
+
left: 1,
|
|
33492
|
+
width: "100%-2",
|
|
33493
|
+
height: 1,
|
|
33494
|
+
tags: false,
|
|
33495
|
+
wrap: false,
|
|
33496
|
+
scrollable: false
|
|
33497
|
+
});
|
|
33498
|
+
const footer = blessed.box({
|
|
33499
|
+
parent: screen,
|
|
33500
|
+
bottom: 0,
|
|
33501
|
+
left: 0,
|
|
33502
|
+
height: 1,
|
|
33503
|
+
width: "100%",
|
|
33504
|
+
tags: false,
|
|
33505
|
+
wrap: false,
|
|
33506
|
+
style: { fg: "gray" }
|
|
33507
|
+
});
|
|
33508
|
+
const viewport = {
|
|
33509
|
+
autoFollow: true,
|
|
33510
|
+
scrollOffset: 0
|
|
33511
|
+
};
|
|
33512
|
+
function getFormattedLogLines(style, widthHint) {
|
|
33513
|
+
return formatWatchLogLines({
|
|
33514
|
+
snapshot: aggregator.snapshot(),
|
|
33515
|
+
lastError,
|
|
33516
|
+
style,
|
|
33517
|
+
widthHint
|
|
33518
|
+
});
|
|
33519
|
+
}
|
|
33520
|
+
function scrollLog(delta) {
|
|
33521
|
+
const bodyHeight = typeof body.height === "number" ? body.height : 0;
|
|
33522
|
+
if (bodyHeight <= 0) return;
|
|
33523
|
+
const bodyWidth = typeof body.width === "number" ? body.width : 80;
|
|
33524
|
+
const lines = getFormattedLogLines(useAnsiStyles(), Math.max(20, bodyWidth));
|
|
33525
|
+
const maxOffset = Math.max(0, lines.length - bodyHeight);
|
|
33526
|
+
viewport.autoFollow = false;
|
|
33527
|
+
viewport.scrollOffset = Math.max(0, Math.min(maxOffset, viewport.scrollOffset + delta));
|
|
33528
|
+
}
|
|
33529
|
+
function scrollToTop() {
|
|
33530
|
+
viewport.autoFollow = false;
|
|
33531
|
+
viewport.scrollOffset = 0;
|
|
33532
|
+
}
|
|
33533
|
+
function scrollToBottom() {
|
|
33534
|
+
const bodyHeight = typeof body.height === "number" ? body.height : 0;
|
|
33535
|
+
if (bodyHeight <= 0) return;
|
|
33536
|
+
const bodyWidth = typeof body.width === "number" ? body.width : 80;
|
|
33537
|
+
const lines = getFormattedLogLines(useAnsiStyles(), Math.max(20, bodyWidth));
|
|
33538
|
+
const maxOffset = Math.max(0, lines.length - bodyHeight);
|
|
33539
|
+
viewport.autoFollow = false;
|
|
33540
|
+
viewport.scrollOffset = maxOffset;
|
|
33541
|
+
}
|
|
33542
|
+
function getHalfScreenScrollStep() {
|
|
33543
|
+
const bodyHeight = typeof body.height === "number" ? body.height : 0;
|
|
33544
|
+
return Math.max(1, Math.floor(bodyHeight / 2));
|
|
33545
|
+
}
|
|
33546
|
+
screen.key(["up"], () => {
|
|
33547
|
+
scrollLog(-getHalfScreenScrollStep());
|
|
33548
|
+
});
|
|
33549
|
+
screen.key(["down"], () => {
|
|
33550
|
+
scrollLog(getHalfScreenScrollStep());
|
|
33551
|
+
});
|
|
33552
|
+
screen.key(["g", "home"], () => {
|
|
33553
|
+
scrollToTop();
|
|
33554
|
+
});
|
|
33555
|
+
screen.key([
|
|
33556
|
+
"G",
|
|
33557
|
+
"S-g",
|
|
33558
|
+
"end"
|
|
33559
|
+
], () => {
|
|
33560
|
+
scrollToBottom();
|
|
33561
|
+
});
|
|
33562
|
+
screen.key(["f"], () => {
|
|
33563
|
+
viewport.autoFollow = true;
|
|
33564
|
+
});
|
|
33565
|
+
const renderTimer = setInterval(() => {
|
|
33566
|
+
const style = useAnsiStyles();
|
|
33567
|
+
const columns = Math.max(40, screen.width ?? 120);
|
|
33568
|
+
const rows = Math.max(8, screen.height ?? 24);
|
|
33569
|
+
const contentHeight = Math.max(1, rows - 1);
|
|
33570
|
+
pane.top = 0;
|
|
33571
|
+
pane.left = 0;
|
|
33572
|
+
pane.width = columns;
|
|
33573
|
+
pane.height = contentHeight;
|
|
33574
|
+
pane.setLabel(" Stream Logs ");
|
|
33575
|
+
const paneInnerWidth = Math.max(1, columns - 2);
|
|
33576
|
+
const paneInnerHeight = Math.max(1, contentHeight - 2);
|
|
33577
|
+
const headerHeight = Math.min(2, paneInnerHeight);
|
|
33578
|
+
const bodyHeight = Math.max(0, paneInnerHeight - headerHeight);
|
|
33579
|
+
header.top = 0;
|
|
33580
|
+
header.left = 1;
|
|
33581
|
+
header.width = paneInnerWidth;
|
|
33582
|
+
header.height = headerHeight;
|
|
33583
|
+
const headerLines = [clip(`stream id: ${streamId}`, paneInnerWidth), clip(`source: ${source ?? "(detecting...)"} • status: ${streamEnded ? "ended" : "streaming"}${abortedByIdleTimeout ? " (idle timeout)" : ""}`, paneInnerWidth)];
|
|
33584
|
+
header.setContent(headerLines.slice(0, headerHeight).join("\n"));
|
|
33585
|
+
body.top = headerHeight;
|
|
33586
|
+
body.left = 1;
|
|
33587
|
+
body.width = paneInnerWidth;
|
|
33588
|
+
body.height = bodyHeight;
|
|
33589
|
+
const lines = getFormattedLogLines(style, paneInnerWidth);
|
|
33590
|
+
const maxOffset = Math.max(0, lines.length - bodyHeight);
|
|
33591
|
+
if (viewport.autoFollow) viewport.scrollOffset = maxOffset;
|
|
33592
|
+
else viewport.scrollOffset = Math.max(0, Math.min(maxOffset, viewport.scrollOffset));
|
|
33593
|
+
if (bodyHeight <= 0) body.hide();
|
|
33594
|
+
else {
|
|
33595
|
+
const visibleLines = lines.slice(viewport.scrollOffset, viewport.scrollOffset + bodyHeight);
|
|
33596
|
+
body.setContent(visibleLines.map((line) => clip(line, paneInnerWidth)).join("\n"));
|
|
33597
|
+
body.show();
|
|
33598
|
+
}
|
|
33599
|
+
const footerParts = [
|
|
33600
|
+
"Ctrl+C to exit",
|
|
33601
|
+
"q to quit",
|
|
33602
|
+
"↑/↓ half-page",
|
|
33603
|
+
"g/G top/bottom",
|
|
33604
|
+
"f resume auto-scroll"
|
|
33605
|
+
];
|
|
33606
|
+
if (!viewport.autoFollow) footerParts.push("auto-scroll paused");
|
|
33607
|
+
if (lastError) footerParts.push(`error: ${clip(lastError, 40)}`);
|
|
33608
|
+
footer.setContent(footerParts.join(" • "));
|
|
33609
|
+
screen.render();
|
|
33610
|
+
}, 300);
|
|
33611
|
+
const streamAbort = new AbortController();
|
|
33612
|
+
(async () => {
|
|
33613
|
+
try {
|
|
33614
|
+
const res = await fetch(makeOpaqueStreamUrl(streamId), {
|
|
33615
|
+
headers: {
|
|
33616
|
+
Authorization: `Bearer ${process$1.env.PANTHEON_API_KEY}`,
|
|
33617
|
+
Accept: "text/event-stream"
|
|
33618
|
+
},
|
|
33619
|
+
signal: streamAbort.signal
|
|
33620
|
+
});
|
|
33621
|
+
if (!res.ok) {
|
|
33622
|
+
lastError = `stream request failed: ${res.status} ${res.statusText}`;
|
|
33623
|
+
streamEnded = true;
|
|
33624
|
+
return;
|
|
33625
|
+
}
|
|
33626
|
+
if (!res.body) {
|
|
33627
|
+
lastError = "missing response body";
|
|
33628
|
+
streamEnded = true;
|
|
33629
|
+
return;
|
|
33630
|
+
}
|
|
33631
|
+
let normalizer;
|
|
33632
|
+
const consumeResult = await consumeOpaqueSseStream({
|
|
33633
|
+
stream: res.body,
|
|
33634
|
+
signal: streamAbort.signal,
|
|
33635
|
+
onWarning: (warning) => aggregator.pushUiChunk({
|
|
33636
|
+
type: "data-agent-unknown",
|
|
33637
|
+
data: { reason: warning }
|
|
33638
|
+
}),
|
|
33639
|
+
onData: (payload) => {
|
|
33640
|
+
if (!normalizer) {
|
|
33641
|
+
source = source ?? detectStreamSourceFromRawPayload(payload) ?? "codex";
|
|
33642
|
+
normalizer = createAgentStreamNormalizer({
|
|
33643
|
+
source,
|
|
33644
|
+
emitStartChunk: false,
|
|
33645
|
+
includeMetaEvents: true,
|
|
33646
|
+
unknownChunkPolicy: "emit"
|
|
33647
|
+
});
|
|
33648
|
+
}
|
|
33649
|
+
aggregator.pushUiChunks(normalizer.push(payload));
|
|
33650
|
+
}
|
|
33651
|
+
});
|
|
33652
|
+
if (normalizer) aggregator.pushUiChunks(normalizer.finish());
|
|
33653
|
+
streamEnded = consumeResult.ended;
|
|
33654
|
+
abortedByIdleTimeout = consumeResult.abortedByIdleTimeout;
|
|
33655
|
+
} catch (error) {
|
|
33656
|
+
if (streamAbort.signal.aborted) {
|
|
33657
|
+
streamEnded = true;
|
|
33658
|
+
return;
|
|
33659
|
+
}
|
|
33660
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
33661
|
+
streamEnded = true;
|
|
33662
|
+
}
|
|
33663
|
+
})();
|
|
33664
|
+
try {
|
|
33665
|
+
await new Promise((resolve) => {
|
|
33666
|
+
const resolveOnce = () => resolve();
|
|
33667
|
+
abortController.signal.addEventListener("abort", resolveOnce, { once: true });
|
|
33668
|
+
if (abortController.signal.aborted) resolveOnce();
|
|
33669
|
+
});
|
|
33670
|
+
} finally {
|
|
33671
|
+
process$1.off("SIGINT", onSigInt);
|
|
33672
|
+
clearInterval(renderTimer);
|
|
33673
|
+
streamAbort.abort();
|
|
33674
|
+
screen.destroy();
|
|
33675
|
+
}
|
|
33676
|
+
});
|
|
33677
|
+
}
|
|
33678
|
+
|
|
33192
33679
|
//#endregion
|
|
33193
33680
|
//#region src/cli/index.ts
|
|
33194
|
-
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(createCancelTaskCommand(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)).addCommand(createLlmExplainCommand(version$1));
|
|
33681
|
+
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(createCancelTaskCommand(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)).addCommand(createWatchStreamCommand(version$1)).addCommand(createLlmExplainCommand(version$1));
|
|
33195
33682
|
async function main() {
|
|
33196
33683
|
if (process$1.argv.length <= 2) {
|
|
33197
33684
|
program.outputHelp();
|