@aigne/cli 1.74.0-beta → 1.74.0-beta.2
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 +153 -14
- package/dist/commands/aigne.cjs +3 -4
- package/dist/commands/aigne.mjs +3 -4
- package/dist/commands/aigne.mjs.map +1 -1
- package/dist/commands/app/agent.cjs +2 -27
- package/dist/commands/app/agent.mjs +2 -26
- package/dist/commands/app/agent.mjs.map +1 -1
- package/dist/commands/create.cjs +1 -1
- package/dist/commands/create.mjs +1 -1
- package/dist/commands/eval.cjs +42 -3
- package/dist/commands/eval.mjs +43 -4
- package/dist/commands/eval.mjs.map +1 -1
- package/dist/commands/explain.cjs +340 -0
- package/dist/commands/explain.mjs +340 -0
- package/dist/commands/explain.mjs.map +1 -0
- package/dist/commands/hub.cjs +111 -14
- package/dist/commands/hub.mjs +111 -14
- package/dist/commands/hub.mjs.map +1 -1
- package/dist/commands/observe.cjs +44 -1
- package/dist/commands/observe.mjs +44 -1
- package/dist/commands/observe.mjs.map +1 -1
- package/dist/commands/run-skill.cjs +29 -13
- package/dist/commands/run-skill.mjs +29 -13
- package/dist/commands/run-skill.mjs.map +1 -1
- package/dist/commands/run.cjs +5 -4
- package/dist/commands/run.mjs +5 -4
- package/dist/commands/run.mjs.map +1 -1
- package/dist/commands/serve-mcp.cjs +49 -4
- package/dist/commands/serve-mcp.mjs +49 -3
- package/dist/commands/serve-mcp.mjs.map +1 -1
- package/dist/commands/shell.cjs +106 -0
- package/dist/commands/shell.mjs +105 -0
- package/dist/commands/shell.mjs.map +1 -0
- package/dist/shell/repl.cjs +544 -0
- package/dist/shell/repl.mjs +543 -0
- package/dist/shell/repl.mjs.map +1 -0
- package/dist/shell/tools/ask-user.cjs +191 -0
- package/dist/shell/tools/ask-user.mjs +187 -0
- package/dist/shell/tools/ask-user.mjs.map +1 -0
- package/dist/shell/tools/index.cjs +2 -0
- package/dist/shell/tools/index.mjs +4 -0
- package/dist/shell/tools/render.cjs +189 -0
- package/dist/shell/tools/render.mjs +186 -0
- package/dist/shell/tools/render.mjs.map +1 -0
- package/dist/tracer/terminal.cjs +120 -133
- package/dist/tracer/terminal.mjs +121 -134
- package/dist/tracer/terminal.mjs.map +1 -1
- package/dist/ui/utils/terminal-select.cjs +73 -0
- package/dist/ui/utils/terminal-select.mjs +72 -0
- package/dist/ui/utils/terminal-select.mjs.map +1 -0
- package/dist/utils/agent-v1.cjs +2 -2
- package/dist/utils/agent-v1.mjs +2 -2
- package/dist/utils/aigne-hub/credential.cjs +3 -3
- package/dist/utils/aigne-hub/credential.mjs +3 -3
- package/dist/utils/aigne-hub/model.cjs +2 -2
- package/dist/utils/aigne-hub/model.mjs +1 -1
- package/dist/utils/ascii-logo.cjs +12 -13
- package/dist/utils/ascii-logo.d.cts.map +1 -1
- package/dist/utils/ascii-logo.d.mts.map +1 -1
- package/dist/utils/ascii-logo.mjs +12 -13
- package/dist/utils/ascii-logo.mjs.map +1 -1
- package/dist/utils/evaluation/evaluator.cjs +1 -1
- package/dist/utils/evaluation/evaluator.mjs +1 -1
- package/dist/utils/evaluation/reporter.cjs +78 -1
- package/dist/utils/evaluation/reporter.mjs +76 -1
- package/dist/utils/evaluation/reporter.mjs.map +1 -1
- package/dist/utils/exit-codes.cjs +73 -0
- package/dist/utils/exit-codes.d.cts +52 -0
- package/dist/utils/exit-codes.d.cts.map +1 -0
- package/dist/utils/exit-codes.d.mts +52 -0
- package/dist/utils/exit-codes.d.mts.map +1 -0
- package/dist/utils/exit-codes.mjs +71 -0
- package/dist/utils/exit-codes.mjs.map +1 -0
- package/dist/utils/output.cjs +61 -0
- package/dist/utils/output.d.cts +43 -0
- package/dist/utils/output.d.cts.map +1 -0
- package/dist/utils/output.d.mts +43 -0
- package/dist/utils/output.d.mts.map +1 -0
- package/dist/utils/output.mjs +56 -0
- package/dist/utils/output.mjs.map +1 -0
- package/dist/utils/run-chat-loop.cjs +1 -1
- package/dist/utils/run-chat-loop.mjs +1 -1
- package/dist/utils/run-with-aigne.cjs +10 -3
- package/dist/utils/run-with-aigne.d.cts.map +1 -1
- package/dist/utils/run-with-aigne.d.mts.map +1 -1
- package/dist/utils/run-with-aigne.mjs +10 -3
- package/dist/utils/run-with-aigne.mjs.map +1 -1
- package/dist/utils/serve-mcp.cjs +1 -1
- package/dist/utils/serve-mcp.mjs +1 -1
- package/dist/utils/view.cjs +34 -0
- package/dist/utils/view.d.cts +47 -0
- package/dist/utils/view.d.cts.map +1 -0
- package/dist/utils/view.d.mts +47 -0
- package/dist/utils/view.d.mts.map +1 -0
- package/dist/utils/view.mjs +33 -0
- package/dist/utils/view.mjs.map +1 -0
- package/dist/utils/yargs.cjs +27 -5
- package/dist/utils/yargs.d.cts +13 -0
- package/dist/utils/yargs.d.cts.map +1 -1
- package/dist/utils/yargs.d.mts +14 -1
- package/dist/utils/yargs.d.mts.map +1 -1
- package/dist/utils/yargs.mjs +32 -10
- package/dist/utils/yargs.mjs.map +1 -1
- package/package.json +20 -16
- package/dist/commands/app/app.cjs +0 -92
- package/dist/commands/app/app.mjs +0 -90
- package/dist/commands/app/app.mjs.map +0 -1
- package/dist/commands/app/cli.cjs +0 -6
- package/dist/commands/app/cli.d.cts +0 -1
- package/dist/commands/app/cli.d.mts +0 -1
- package/dist/commands/app/cli.mjs +0 -8
- package/dist/commands/app/cli.mjs.map +0 -1
- package/dist/commands/app/upgrade.cjs +0 -243
- package/dist/commands/app/upgrade.mjs +0 -240
- package/dist/commands/app/upgrade.mjs.map +0 -1
- package/dist/commands/app.cjs +0 -53
- package/dist/commands/app.mjs +0 -53
- package/dist/commands/app.mjs.map +0 -1
- package/dist/commands/deploy.cjs +0 -237
- package/dist/commands/deploy.mjs +0 -237
- package/dist/commands/deploy.mjs.map +0 -1
- package/dist/utils/listr.cjs +0 -226
- package/dist/utils/listr.d.cts +0 -71
- package/dist/utils/listr.d.cts.map +0 -1
- package/dist/utils/listr.d.mts +0 -71
- package/dist/utils/listr.d.mts.map +0 -1
- package/dist/utils/listr.mjs +0 -222
- package/dist/utils/listr.mjs.map +0 -1
package/dist/tracer/terminal.mjs
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE } from "../constants.mjs";
|
|
2
|
+
import { formatJSON, formatLLMDSL } from "../utils/output.mjs";
|
|
2
3
|
import { terminalInput } from "../ui/utils/terminal-input.mjs";
|
|
4
|
+
import { stopThinkingIndicator } from "../shell/tools/ask-user.mjs";
|
|
3
5
|
import checkbox_default from "../utils/inquirer/checkbox.mjs";
|
|
4
|
-
import { AIGNEListr, AIGNEListrRenderer } from "../utils/listr.mjs";
|
|
5
6
|
import { highlightUrl } from "../utils/string-utils.mjs";
|
|
6
7
|
import { parseDuration } from "../utils/time.mjs";
|
|
7
8
|
import chalk from "chalk";
|
|
8
|
-
import {
|
|
9
|
-
import { withProtocol } from "ufo";
|
|
10
|
-
import { AIAgent, ChatModel, DEFAULT_OUTPUT_FILE_KEY, DEFAULT_OUTPUT_KEY, UserAgent, mergeContextUsage, newEmptyContextUsage } from "@aigne/core";
|
|
9
|
+
import { AIAgent, ChatModel, DEFAULT_OUTPUT_FILE_KEY, DEFAULT_OUTPUT_KEY, UserAgent, isAgentResponseProgress, mergeContextUsage, newEmptyContextUsage } from "@aigne/core";
|
|
11
10
|
import { flat, omit } from "@aigne/core/utils/type-utils";
|
|
12
11
|
import { EOL } from "node:os";
|
|
13
|
-
import
|
|
12
|
+
import { withProtocol } from "ufo";
|
|
14
13
|
import { inspect } from "node:util";
|
|
15
|
-
import {
|
|
14
|
+
import { mergeAgentResponseChunk } from "@aigne/core/utils/stream-utils";
|
|
16
15
|
import { markedTerminal } from "@aigne/marked-terminal";
|
|
16
|
+
import * as prompts from "@inquirer/prompts";
|
|
17
17
|
import { Marked } from "marked";
|
|
18
18
|
import terminalImage from "terminal-image";
|
|
19
19
|
import terminalLink from "terminal-link";
|
|
@@ -25,22 +25,20 @@ var TerminalTracer = class {
|
|
|
25
25
|
this.context = context;
|
|
26
26
|
this.options = options;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
result = {};
|
|
29
|
+
usage = newEmptyContextUsage();
|
|
30
|
+
/** Get TTY status, using options.isTTY if provided, otherwise process.stdout.isTTY */
|
|
31
|
+
get isTTY() {
|
|
32
|
+
return this.options.isTTY ?? process.stdout.isTTY ?? false;
|
|
33
|
+
}
|
|
34
|
+
async run(agent, input, options) {
|
|
30
35
|
await this.context.observer?.serve();
|
|
31
36
|
const context = this.context.newContext({ reset: true });
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
formatResult: (result, options$1) => this.formatResult(agent, context, result, options$1)
|
|
35
|
-
}, [], {
|
|
36
|
-
concurrent: true,
|
|
37
|
-
exitOnError: false,
|
|
38
|
-
registerSignalListeners: false
|
|
39
|
-
});
|
|
40
|
-
this.listr = listr;
|
|
37
|
+
const request = this.formatRequest(agent, context, input);
|
|
38
|
+
if (request) console.log(request);
|
|
41
39
|
const collapsedMap = /* @__PURE__ */ new Map();
|
|
42
40
|
const hideContextIds = /* @__PURE__ */ new Set();
|
|
43
|
-
const onStart = async ({ context: context$1, agent: agent$1
|
|
41
|
+
const onStart = async ({ context: context$1, agent: agent$1 }) => {
|
|
44
42
|
const result = { options: { prompts: this.proxiedPrompts } };
|
|
45
43
|
if (agent$1 instanceof UserAgent) return result;
|
|
46
44
|
if (agent$1.taskRenderMode === "hide") {
|
|
@@ -63,87 +61,25 @@ var TerminalTracer = class {
|
|
|
63
61
|
return result;
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
|
-
const contextId = context$1.id;
|
|
67
|
-
const parentContextId = context$1.parentId;
|
|
68
|
-
const task = {
|
|
69
|
-
...promiseWithResolvers(),
|
|
70
|
-
agent: agent$1,
|
|
71
|
-
input: event.input,
|
|
72
|
-
listr: promiseWithResolvers(),
|
|
73
|
-
startTime: Date.now()
|
|
74
|
-
};
|
|
75
|
-
this.tasks[contextId] = task;
|
|
76
|
-
const listrTask = {
|
|
77
|
-
title: await this.formatTaskTitle(agent$1, { ...event }),
|
|
78
|
-
task: (ctx, taskWrapper) => {
|
|
79
|
-
const subtask = taskWrapper.newListr([{ task: () => task.promise }]);
|
|
80
|
-
task.listr.resolve({
|
|
81
|
-
subtask,
|
|
82
|
-
taskWrapper,
|
|
83
|
-
ctx
|
|
84
|
-
});
|
|
85
|
-
return subtask;
|
|
86
|
-
},
|
|
87
|
-
rendererOptions: {
|
|
88
|
-
persistentOutput: true,
|
|
89
|
-
outputBar: Number.POSITIVE_INFINITY,
|
|
90
|
-
bottomBar: Number.POSITIVE_INFINITY
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
const parentTask = parentContextId ? this.tasks[parentContextId] : void 0;
|
|
94
|
-
if (parentTask) parentTask.listr.promise.then(({ subtask }) => {
|
|
95
|
-
subtask.add(listrTask);
|
|
96
|
-
});
|
|
97
|
-
else listr.add(listrTask);
|
|
98
64
|
return result;
|
|
99
65
|
};
|
|
100
|
-
const onSuccess = async ({ context: context$1, agent: agent$1, output
|
|
101
|
-
const
|
|
102
|
-
const parentContextId = context$1.parentId;
|
|
103
|
-
const collapsed = collapsedMap.get(contextId);
|
|
66
|
+
const onSuccess = async ({ context: context$1, agent: agent$1, output }) => {
|
|
67
|
+
const collapsed = collapsedMap.get(context$1.id);
|
|
104
68
|
if (collapsed) {
|
|
105
69
|
if (agent$1 instanceof ChatModel) {
|
|
106
70
|
const { usage, model } = output;
|
|
107
71
|
if (usage) mergeContextUsage(collapsed.usage, usage);
|
|
108
72
|
if (model) collapsed.models.add(model);
|
|
109
73
|
}
|
|
110
|
-
|
|
111
|
-
if (task$1) {
|
|
112
|
-
task$1.usage = collapsed.usage;
|
|
113
|
-
task$1.extraTitleMetadata ??= {};
|
|
114
|
-
if (collapsed.models.size) task$1.extraTitleMetadata.model = [...collapsed.models].join(",");
|
|
115
|
-
const { taskWrapper: taskWrapper$1 } = await task$1.listr.promise;
|
|
116
|
-
taskWrapper$1.title = await this.formatTaskTitle(task$1.agent, {
|
|
117
|
-
input: task$1.input,
|
|
118
|
-
task: task$1,
|
|
119
|
-
usage: Boolean(task$1.usage.inputTokens || task$1.usage.outputTokens || task$1.usage.aigneHubCredits || task$1.usage.cacheCreationInputTokens || task$1.usage.cacheReadInputTokens),
|
|
120
|
-
time: context$1.id === collapsed.ancestor.contextId
|
|
121
|
-
});
|
|
122
|
-
if (context$1.id === collapsed.ancestor.contextId) task$1?.resolve();
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
74
|
+
return;
|
|
125
75
|
}
|
|
126
|
-
const task = this.tasks[contextId];
|
|
127
|
-
if (!task) return;
|
|
128
|
-
task.endTime = Date.now();
|
|
129
|
-
const { taskWrapper, ctx } = await task.listr.promise;
|
|
130
76
|
if (agent$1 instanceof ChatModel) {
|
|
131
|
-
const { usage
|
|
132
|
-
|
|
133
|
-
task.extraTitleMetadata ??= {};
|
|
134
|
-
if (model) task.extraTitleMetadata.model = model;
|
|
77
|
+
const { usage } = output;
|
|
78
|
+
if (usage) mergeContextUsage(this.usage, usage);
|
|
135
79
|
}
|
|
136
|
-
taskWrapper.title = await this.formatTaskTitle(agent$1, {
|
|
137
|
-
...event,
|
|
138
|
-
task,
|
|
139
|
-
usage: true,
|
|
140
|
-
time: true
|
|
141
|
-
});
|
|
142
|
-
if (!parentContextId || !this.tasks[parentContextId]) Object.assign(ctx, output);
|
|
143
|
-
task.resolve();
|
|
144
80
|
};
|
|
145
81
|
let retryPromptPromise;
|
|
146
|
-
const onError = async ({
|
|
82
|
+
const onError = async ({ agent: agent$1, error }) => {
|
|
147
83
|
if ("type" in error && error.type === AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE) {
|
|
148
84
|
if (!Object.hasOwn(error, CREDITS_ERROR_PROCESSED_FLAG)) {
|
|
149
85
|
Object.defineProperty(error, CREDITS_ERROR_PROCESSED_FLAG, {
|
|
@@ -171,46 +107,34 @@ var TerminalTracer = class {
|
|
|
171
107
|
const { retry } = await retryPromptPromise;
|
|
172
108
|
if (retry) return { retry: true };
|
|
173
109
|
}
|
|
174
|
-
const contextId = context$1.id;
|
|
175
|
-
const task = this.tasks[contextId];
|
|
176
|
-
if (!task) return;
|
|
177
|
-
task.endTime = Date.now();
|
|
178
|
-
const { taskWrapper } = await task.listr.promise;
|
|
179
|
-
taskWrapper.title = await this.formatTaskTitle(agent$1, {
|
|
180
|
-
...event,
|
|
181
|
-
task,
|
|
182
|
-
usage: true,
|
|
183
|
-
time: true
|
|
184
|
-
});
|
|
185
|
-
task.reject(error);
|
|
186
110
|
};
|
|
111
|
+
const stream = await context.invoke(agent, input, {
|
|
112
|
+
...options,
|
|
113
|
+
hooks: flat({
|
|
114
|
+
priority: "high",
|
|
115
|
+
onStart,
|
|
116
|
+
onSuccess,
|
|
117
|
+
onError
|
|
118
|
+
}, options?.hooks),
|
|
119
|
+
streaming: true,
|
|
120
|
+
newContext: false
|
|
121
|
+
});
|
|
122
|
+
this.result = await this.processStream(stream);
|
|
123
|
+
console.log(await this.formatResult(agent, context, this.result, {
|
|
124
|
+
running: false,
|
|
125
|
+
renderImage: true,
|
|
126
|
+
streamed: true
|
|
127
|
+
}));
|
|
187
128
|
return {
|
|
188
|
-
result:
|
|
189
|
-
...options,
|
|
190
|
-
hooks: flat({
|
|
191
|
-
priority: "high",
|
|
192
|
-
onStart,
|
|
193
|
-
onSuccess,
|
|
194
|
-
onError
|
|
195
|
-
}, options?.hooks),
|
|
196
|
-
streaming: true,
|
|
197
|
-
newContext: false
|
|
198
|
-
})),
|
|
129
|
+
result: this.result,
|
|
199
130
|
context
|
|
200
131
|
};
|
|
201
132
|
}
|
|
202
|
-
listr;
|
|
203
133
|
proxiedPrompts = new Proxy({}, { get: (_target, prop) => {
|
|
204
134
|
const method = prop === "checkbox" ? checkbox_default : prop === "input" ? terminalInput : prompts[prop];
|
|
205
135
|
if (typeof method !== "function") throw new Error(`Unsupported prompt method ${String(prop)}`);
|
|
206
136
|
return async (config) => {
|
|
207
|
-
|
|
208
|
-
await renderer?.pause();
|
|
209
|
-
try {
|
|
210
|
-
return await method({ ...config });
|
|
211
|
-
} finally {
|
|
212
|
-
await renderer?.resume();
|
|
213
|
-
}
|
|
137
|
+
return await method({ ...config });
|
|
214
138
|
};
|
|
215
139
|
} });
|
|
216
140
|
buyCreditsPromptPromise;
|
|
@@ -231,6 +155,66 @@ var TerminalTracer = class {
|
|
|
231
155
|
this.buyCreditsPromptPromise = void 0;
|
|
232
156
|
});
|
|
233
157
|
}
|
|
158
|
+
marked = new Marked().use({ walkTokens: (token) => {
|
|
159
|
+
if (token.type === "code") {
|
|
160
|
+
if (typeof token.lang === "string") token.lang = token.lang.trim().split(/\s+/)[0];
|
|
161
|
+
}
|
|
162
|
+
} }, markedTerminal({ forceHyperLink: false }, { theme: { string: chalk.green } }));
|
|
163
|
+
async processStream(stream) {
|
|
164
|
+
const result = {};
|
|
165
|
+
const spinnerFrames = [
|
|
166
|
+
"⠋",
|
|
167
|
+
"⠙",
|
|
168
|
+
"⠹",
|
|
169
|
+
"⠸",
|
|
170
|
+
"⠼",
|
|
171
|
+
"⠴",
|
|
172
|
+
"⠦",
|
|
173
|
+
"⠧",
|
|
174
|
+
"⠇",
|
|
175
|
+
"⠏"
|
|
176
|
+
];
|
|
177
|
+
let spinnerIndex = 0;
|
|
178
|
+
let spinnerInterval;
|
|
179
|
+
if (this.isTTY) {
|
|
180
|
+
process.stdout.write(`${spinnerFrames[0]} ${chalk.gray("Thinking...")}`);
|
|
181
|
+
spinnerInterval = setInterval(() => {
|
|
182
|
+
spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
|
|
183
|
+
process.stdout.write(`\r${spinnerFrames[spinnerIndex]} ${chalk.gray("Thinking...")}`);
|
|
184
|
+
}, 80);
|
|
185
|
+
}
|
|
186
|
+
const stopThinking = () => {
|
|
187
|
+
if (spinnerInterval) {
|
|
188
|
+
clearInterval(spinnerInterval);
|
|
189
|
+
spinnerInterval = void 0;
|
|
190
|
+
console.log();
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
for await (const value of stream) {
|
|
194
|
+
mergeAgentResponseChunk(result, value);
|
|
195
|
+
if (isAgentResponseProgress(value) && value.progress.event === "message") {
|
|
196
|
+
const { message } = value.progress;
|
|
197
|
+
if (message.role === "user") continue;
|
|
198
|
+
if (message.role === "agent") {
|
|
199
|
+
stopThinking();
|
|
200
|
+
stopThinkingIndicator();
|
|
201
|
+
}
|
|
202
|
+
const rendered = [];
|
|
203
|
+
if (message.role === "agent") {
|
|
204
|
+
if (message.toolCalls) {
|
|
205
|
+
if (!this.options.suppressToolCallLogs) for (const call of message.toolCalls) rendered.push(`${chalk.bold.gray(`[${call.function.name}]`)} ${chalk.gray(`${JSON.stringify(call.function.arguments).slice(0, 200)}...`)}`);
|
|
206
|
+
} else if (typeof message.content === "string") rendered.push(this.marked.parse(message.content, { async: false }).trim());
|
|
207
|
+
else if (Array.isArray(message.content)) {
|
|
208
|
+
for (const msg of message.content) if (msg.type === "text") if (msg.isThinking) rendered.push(chalk.dim(chalk.grey(chalk.italic(`[Thinking] ${msg.text}`))));
|
|
209
|
+
else rendered.push(this.marked.parse(msg.text, { async: false }).trim());
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (rendered.length) console.log(`${chalk.green.bold("•")} ${rendered.join("\n")}\n`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
stopThinking();
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
234
218
|
formatAigneHubCredits(credits, creditPrefix) {
|
|
235
219
|
const formattedCredits = credits % 1 !== 0 ? parseFloat(credits.toFixed(6)).toString() : credits.toFixed();
|
|
236
220
|
if (creditPrefix) return [chalk.grey("cost:"), chalk.blue(`${creditPrefix}${formattedCredits}`)];
|
|
@@ -252,18 +236,6 @@ var TerminalTracer = class {
|
|
|
252
236
|
const duration = endTime - startTime;
|
|
253
237
|
return chalk.grey(`[${parseDuration(duration)}]`);
|
|
254
238
|
}
|
|
255
|
-
async formatTaskTitle(agent, { task, usage, time, input: input$1 }) {
|
|
256
|
-
let title = agent.name;
|
|
257
|
-
if (agent.taskTitle) title += ` ${chalk.cyan(await agent.renderTaskTitle(input$1))}`;
|
|
258
|
-
if (usage && task?.usage) title += ` ${this.formatTokenUsage(task.usage, task.extraTitleMetadata)}`;
|
|
259
|
-
if (time && task?.startTime && task.endTime) title += ` ${this.formatTimeUsage(task.startTime, task.endTime)}`;
|
|
260
|
-
return title;
|
|
261
|
-
}
|
|
262
|
-
marked = new Marked().use({ walkTokens: (token) => {
|
|
263
|
-
if (token.type === "code") {
|
|
264
|
-
if (typeof token.lang === "string") token.lang = token.lang.trim().split(/\s+/)[0];
|
|
265
|
-
}
|
|
266
|
-
} }, markedTerminal({ forceHyperLink: false }, { theme: { string: chalk.green } }));
|
|
267
239
|
get outputKey() {
|
|
268
240
|
return this.options.outputKey || DEFAULT_OUTPUT_KEY;
|
|
269
241
|
}
|
|
@@ -271,8 +243,8 @@ var TerminalTracer = class {
|
|
|
271
243
|
return this.options.outputFileKey || DEFAULT_OUTPUT_FILE_KEY;
|
|
272
244
|
}
|
|
273
245
|
formatRequest(agent, _context, m = {}, { running = false } = {}) {
|
|
274
|
-
const prefix = `${chalk.grey(
|
|
275
|
-
const inputKey = agent instanceof AIAgent ? agent.inputKey : void 0;
|
|
246
|
+
const prefix = `${chalk.grey("→")} 💬 `;
|
|
247
|
+
const inputKey = agent instanceof AIAgent ? agent.inputKey : agent instanceof UserAgent ? "message" : void 0;
|
|
276
248
|
const msg = inputKey ? m[inputKey] : void 0;
|
|
277
249
|
const message = inputKey ? omit(m, inputKey) : m;
|
|
278
250
|
const r = [msg && typeof msg === "string" ? this.marked.parse(msg, { async: false }).trim() : void 0, Object.keys(message).length > 0 ? inspect(message, {
|
|
@@ -282,10 +254,25 @@ var TerminalTracer = class {
|
|
|
282
254
|
if (!r) return void 0;
|
|
283
255
|
return `${prefix}${r}`;
|
|
284
256
|
}
|
|
285
|
-
formatResult(agent, context, m = {}, { running = false, renderImage = false } = {}) {
|
|
286
|
-
const
|
|
257
|
+
formatResult(agent, context, m = {}, { running = false, renderImage = false, streamed = false } = {}) {
|
|
258
|
+
const view = this.options.view;
|
|
259
|
+
if (view === "json") return formatJSON(m);
|
|
260
|
+
if (view === "llm") return formatLLMDSL(m, Object.keys(m));
|
|
261
|
+
if (view === "default") {
|
|
262
|
+
const outputKey$1 = this.outputKey || (agent instanceof AIAgent ? agent.outputKey : void 0);
|
|
263
|
+
const msg$1 = outputKey$1 ? m[outputKey$1] : void 0;
|
|
264
|
+
if (msg$1 && typeof msg$1 === "string") return msg$1;
|
|
265
|
+
return JSON.stringify(m);
|
|
266
|
+
}
|
|
267
|
+
const isTTY = this.isTTY;
|
|
287
268
|
const outputKey = this.outputKey || (agent instanceof AIAgent ? agent.outputKey : void 0);
|
|
288
|
-
const prefix = `${chalk.grey(
|
|
269
|
+
const prefix = `${chalk.grey("✓")} 🤖 ${this.formatTokenUsage(context.usage)}`;
|
|
270
|
+
if (streamed) {
|
|
271
|
+
if (renderImage) return this.formatResultData(m).then((images) => {
|
|
272
|
+
return [prefix, images].filter(Boolean).join(EOL.repeat(2));
|
|
273
|
+
});
|
|
274
|
+
return prefix;
|
|
275
|
+
}
|
|
289
276
|
const msg = outputKey ? m[outputKey] : void 0;
|
|
290
277
|
const message = outputKey ? omit(m, outputKey, this.outputFileKey) : m;
|
|
291
278
|
const text = msg && typeof msg === "string" ? isTTY ? this.marked.parse(msg, { async: false }).trim() : msg : void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.mjs","names":["input","options","agent","context","task","checkbox"],"sources":["../../src/tracer/terminal.ts"],"sourcesContent":["import { EOL } from \"node:os\";\nimport { type InspectOptions, inspect } from \"node:util\";\nimport {\n type Agent,\n type AgentHooks,\n AIAgent,\n ChatModel,\n type ChatModelOutput,\n type Context,\n type ContextUsage,\n DEFAULT_OUTPUT_FILE_KEY,\n DEFAULT_OUTPUT_KEY,\n type FileUnionContent,\n type InvokeOptions,\n type Message,\n mergeContextUsage,\n newEmptyContextUsage,\n UserAgent,\n} from \"@aigne/core\";\nimport { promiseWithResolvers } from \"@aigne/core/utils/promise\";\nimport { flat, omit } from \"@aigne/core/utils/type-utils\";\nimport { figures, type Listr } from \"@aigne/listr2\";\nimport { markedTerminal } from \"@aigne/marked-terminal\";\nimport * as prompts from \"@inquirer/prompts\";\nimport chalk from \"chalk\";\nimport { Marked } from \"marked\";\nimport terminalImage from \"terminal-image\";\nimport terminalLink from \"terminal-link\";\nimport { withProtocol } from \"ufo\";\nimport { AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE } from \"../constants.js\";\nimport { terminalInput } from \"../ui/utils/terminal-input.js\";\nimport checkbox from \"../utils/inquirer/checkbox.js\";\nimport { AIGNEListr, AIGNEListrRenderer, type AIGNEListrTaskWrapper } from \"../utils/listr.js\";\nimport { highlightUrl } from \"../utils/string-utils.js\";\nimport { parseDuration } from \"../utils/time.js\";\n\nconst CREDITS_ERROR_PROCESSED_FLAG = \"$credits_error_processed\";\n\nexport interface TerminalTracerOptions {\n outputKey?: string;\n outputFileKey?: string;\n}\n\nexport class TerminalTracer {\n constructor(\n public readonly context: Context,\n public readonly options: TerminalTracerOptions = {},\n ) {}\n\n private tasks: { [callId: string]: Task } = {};\n\n async run(agent: Agent, input: Message, options?: InvokeOptions) {\n await this.context.observer?.serve();\n\n const context = this.context.newContext({ reset: true });\n\n const listr = new AIGNEListr(\n {\n formatRequest: (options?: { running?: boolean }) =>\n this.formatRequest(agent, context, input, options),\n formatResult: (result, options?: { running?: boolean; renderImage?: boolean }) =>\n this.formatResult(agent, context, result, options),\n },\n [],\n { concurrent: true, exitOnError: false, registerSignalListeners: false },\n );\n this.listr = listr;\n\n const collapsedMap = new Map<\n string,\n { ancestor: { contextId: string }; usage: ContextUsage; models: Set<string> }\n >();\n const hideContextIds = new Set<string>();\n\n const onStart: AgentHooks[\"onStart\"] = async ({ context, agent, ...event }) => {\n const result = { options: { prompts: this.proxiedPrompts } };\n\n if (agent instanceof UserAgent) return result;\n\n if (agent.taskRenderMode === \"hide\") {\n hideContextIds.add(context.id);\n return result;\n }\n\n if (agent.taskRenderMode === \"collapse\") {\n collapsedMap.set(context.id, {\n ancestor: { contextId: context.id },\n usage: newEmptyContextUsage(),\n models: new Set(),\n });\n }\n\n if (context.parentId) {\n if (hideContextIds.has(context.parentId)) {\n hideContextIds.add(context.id);\n return result;\n }\n\n const collapsed = collapsedMap.get(context.parentId);\n if (collapsed) {\n collapsedMap.set(context.id, collapsed);\n return result;\n }\n }\n\n const contextId = context.id;\n const parentContextId = context.parentId;\n\n const task: Task = {\n ...promiseWithResolvers(),\n agent,\n input: event.input,\n listr: promiseWithResolvers(),\n startTime: Date.now(),\n };\n this.tasks[contextId] = task;\n\n const listrTask: Parameters<typeof listr.add>[0] = {\n title: await this.formatTaskTitle(agent, { ...event }),\n task: (ctx, taskWrapper) => {\n const subtask = taskWrapper.newListr([{ task: () => task.promise }]);\n task.listr.resolve({ subtask, taskWrapper, ctx });\n return subtask;\n },\n rendererOptions: {\n persistentOutput: true,\n outputBar: Number.POSITIVE_INFINITY,\n bottomBar: Number.POSITIVE_INFINITY,\n },\n };\n\n const parentTask = parentContextId ? this.tasks[parentContextId] : undefined;\n if (parentTask) {\n parentTask.listr.promise.then(({ subtask }) => {\n subtask.add(listrTask);\n });\n } else {\n listr.add(listrTask);\n }\n\n return result;\n };\n\n const onSuccess: AgentHooks[\"onSuccess\"] = async ({ context, agent, output, ...event }) => {\n const contextId = context.id;\n const parentContextId = context.parentId;\n\n const collapsed = collapsedMap.get(contextId);\n if (collapsed) {\n if (agent instanceof ChatModel) {\n const { usage, model } = output as ChatModelOutput;\n if (usage) mergeContextUsage(collapsed.usage, usage);\n if (model) collapsed.models.add(model);\n }\n\n const task = this.tasks[collapsed.ancestor.contextId];\n if (task) {\n task.usage = collapsed.usage;\n task.extraTitleMetadata ??= {};\n if (collapsed.models.size)\n task.extraTitleMetadata.model = [...collapsed.models].join(\",\");\n\n const { taskWrapper } = await task.listr.promise;\n\n taskWrapper.title = await this.formatTaskTitle(task.agent, {\n input: task.input,\n task,\n usage: Boolean(\n task.usage.inputTokens ||\n task.usage.outputTokens ||\n task.usage.aigneHubCredits ||\n task.usage.cacheCreationInputTokens ||\n task.usage.cacheReadInputTokens,\n ),\n time: context.id === collapsed.ancestor.contextId,\n });\n\n if (context.id === collapsed.ancestor.contextId) {\n task?.resolve();\n }\n return;\n }\n }\n\n const task = this.tasks[contextId];\n if (!task) return;\n\n task.endTime = Date.now();\n\n const { taskWrapper, ctx } = await task.listr.promise;\n\n if (agent instanceof ChatModel) {\n const { usage, model } = output as ChatModelOutput;\n task.usage = usage;\n task.extraTitleMetadata ??= {};\n if (model) task.extraTitleMetadata.model = model;\n }\n\n taskWrapper.title = await this.formatTaskTitle(agent, {\n ...event,\n task,\n usage: true,\n time: true,\n });\n\n if (!parentContextId || !this.tasks[parentContextId]) {\n Object.assign(ctx, output);\n }\n\n task.resolve();\n };\n\n let retryPromptPromise: Promise<{ retry?: boolean }> | undefined;\n\n const onError: AgentHooks[\"onError\"] = async ({ context, agent, error, ...event }) => {\n if (\"type\" in error && error.type === AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE) {\n if (!Object.hasOwn(error, CREDITS_ERROR_PROCESSED_FLAG)) {\n Object.defineProperty(error, CREDITS_ERROR_PROCESSED_FLAG, {\n value: true,\n enumerable: false,\n });\n\n const retry = await this.promptBuyCredits(error);\n\n console.log(\"\");\n\n if (retry === \"retry\") {\n return { retry: true };\n }\n }\n }\n\n if (agent instanceof ChatModel) {\n retryPromptPromise ??= this.proxiedPrompts\n .select({\n message: chalk.red(`Error: ${error.message}`),\n choices: [\n { value: \"retry\", name: \"Retry\" },\n { value: \"exit\", name: \"Exit\" },\n ],\n })\n .then((result) => ({ retry: result === \"retry\" }))\n .finally(() => {\n retryPromptPromise = undefined;\n });\n\n const { retry } = await retryPromptPromise;\n if (retry) return { retry: true };\n }\n\n const contextId = context.id;\n\n const task = this.tasks[contextId];\n if (!task) return;\n\n task.endTime = Date.now();\n\n const { taskWrapper } = await task.listr.promise;\n taskWrapper.title = await this.formatTaskTitle(agent, {\n ...event,\n task,\n usage: true,\n time: true,\n });\n\n task.reject(error);\n };\n\n const result = await listr.run(() =>\n context.invoke(agent, input, {\n ...options,\n hooks: flat(\n {\n priority: \"high\",\n onStart,\n onSuccess,\n onError,\n },\n options?.hooks,\n ),\n streaming: true,\n newContext: false,\n }),\n );\n\n return { result, context };\n }\n\n private listr?: AIGNEListr;\n\n private proxiedPrompts = new Proxy(\n {},\n {\n get: (_target, prop) => {\n const method =\n prop === \"checkbox\"\n ? checkbox\n : prop === \"input\"\n ? terminalInput\n : // biome-ignore lint/performance/noDynamicNamespaceImportAccess: we need to access prompts dynamically\n (prompts[prop as keyof typeof prompts] as (...args: any[]) => any);\n if (typeof method !== \"function\")\n throw new Error(`Unsupported prompt method ${String(prop)}`);\n\n return async (config: any) => {\n const renderer =\n this.listr?.[\"renderer\"] instanceof AIGNEListrRenderer\n ? this.listr[\"renderer\"]\n : undefined;\n await renderer?.pause();\n\n try {\n return await method({ ...config });\n } finally {\n await renderer?.resume();\n }\n };\n },\n },\n ) as typeof prompts;\n\n private buyCreditsPromptPromise: Promise<\"retry\" | \"exit\"> | undefined;\n\n private async promptBuyCredits(error: Error) {\n // Avoid multiple agents asking for credits, we will only show the prompt once\n this.buyCreditsPromptPromise ??= (async () => {\n const retry = await this.proxiedPrompts.select({\n message: highlightUrl(error.message),\n choices: [\n {\n name: \"I have bought some credits, try again\",\n value: \"retry\" as const,\n },\n {\n name: \"Exit\",\n value: \"exit\" as const,\n },\n ],\n });\n\n return retry;\n })();\n\n return this.buyCreditsPromptPromise\n .catch(() => \"exit\")\n .finally(() => {\n // Clear the promise so that we can show the prompt again if needed\n this.buyCreditsPromptPromise = undefined;\n });\n }\n\n formatAigneHubCredits(credits: number, creditPrefix?: string): [string, string] {\n const hasDecimal = credits % 1 !== 0;\n const formattedCredits = hasDecimal\n ? parseFloat(credits.toFixed(6)).toString()\n : credits.toFixed();\n\n if (creditPrefix) {\n return [chalk.grey(\"cost:\"), chalk.blue(`${creditPrefix}${formattedCredits}`)];\n }\n\n return [chalk.blue(formattedCredits), chalk.grey(\"AIGNE Hub credits\")];\n }\n\n formatTokenUsage(usage: Partial<ContextUsage>, extra?: { [key: string]: string }) {\n const items = [\n [chalk.yellow(usage.inputTokens), chalk.grey(\"input tokens\")],\n usage.cacheReadInputTokens\n ? [chalk.green(usage.cacheReadInputTokens), chalk.grey(\"cached\")]\n : undefined,\n usage.cacheCreationInputTokens\n ? [chalk.yellow(usage.cacheCreationInputTokens), chalk.grey(\"cache write\")]\n : undefined,\n [chalk.cyan(usage.outputTokens), chalk.grey(\"output tokens\")],\n usage.aigneHubCredits\n ? this.formatAigneHubCredits(usage.aigneHubCredits, usage.creditPrefix)\n : undefined,\n usage.agentCalls ? [chalk.magenta(usage.agentCalls), chalk.grey(\"agent calls\")] : undefined,\n ];\n\n const content = items.filter((i) => !!i).map((i) => i.join(\" \"));\n\n if (extra) {\n content.unshift(\n ...Object.entries(extra)\n .filter(([k, v]) => k && v)\n .map(([k, v]) => `${chalk.grey(k)}: ${v}`),\n );\n }\n\n return `${chalk.grey(\"(\")}${content.join(chalk.green(\", \"))}${chalk.grey(\")\")}`;\n }\n\n formatTimeUsage(startTime: number, endTime: number) {\n const duration = endTime - startTime;\n return chalk.grey(`[${parseDuration(duration)}]`);\n }\n\n async formatTaskTitle(\n agent: Agent,\n { task, usage, time, input }: { task?: Task; usage?: boolean; time?: boolean; input: Message },\n ) {\n let title = agent.name;\n\n if (agent.taskTitle) {\n title += ` ${chalk.cyan(await agent.renderTaskTitle(input))}`;\n }\n\n if (usage && task?.usage)\n title += ` ${this.formatTokenUsage(task.usage, task.extraTitleMetadata)}`;\n if (time && task?.startTime && task.endTime)\n title += ` ${this.formatTimeUsage(task.startTime, task.endTime)}`;\n\n return title;\n }\n\n private marked = new Marked().use(\n {\n // marked-terminal does not support code block meta, so we need to strip it\n walkTokens: (token) => {\n if (token.type === \"code\") {\n if (typeof token.lang === \"string\") {\n token.lang = token.lang.trim().split(/\\s+/)[0];\n }\n }\n },\n },\n markedTerminal(\n { forceHyperLink: false },\n {\n theme: {\n string: chalk.green,\n },\n },\n ),\n );\n\n get outputKey() {\n return this.options.outputKey || DEFAULT_OUTPUT_KEY;\n }\n\n get outputFileKey() {\n return this.options.outputFileKey || DEFAULT_OUTPUT_FILE_KEY;\n }\n\n formatRequest(agent: Agent, _context: Context, m: Message = {}, { running = false } = {}) {\n const prefix = `${chalk.grey(figures.pointer)} 💬 `;\n\n const inputKey = agent instanceof AIAgent ? agent.inputKey : undefined;\n\n const msg = inputKey ? m[inputKey] : undefined;\n const message = inputKey ? omit(m, inputKey) : m;\n\n const text =\n msg && typeof msg === \"string\" ? this.marked.parse(msg, { async: false }).trim() : undefined;\n\n const json =\n Object.keys(message).length > 0\n ? inspect(message, { colors: true, ...(running ? this.runningInspectOptions : undefined) })\n : undefined;\n\n const r = [text, json].filter(Boolean).join(EOL).trim();\n if (!r) return undefined;\n\n return `${prefix}${r}`;\n }\n\n formatResult(\n agent: Agent,\n context: Context,\n m: Message = {},\n { running = false, renderImage = false } = {},\n ): string | Promise<string> {\n const { isTTY } = process.stdout;\n const outputKey = this.outputKey || (agent instanceof AIAgent ? agent.outputKey : undefined);\n\n const prefix = `${chalk.grey(figures.tick)} 🤖 ${this.formatTokenUsage(context.usage)}`;\n\n const msg = outputKey ? m[outputKey] : undefined;\n const message = outputKey ? omit(m, outputKey, this.outputFileKey) : m;\n\n const text =\n msg && typeof msg === \"string\"\n ? isTTY\n ? this.marked.parse(msg, { async: false }).trim()\n : msg\n : undefined;\n\n const json =\n Object.keys(message).length > 0\n ? inspect(message, { colors: isTTY, ...(running ? this.runningInspectOptions : undefined) })\n : undefined;\n\n if (renderImage) {\n return this.formatResultData(m).then((images) => {\n return [prefix, text, images, json].filter(Boolean).join(EOL.repeat(2));\n });\n }\n\n return [prefix, text, json].filter(Boolean).join(EOL.repeat(2));\n }\n\n async formatResultData(output: Message): Promise<string | undefined> {\n const files = output[this.outputFileKey] as FileUnionContent[];\n if (!Array.isArray(files)) return;\n\n const options: Parameters<typeof terminalImage.file>[1] = {\n height: 30,\n };\n\n return (\n await Promise.all(\n files.map(async (item) => {\n const image =\n item.type === \"local\"\n ? await terminalImage.file(item.path, options)\n : item.type === \"file\"\n ? await terminalImage.buffer(Buffer.from(item.data, \"base64\"), options)\n : undefined;\n\n const link =\n item.type === \"local\"\n ? withProtocol(item.path, \"file://\")\n : item.type === \"url\"\n ? item.url\n : undefined;\n const text = [\n link ? chalk.cyan(terminalLink(link, link)) : undefined,\n item.filename,\n item.mimeType ? chalk.gray(item.mimeType) : undefined,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return [image, text].filter(Boolean).join(EOL);\n }),\n )\n )\n .filter(Boolean)\n .join(EOL);\n }\n\n protected runningInspectOptions: InspectOptions = {\n maxArrayLength: 3,\n maxStringLength: 200,\n };\n}\n\ntype Task = ReturnType<typeof promiseWithResolvers<void>> & {\n listr: ReturnType<\n typeof promiseWithResolvers<{\n ctx: object;\n subtask: Listr;\n taskWrapper: AIGNEListrTaskWrapper;\n }>\n >;\n agent: Agent;\n input: Message;\n startTime?: number;\n endTime?: number;\n usage?: Partial<ContextUsage>;\n extraTitleMetadata?: { [key: string]: string };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"terminal.mjs","names":["agent","context","checkbox","outputKey","msg"],"sources":["../../src/tracer/terminal.ts"],"sourcesContent":["import { EOL } from \"node:os\";\nimport { type InspectOptions, inspect } from \"node:util\";\nimport {\n type Agent,\n type AgentHooks,\n type AgentResponseStream,\n AIAgent,\n ChatModel,\n type ChatModelOutput,\n type Context,\n type ContextUsage,\n DEFAULT_OUTPUT_FILE_KEY,\n DEFAULT_OUTPUT_KEY,\n type FileUnionContent,\n type InvokeOptions,\n isAgentResponseProgress,\n type Message,\n mergeContextUsage,\n newEmptyContextUsage,\n UserAgent,\n} from \"@aigne/core\";\nimport { mergeAgentResponseChunk } from \"@aigne/core/utils/stream-utils\";\nimport { flat, omit } from \"@aigne/core/utils/type-utils\";\nimport { markedTerminal } from \"@aigne/marked-terminal\";\nimport * as prompts from \"@inquirer/prompts\";\nimport chalk from \"chalk\";\nimport { Marked } from \"marked\";\nimport terminalImage from \"terminal-image\";\nimport terminalLink from \"terminal-link\";\nimport { withProtocol } from \"ufo\";\nimport { AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE } from \"../constants.js\";\nimport { stopThinkingIndicator } from \"../shell/tools/ask-user.js\";\nimport { terminalInput } from \"../ui/utils/terminal-input.js\";\nimport checkbox from \"../utils/inquirer/checkbox.js\";\nimport { formatJSON, formatLLMDSL } from \"../utils/output.js\";\nimport { highlightUrl } from \"../utils/string-utils.js\";\nimport { parseDuration } from \"../utils/time.js\";\nimport type { ViewType } from \"../utils/view.js\";\n\nconst CREDITS_ERROR_PROCESSED_FLAG = \"$credits_error_processed\";\n\nexport interface TerminalTracerOptions {\n outputKey?: string;\n outputFileKey?: string;\n /** Output view type for formatting results */\n view?: ViewType;\n /** Suppress tool call logging (useful for interactive shells) */\n suppressToolCallLogs?: boolean;\n /** Override TTY detection (useful for testing) */\n isTTY?: boolean;\n}\n\nexport class TerminalTracer {\n constructor(\n public readonly context: Context,\n public readonly options: TerminalTracerOptions = {},\n ) {}\n\n private result: Message = {};\n private usage: ContextUsage = newEmptyContextUsage();\n\n /** Get TTY status, using options.isTTY if provided, otherwise process.stdout.isTTY */\n private get isTTY(): boolean {\n return this.options.isTTY ?? process.stdout.isTTY ?? false;\n }\n\n async run(agent: Agent, input: Message, options?: InvokeOptions) {\n await this.context.observer?.serve();\n\n const context = this.context.newContext({ reset: true });\n\n // Print request\n const request = this.formatRequest(agent, context, input);\n if (request) console.log(request);\n\n const collapsedMap = new Map<\n string,\n { ancestor: { contextId: string }; usage: ContextUsage; models: Set<string> }\n >();\n const hideContextIds = new Set<string>();\n\n const onStart: AgentHooks[\"onStart\"] = async ({ context, agent }) => {\n const result = { options: { prompts: this.proxiedPrompts } };\n\n if (agent instanceof UserAgent) return result;\n\n if (agent.taskRenderMode === \"hide\") {\n hideContextIds.add(context.id);\n return result;\n }\n\n if (agent.taskRenderMode === \"collapse\") {\n collapsedMap.set(context.id, {\n ancestor: { contextId: context.id },\n usage: newEmptyContextUsage(),\n models: new Set(),\n });\n }\n\n if (context.parentId) {\n if (hideContextIds.has(context.parentId)) {\n hideContextIds.add(context.id);\n return result;\n }\n\n const collapsed = collapsedMap.get(context.parentId);\n if (collapsed) {\n collapsedMap.set(context.id, collapsed);\n return result;\n }\n }\n\n return result;\n };\n\n const onSuccess: AgentHooks[\"onSuccess\"] = async ({ context, agent, output }) => {\n const collapsed = collapsedMap.get(context.id);\n if (collapsed) {\n if (agent instanceof ChatModel) {\n const { usage, model } = output as ChatModelOutput;\n if (usage) mergeContextUsage(collapsed.usage, usage);\n if (model) collapsed.models.add(model);\n }\n return;\n }\n\n if (agent instanceof ChatModel) {\n const { usage } = output as ChatModelOutput;\n if (usage) mergeContextUsage(this.usage, usage);\n }\n };\n\n let retryPromptPromise: Promise<{ retry?: boolean }> | undefined;\n\n const onError: AgentHooks[\"onError\"] = async ({ agent, error }) => {\n if (\"type\" in error && error.type === AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE) {\n if (!Object.hasOwn(error, CREDITS_ERROR_PROCESSED_FLAG)) {\n Object.defineProperty(error, CREDITS_ERROR_PROCESSED_FLAG, {\n value: true,\n enumerable: false,\n });\n\n const retry = await this.promptBuyCredits(error);\n\n console.log(\"\");\n\n if (retry === \"retry\") {\n return { retry: true };\n }\n }\n }\n\n if (agent instanceof ChatModel) {\n retryPromptPromise ??= this.proxiedPrompts\n .select({\n message: chalk.red(`Error: ${error.message}`),\n choices: [\n { value: \"retry\", name: \"Retry\" },\n { value: \"exit\", name: \"Exit\" },\n ],\n })\n .then((result) => ({ retry: result === \"retry\" }))\n .finally(() => {\n retryPromptPromise = undefined;\n });\n\n const { retry } = await retryPromptPromise;\n if (retry) return { retry: true };\n }\n };\n\n const stream = await context.invoke(agent, input, {\n ...options,\n hooks: flat(\n {\n priority: \"high\",\n onStart,\n onSuccess,\n onError,\n },\n options?.hooks,\n ),\n streaming: true,\n newContext: false,\n });\n\n this.result = await this.processStream(stream);\n\n // Print result (streamed: true since content was already printed via streaming)\n console.log(\n await this.formatResult(agent, context, this.result, {\n running: false,\n renderImage: true,\n streamed: true,\n }),\n );\n\n return { result: this.result, context };\n }\n\n private proxiedPrompts = new Proxy(\n {},\n {\n get: (_target, prop) => {\n const method =\n prop === \"checkbox\"\n ? checkbox\n : prop === \"input\"\n ? terminalInput\n : // biome-ignore lint/performance/noDynamicNamespaceImportAccess: we need to access prompts dynamically\n (prompts[prop as keyof typeof prompts] as (...args: any[]) => any);\n if (typeof method !== \"function\")\n throw new Error(`Unsupported prompt method ${String(prop)}`);\n\n return async (config: any) => {\n return await method({ ...config });\n };\n },\n },\n ) as typeof prompts;\n\n private buyCreditsPromptPromise: Promise<\"retry\" | \"exit\"> | undefined;\n\n private async promptBuyCredits(error: Error) {\n // Avoid multiple agents asking for credits, we will only show the prompt once\n this.buyCreditsPromptPromise ??= (async () => {\n const retry = await this.proxiedPrompts.select({\n message: highlightUrl(error.message),\n choices: [\n {\n name: \"I have bought some credits, try again\",\n value: \"retry\" as const,\n },\n {\n name: \"Exit\",\n value: \"exit\" as const,\n },\n ],\n });\n\n return retry;\n })();\n\n return this.buyCreditsPromptPromise\n .catch(() => \"exit\")\n .finally(() => {\n // Clear the promise so that we can show the prompt again if needed\n this.buyCreditsPromptPromise = undefined;\n });\n }\n\n private marked = new Marked().use(\n {\n // marked-terminal does not support code block meta, so we need to strip it\n walkTokens: (token) => {\n if (token.type === \"code\") {\n if (typeof token.lang === \"string\") {\n token.lang = token.lang.trim().split(/\\s+/)[0];\n }\n }\n },\n },\n markedTerminal(\n { forceHyperLink: false },\n {\n theme: {\n string: chalk.green,\n },\n },\n ),\n );\n\n private async processStream(stream: AgentResponseStream<Message>): Promise<Message> {\n const result: Message = {};\n\n // Show thinking indicator while waiting for response\n const spinnerFrames = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n let spinnerIndex = 0;\n let spinnerInterval: ReturnType<typeof setInterval> | undefined;\n\n if (this.isTTY) {\n // Write first frame immediately\n process.stdout.write(`${spinnerFrames[0]} ${chalk.gray(\"Thinking...\")}`);\n spinnerInterval = setInterval(() => {\n spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;\n process.stdout.write(`\\r${spinnerFrames[spinnerIndex]} ${chalk.gray(\"Thinking...\")}`);\n }, 80);\n }\n\n const stopThinking = () => {\n if (spinnerInterval) {\n clearInterval(spinnerInterval);\n spinnerInterval = undefined;\n // Just move to a new line - leave \"Thinking...\" visible as a log\n console.log();\n }\n };\n\n for await (const value of stream) {\n mergeAgentResponseChunk(result, value);\n\n if (isAgentResponseProgress(value) && value.progress.event === \"message\") {\n const { message } = value.progress;\n\n // Skip user messages - they're already printed by formatRequest\n if (message.role === \"user\") continue;\n\n // Stop thinking indicator when any agent message arrives (including tool calls)\n if (message.role === \"agent\") {\n stopThinking();\n stopThinkingIndicator(); // Also stop ask_user's thinking indicator\n }\n\n const rendered: string[] = [];\n\n if (message.role === \"agent\") {\n if (message.toolCalls) {\n // Skip tool call logging if suppressToolCallLogs is enabled\n if (!this.options.suppressToolCallLogs) {\n for (const call of message.toolCalls) {\n rendered.push(\n `${chalk.bold.gray(`[${call.function.name}]`)} ${chalk.gray(`${JSON.stringify(call.function.arguments).slice(0, 200)}...`)}`,\n );\n }\n }\n } else if (typeof message.content === \"string\") {\n rendered.push(this.marked.parse(message.content, { async: false }).trim());\n } else if (Array.isArray(message.content)) {\n for (const msg of message.content) {\n if (msg.type === \"text\") {\n if (msg.isThinking) {\n rendered.push(chalk.dim(chalk.grey(chalk.italic(`[Thinking] ${msg.text}`))));\n } else {\n rendered.push(this.marked.parse(msg.text, { async: false }).trim());\n }\n }\n }\n }\n }\n\n if (rendered.length) {\n console.log(`${chalk.green.bold(\"•\")} ${rendered.join(\"\\n\")}\\n`);\n }\n }\n }\n\n // Ensure spinner is stopped even if no messages came through\n stopThinking();\n\n return result;\n }\n\n formatAigneHubCredits(credits: number, creditPrefix?: string): [string, string] {\n const hasDecimal = credits % 1 !== 0;\n const formattedCredits = hasDecimal\n ? parseFloat(credits.toFixed(6)).toString()\n : credits.toFixed();\n\n if (creditPrefix) {\n return [chalk.grey(\"cost:\"), chalk.blue(`${creditPrefix}${formattedCredits}`)];\n }\n\n return [chalk.blue(formattedCredits), chalk.grey(\"AIGNE Hub credits\")];\n }\n\n formatTokenUsage(usage: Partial<ContextUsage>, extra?: { [key: string]: string }) {\n const items = [\n [chalk.yellow(usage.inputTokens), chalk.grey(\"input tokens\")],\n usage.cacheReadInputTokens\n ? [chalk.green(usage.cacheReadInputTokens), chalk.grey(\"cached\")]\n : undefined,\n usage.cacheCreationInputTokens\n ? [chalk.yellow(usage.cacheCreationInputTokens), chalk.grey(\"cache write\")]\n : undefined,\n [chalk.cyan(usage.outputTokens), chalk.grey(\"output tokens\")],\n usage.aigneHubCredits\n ? this.formatAigneHubCredits(usage.aigneHubCredits, usage.creditPrefix)\n : undefined,\n usage.agentCalls ? [chalk.magenta(usage.agentCalls), chalk.grey(\"agent calls\")] : undefined,\n ];\n\n const content = items.filter((i) => !!i).map((i) => i.join(\" \"));\n\n if (extra) {\n content.unshift(\n ...Object.entries(extra)\n .filter(([k, v]) => k && v)\n .map(([k, v]) => `${chalk.grey(k)}: ${v}`),\n );\n }\n\n return `${chalk.grey(\"(\")}${content.join(chalk.green(\", \"))}${chalk.grey(\")\")}`;\n }\n\n formatTimeUsage(startTime: number, endTime: number) {\n const duration = endTime - startTime;\n return chalk.grey(`[${parseDuration(duration)}]`);\n }\n\n get outputKey() {\n return this.options.outputKey || DEFAULT_OUTPUT_KEY;\n }\n\n get outputFileKey() {\n return this.options.outputFileKey || DEFAULT_OUTPUT_FILE_KEY;\n }\n\n formatRequest(agent: Agent, _context: Context, m: Message = {}, { running = false } = {}) {\n const prefix = `${chalk.grey(\"→\")} 💬 `;\n\n // For AIAgent, use its inputKey; for UserAgent, default to \"message\"\n const inputKey =\n agent instanceof AIAgent\n ? agent.inputKey\n : agent instanceof UserAgent\n ? \"message\"\n : undefined;\n\n const msg = inputKey ? m[inputKey] : undefined;\n const message = inputKey ? omit(m, inputKey) : m;\n\n const text =\n msg && typeof msg === \"string\" ? this.marked.parse(msg, { async: false }).trim() : undefined;\n\n const json =\n Object.keys(message).length > 0\n ? inspect(message, { colors: true, ...(running ? this.runningInspectOptions : undefined) })\n : undefined;\n\n const r = [text, json].filter(Boolean).join(EOL).trim();\n if (!r) return undefined;\n\n return `${prefix}${r}`;\n }\n\n formatResult(\n agent: Agent,\n context: Context,\n m: Message = {},\n { running = false, renderImage = false, streamed = false } = {},\n ): string | Promise<string> {\n const view = this.options.view;\n\n // Handle structured output modes (json, llm, default/machine-truth)\n if (view === \"json\") {\n return formatJSON(m);\n }\n\n if (view === \"llm\") {\n const fields = Object.keys(m);\n return formatLLMDSL(m, fields);\n }\n\n if (view === \"default\") {\n // Machine truth: just the main output value\n const outputKey = this.outputKey || (agent instanceof AIAgent ? agent.outputKey : undefined);\n const msg = outputKey ? m[outputKey] : undefined;\n if (msg && typeof msg === \"string\") {\n return msg;\n }\n // Fallback to JSON if no string output\n return JSON.stringify(m);\n }\n\n // Human view (default for TTY)\n const isTTY = this.isTTY;\n const outputKey = this.outputKey || (agent instanceof AIAgent ? agent.outputKey : undefined);\n\n const prefix = `${chalk.grey(\"✓\")} 🤖 ${this.formatTokenUsage(context.usage)}`;\n\n // When streaming, content was already printed via processStream\n // Only show the stats prefix line, no need to duplicate text or show JSON\n if (streamed) {\n if (renderImage) {\n return this.formatResultData(m).then((images) => {\n return [prefix, images].filter(Boolean).join(EOL.repeat(2));\n });\n }\n return prefix;\n }\n\n const msg = outputKey ? m[outputKey] : undefined;\n const message = outputKey ? omit(m, outputKey, this.outputFileKey) : m;\n\n const text =\n msg && typeof msg === \"string\"\n ? isTTY\n ? this.marked.parse(msg, { async: false }).trim()\n : msg\n : undefined;\n\n const json =\n Object.keys(message).length > 0\n ? inspect(message, { colors: isTTY, ...(running ? this.runningInspectOptions : undefined) })\n : undefined;\n\n if (renderImage) {\n return this.formatResultData(m).then((images) => {\n return [prefix, text, images, json].filter(Boolean).join(EOL.repeat(2));\n });\n }\n\n return [prefix, text, json].filter(Boolean).join(EOL.repeat(2));\n }\n\n async formatResultData(output: Message): Promise<string | undefined> {\n const files = output[this.outputFileKey] as FileUnionContent[];\n if (!Array.isArray(files)) return;\n\n const options: Parameters<typeof terminalImage.file>[1] = {\n height: 30,\n };\n\n return (\n await Promise.all(\n files.map(async (item) => {\n const image =\n item.type === \"local\"\n ? await terminalImage.file(item.path, options)\n : item.type === \"file\"\n ? await terminalImage.buffer(Buffer.from(item.data, \"base64\"), options)\n : undefined;\n\n const link =\n item.type === \"local\"\n ? withProtocol(item.path, \"file://\")\n : item.type === \"url\"\n ? item.url\n : undefined;\n const text = [\n link ? chalk.cyan(terminalLink(link, link)) : undefined,\n item.filename,\n item.mimeType ? chalk.gray(item.mimeType) : undefined,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return [image, text].filter(Boolean).join(EOL);\n }),\n )\n )\n .filter(Boolean)\n .join(EOL);\n }\n\n protected runningInspectOptions: InspectOptions = {\n maxArrayLength: 3,\n maxStringLength: 200,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
let chalk = require("chalk");
|
|
3
|
+
chalk = require_rolldown_runtime.__toESM(chalk);
|
|
4
|
+
let ink = require("ink");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
|
|
8
|
+
//#region src/ui/utils/terminal-select.tsx
|
|
9
|
+
async function terminalSelect({ render: r = ink.render, message, choices, clear = true }) {
|
|
10
|
+
if (process.stdin.isTTY) {
|
|
11
|
+
process.stdin.resume();
|
|
12
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(false);
|
|
13
|
+
}
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const handleSigInt = () => {
|
|
16
|
+
reject(/* @__PURE__ */ new Error("Selection aborted"));
|
|
17
|
+
};
|
|
18
|
+
process.addListener("SIGINT", handleSigInt);
|
|
19
|
+
const clean = () => process.removeListener("SIGINT", handleSigInt);
|
|
20
|
+
const app = r(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TerminalSelect, {
|
|
21
|
+
message,
|
|
22
|
+
choices,
|
|
23
|
+
onSubmit: (value) => {
|
|
24
|
+
if (clear) app.clear();
|
|
25
|
+
app.unmount();
|
|
26
|
+
resolve(value);
|
|
27
|
+
clean();
|
|
28
|
+
},
|
|
29
|
+
onCancel: () => {
|
|
30
|
+
if (clear) app.clear();
|
|
31
|
+
app.unmount();
|
|
32
|
+
reject(/* @__PURE__ */ new Error("Selection cancelled"));
|
|
33
|
+
clean();
|
|
34
|
+
}
|
|
35
|
+
}), { exitOnCtrlC: false });
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function TerminalSelect(props) {
|
|
39
|
+
const [selectedIndex, setSelectedIndex] = (0, react.useState)(0);
|
|
40
|
+
(0, ink.useInput)((input, key) => {
|
|
41
|
+
if (input === "c" && key.ctrl) {
|
|
42
|
+
props.onCancel();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (key.upArrow) setSelectedIndex((prev) => prev > 0 ? prev - 1 : props.choices.length - 1);
|
|
46
|
+
else if (key.downArrow) setSelectedIndex((prev) => prev < props.choices.length - 1 ? prev + 1 : 0);
|
|
47
|
+
else if (key.return) {
|
|
48
|
+
const choice = props.choices[selectedIndex];
|
|
49
|
+
if (choice) props.onSubmit(choice.value);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Box, {
|
|
53
|
+
flexDirection: "column",
|
|
54
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Text, { children: [
|
|
55
|
+
chalk.default.cyan("?"),
|
|
56
|
+
" ",
|
|
57
|
+
chalk.default.bold(props.message),
|
|
58
|
+
" ",
|
|
59
|
+
chalk.default.gray("(Use arrow keys)")
|
|
60
|
+
] }), props.choices.map((choice, index) => {
|
|
61
|
+
const isSelected = index === selectedIndex;
|
|
62
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Text, { children: [
|
|
63
|
+
isSelected ? chalk.default.cyan("❯") : " ",
|
|
64
|
+
" ",
|
|
65
|
+
isSelected ? chalk.default.cyan(choice.name) : choice.name,
|
|
66
|
+
choice.description ? chalk.default.gray(` - ${choice.description}`) : ""
|
|
67
|
+
] }, choice.value);
|
|
68
|
+
})]
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
exports.terminalSelect = terminalSelect;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { Box, Text, render, useInput } from "ink";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/ui/utils/terminal-select.tsx
|
|
7
|
+
async function terminalSelect({ render: r = render, message, choices, clear = true }) {
|
|
8
|
+
if (process.stdin.isTTY) {
|
|
9
|
+
process.stdin.resume();
|
|
10
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(false);
|
|
11
|
+
}
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const handleSigInt = () => {
|
|
14
|
+
reject(/* @__PURE__ */ new Error("Selection aborted"));
|
|
15
|
+
};
|
|
16
|
+
process.addListener("SIGINT", handleSigInt);
|
|
17
|
+
const clean = () => process.removeListener("SIGINT", handleSigInt);
|
|
18
|
+
const app = r(/* @__PURE__ */ jsx(TerminalSelect, {
|
|
19
|
+
message,
|
|
20
|
+
choices,
|
|
21
|
+
onSubmit: (value) => {
|
|
22
|
+
if (clear) app.clear();
|
|
23
|
+
app.unmount();
|
|
24
|
+
resolve(value);
|
|
25
|
+
clean();
|
|
26
|
+
},
|
|
27
|
+
onCancel: () => {
|
|
28
|
+
if (clear) app.clear();
|
|
29
|
+
app.unmount();
|
|
30
|
+
reject(/* @__PURE__ */ new Error("Selection cancelled"));
|
|
31
|
+
clean();
|
|
32
|
+
}
|
|
33
|
+
}), { exitOnCtrlC: false });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function TerminalSelect(props) {
|
|
37
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
38
|
+
useInput((input, key) => {
|
|
39
|
+
if (input === "c" && key.ctrl) {
|
|
40
|
+
props.onCancel();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (key.upArrow) setSelectedIndex((prev) => prev > 0 ? prev - 1 : props.choices.length - 1);
|
|
44
|
+
else if (key.downArrow) setSelectedIndex((prev) => prev < props.choices.length - 1 ? prev + 1 : 0);
|
|
45
|
+
else if (key.return) {
|
|
46
|
+
const choice = props.choices[selectedIndex];
|
|
47
|
+
if (choice) props.onSubmit(choice.value);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
51
|
+
flexDirection: "column",
|
|
52
|
+
children: [/* @__PURE__ */ jsxs(Text, { children: [
|
|
53
|
+
chalk.cyan("?"),
|
|
54
|
+
" ",
|
|
55
|
+
chalk.bold(props.message),
|
|
56
|
+
" ",
|
|
57
|
+
chalk.gray("(Use arrow keys)")
|
|
58
|
+
] }), props.choices.map((choice, index) => {
|
|
59
|
+
const isSelected = index === selectedIndex;
|
|
60
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
61
|
+
isSelected ? chalk.cyan("❯") : " ",
|
|
62
|
+
" ",
|
|
63
|
+
isSelected ? chalk.cyan(choice.name) : choice.name,
|
|
64
|
+
choice.description ? chalk.gray(` - ${choice.description}`) : ""
|
|
65
|
+
] }, choice.value);
|
|
66
|
+
})]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { terminalSelect };
|
|
72
|
+
//# sourceMappingURL=terminal-select.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-select.mjs","names":[],"sources":["../../../src/ui/utils/terminal-select.tsx"],"sourcesContent":["import chalk from \"chalk\";\nimport { Box, render, Text, useInput } from \"ink\";\nimport { useState } from \"react\";\n\nexport interface SelectChoice {\n name: string;\n value: string;\n description?: string;\n}\n\nexport async function terminalSelect({\n render: r = render,\n message,\n choices,\n clear = true,\n}: {\n message: string;\n choices: SelectChoice[];\n render?: typeof render;\n clear?: boolean;\n}): Promise<string> {\n // Ensure stdin is ready for Ink (previous Ink app may have left it in a bad state)\n if (process.stdin.isTTY) {\n process.stdin.resume();\n // Ensure raw mode is off so Ink can set it up fresh\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(false);\n }\n }\n\n return new Promise<string>((resolve, reject) => {\n const handleSigInt = () => {\n reject(new Error(\"Selection aborted\"));\n };\n process.addListener(\"SIGINT\", handleSigInt);\n const clean = () => process.removeListener(\"SIGINT\", handleSigInt);\n\n const app = r(\n <TerminalSelect\n message={message}\n choices={choices}\n onSubmit={(value) => {\n if (clear) app.clear();\n app.unmount();\n resolve(value);\n clean();\n }}\n onCancel={() => {\n if (clear) app.clear();\n app.unmount();\n reject(new Error(\"Selection cancelled\"));\n clean();\n }}\n />,\n { exitOnCtrlC: false },\n );\n });\n}\n\nfunction TerminalSelect(props: {\n message: string;\n choices: SelectChoice[];\n onSubmit: (value: string) => void;\n onCancel: () => void;\n}) {\n const [selectedIndex, setSelectedIndex] = useState(0);\n\n useInput((input, key) => {\n if (input === \"c\" && key.ctrl) {\n props.onCancel();\n return;\n }\n\n if (key.upArrow) {\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : props.choices.length - 1));\n } else if (key.downArrow) {\n setSelectedIndex((prev) => (prev < props.choices.length - 1 ? prev + 1 : 0));\n } else if (key.return) {\n const choice = props.choices[selectedIndex];\n if (choice) {\n props.onSubmit(choice.value);\n }\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <Text>\n {chalk.cyan(\"?\")} {chalk.bold(props.message)} {chalk.gray(\"(Use arrow keys)\")}\n </Text>\n {props.choices.map((choice, index) => {\n const isSelected = index === selectedIndex;\n const prefix = isSelected ? chalk.cyan(\"❯\") : \" \";\n const text = isSelected ? chalk.cyan(choice.name) : choice.name;\n const desc = choice.description ? chalk.gray(` - ${choice.description}`) : \"\";\n return (\n <Text key={choice.value}>\n {prefix} {text}\n {desc}\n </Text>\n );\n })}\n </Box>\n );\n}\n"],"mappings":";;;;;;AAUA,eAAsB,eAAe,EACnC,QAAQ,IAAI,QACZ,SACA,SACA,QAAQ,QAMU;AAElB,KAAI,QAAQ,MAAM,OAAO;AACvB,UAAQ,MAAM,QAAQ;AAEtB,MAAI,QAAQ,MAAM,WAChB,SAAQ,MAAM,WAAW,MAAM;;AAInC,QAAO,IAAI,SAAiB,SAAS,WAAW;EAC9C,MAAM,qBAAqB;AACzB,0BAAO,IAAI,MAAM,oBAAoB,CAAC;;AAExC,UAAQ,YAAY,UAAU,aAAa;EAC3C,MAAM,cAAc,QAAQ,eAAe,UAAU,aAAa;EAElE,MAAM,MAAM,EACV,oBAAC;GACU;GACA;GACT,WAAW,UAAU;AACnB,QAAI,MAAO,KAAI,OAAO;AACtB,QAAI,SAAS;AACb,YAAQ,MAAM;AACd,WAAO;;GAET,gBAAgB;AACd,QAAI,MAAO,KAAI,OAAO;AACtB,QAAI,SAAS;AACb,2BAAO,IAAI,MAAM,sBAAsB,CAAC;AACxC,WAAO;;IAET,EACF,EAAE,aAAa,OAAO,CACvB;GACD;;AAGJ,SAAS,eAAe,OAKrB;CACD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;AAErD,WAAU,OAAO,QAAQ;AACvB,MAAI,UAAU,OAAO,IAAI,MAAM;AAC7B,SAAM,UAAU;AAChB;;AAGF,MAAI,IAAI,QACN,mBAAkB,SAAU,OAAO,IAAI,OAAO,IAAI,MAAM,QAAQ,SAAS,EAAG;WACnE,IAAI,UACb,mBAAkB,SAAU,OAAO,MAAM,QAAQ,SAAS,IAAI,OAAO,IAAI,EAAG;WACnE,IAAI,QAAQ;GACrB,MAAM,SAAS,MAAM,QAAQ;AAC7B,OAAI,OACF,OAAM,SAAS,OAAO,MAAM;;GAGhC;AAEF,QACE,qBAAC;EAAI,eAAc;aACjB,qBAAC;GACE,MAAM,KAAK,IAAI;GAAC;GAAE,MAAM,KAAK,MAAM,QAAQ;GAAC;GAAE,MAAM,KAAK,mBAAmB;MACxE,EACN,MAAM,QAAQ,KAAK,QAAQ,UAAU;GACpC,MAAM,aAAa,UAAU;AAI7B,UACE,qBAAC;IAJY,aAAa,MAAM,KAAK,IAAI,GAAG;IAKlC;IAJC,aAAa,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;IAC9C,OAAO,cAAc,MAAM,KAAK,MAAM,OAAO,cAAc,GAAG;QAE9D,OAAO,MAGX;IAET;GACE"}
|
package/dist/utils/agent-v1.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
-
let node_path = require("node:path");
|
|
3
2
|
let node_fs_promises = require("node:fs/promises");
|
|
4
|
-
let
|
|
3
|
+
let node_path = require("node:path");
|
|
5
4
|
let glob = require("glob");
|
|
5
|
+
let yaml = require("yaml");
|
|
6
6
|
|
|
7
7
|
//#region src/utils/agent-v1.ts
|
|
8
8
|
async function isV1Package(src) {
|
package/dist/utils/agent-v1.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
-
import {
|
|
2
|
+
import { join } from "node:path";
|
|
4
3
|
import { glob } from "glob";
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
5
|
|
|
6
6
|
//#region src/utils/agent-v1.ts
|
|
7
7
|
async function isV1Package(src) {
|