u1s1-cli 0.16.4 → 0.16.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/loop.js +9 -5
- package/dist/tools.d.ts +2 -10
- package/dist/tools.js +50 -0
- package/package.json +1 -1
package/dist/loop.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* /loop 20m /review-pr 1234 循环里也能跑其他斜杠命令
|
|
9
9
|
* /loop stop 停止当前循环
|
|
10
10
|
*
|
|
11
|
-
* 语义与 Claude Code 对齐:任务只活在当前会话,/clear
|
|
12
|
-
*
|
|
11
|
+
* 语义与 Claude Code 对齐:任务只活在当前会话,/clear 或退出即消失;
|
|
12
|
+
* 启动时立刻跑第一轮,之后每隔一个间隔再跑。
|
|
13
|
+
* 实现核心是 pi.sendUserMessage():到点就"替用户打字"发一轮,
|
|
13
14
|
* deliverAs: "followUp" 保证上一轮没跑完时排队等它结束,不硬插打断;
|
|
14
15
|
* expandPromptTemplates: true 让 prompt 里的斜杠命令也能被展开执行。
|
|
15
16
|
*/
|
|
@@ -116,7 +117,7 @@ export function registerLoopCommand(pi) {
|
|
|
116
117
|
stopLoop(ctx.ui);
|
|
117
118
|
activePrompt = parsed.prompt;
|
|
118
119
|
activeIntervalMs = parsed.intervalMs;
|
|
119
|
-
|
|
120
|
+
const fire = () => {
|
|
120
121
|
try {
|
|
121
122
|
pi.sendUserMessage(activePrompt, {
|
|
122
123
|
deliverAs: "followUp",
|
|
@@ -126,9 +127,12 @@ export function registerLoopCommand(pi) {
|
|
|
126
127
|
catch (e) {
|
|
127
128
|
ctx.ui.notify(`loop 执行失败: ${e instanceof Error ? e.message : String(e)}`, "error");
|
|
128
129
|
}
|
|
129
|
-
}
|
|
130
|
+
};
|
|
131
|
+
// 第一轮立刻跑:用户写完命令就想看到结果,不该干等一个间隔
|
|
132
|
+
fire();
|
|
133
|
+
timer = setInterval(fire, activeIntervalMs);
|
|
130
134
|
ctx.ui.setStatus(STATUS_KEY, `🔁 每${formatInterval(activeIntervalMs)} · ${preview(activePrompt)}`);
|
|
131
|
-
ctx.ui.notify(`🔁
|
|
135
|
+
ctx.ui.notify(`🔁 已开始:现在先跑第一轮,之后每${formatInterval(activeIntervalMs)}一次「${preview(activePrompt)}」`, "info");
|
|
132
136
|
},
|
|
133
137
|
});
|
|
134
138
|
}
|
package/dist/tools.d.ts
CHANGED
|
@@ -4,10 +4,7 @@ import type { CliConfig } from "./config.js";
|
|
|
4
4
|
export declare function createSearchTool(cfg: Pick<CliConfig, "baseUrl" | "apiKey">): import("@earendil-works/pi-coding-agent").ToolDefinition<Type.TObject<{
|
|
5
5
|
query: Type.TString;
|
|
6
6
|
maxResults: Type.TOptional<Type.TNumber>;
|
|
7
|
-
}>,
|
|
8
|
-
query: string;
|
|
9
|
-
count: number;
|
|
10
|
-
}, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
|
7
|
+
}>, unknown, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
|
11
8
|
/** 生图工具:走 u1s1 网关代理火山方舟 Seedream,上游 key 不落到用户机器上。 */
|
|
12
9
|
export declare function createImageTool(cfg: Pick<CliConfig, "baseUrl" | "apiKey">): import("@earendil-works/pi-coding-agent").ToolDefinition<Type.TObject<{
|
|
13
10
|
prompt: Type.TString;
|
|
@@ -31,9 +28,4 @@ export interface FetchToolConfig {
|
|
|
31
28
|
*/
|
|
32
29
|
export declare function createFetchTool(cfg: FetchToolConfig): import("@earendil-works/pi-coding-agent").ToolDefinition<Type.TObject<{
|
|
33
30
|
url: Type.TString;
|
|
34
|
-
}>,
|
|
35
|
-
url: string;
|
|
36
|
-
contentType: string;
|
|
37
|
-
via: "direct" | "render";
|
|
38
|
-
chars: number;
|
|
39
|
-
}, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
|
31
|
+
}>, unknown, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
package/dist/tools.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, extname, resolve } from "node:path";
|
|
3
3
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { Text } from "@earendil-works/pi-tui";
|
|
4
5
|
import { Type } from "typebox";
|
|
5
6
|
import { generateImage, renderPage, searchWeb } from "./api.js";
|
|
6
7
|
const FETCH_TIMEOUT_MS = 20_000;
|
|
@@ -75,6 +76,32 @@ function decodeBody(bytes, contentType) {
|
|
|
75
76
|
return new TextDecoder("utf-8").decode(bytes);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
79
|
+
/** 压成单行并截断,给联网工具的精简展示用 */
|
|
80
|
+
function previewLine(text, max = 100) {
|
|
81
|
+
const flat = String(text).replace(/\s*\n\s*/g, " ").trim();
|
|
82
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
83
|
+
}
|
|
84
|
+
/** 从工具结果里取纯文本内容 */
|
|
85
|
+
function resultText(result) {
|
|
86
|
+
const c = result.content.find((x) => x.type === "text");
|
|
87
|
+
return c && c.type === "text" ? (c.text ?? "") : "";
|
|
88
|
+
}
|
|
89
|
+
/** 联网工具通用渲染:调用行不占位,收起时只显一行摘要,ctrl+o 展开全文,出错显一行 ✗ */
|
|
90
|
+
function compactResultRender(result, options,
|
|
91
|
+
// 放宽成 any 只为避开 pi 的 ThemeColor 联合类型在结构化匹配时的逆变报错;
|
|
92
|
+
// 实际传入的就是 pi 的 Theme,取值只用 "warning"/"muted" 两色
|
|
93
|
+
theme, context, summaryLine) {
|
|
94
|
+
if (context.isError) {
|
|
95
|
+
// 低调处理:✗ 用警示色,内容用灰色弱化(与内置工具的错误展示一致)
|
|
96
|
+
const msg = previewLine(resultText(result) || "error", 160);
|
|
97
|
+
return new Text(theme.fg("warning", "✗ ") + theme.fg("muted", msg), 0, 0);
|
|
98
|
+
}
|
|
99
|
+
if (!options.expanded) {
|
|
100
|
+
return new Text(theme.fg("muted", summaryLine), 0, 0);
|
|
101
|
+
}
|
|
102
|
+
const text = resultText(result);
|
|
103
|
+
return new Text(text, 0, 0);
|
|
104
|
+
}
|
|
78
105
|
/** 联网搜索工具:走 u1s1 网关代理,上游 key 不落到用户机器上。 */
|
|
79
106
|
export function createSearchTool(cfg) {
|
|
80
107
|
return defineTool({
|
|
@@ -90,6 +117,17 @@ export function createSearchTool(cfg) {
|
|
|
90
117
|
query: Type.String({ description: "Search query. Be specific; keep it under ~15 words." }),
|
|
91
118
|
maxResults: Type.Optional(Type.Number({ description: "How many results to return (1-10, default 5).", minimum: 1, maximum: 10 })),
|
|
92
119
|
}),
|
|
120
|
+
// 精简展示:收起时一行摘要(🔍 搜索 "…" · N 条结果),ctrl+o 展开全文
|
|
121
|
+
renderShell: "self",
|
|
122
|
+
renderCall() {
|
|
123
|
+
return new Text("", 0, 0);
|
|
124
|
+
},
|
|
125
|
+
renderResult(result, options, theme, context) {
|
|
126
|
+
const d = result.details;
|
|
127
|
+
const q = d?.query ? `"${previewLine(d.query, 80)}"` : "…";
|
|
128
|
+
const n = typeof d?.count === "number" ? ` · ${d.count} 条结果` : "";
|
|
129
|
+
return compactResultRender(result, options, theme, context, `🔍 搜索 ${q}${n}`);
|
|
130
|
+
},
|
|
93
131
|
async execute(_toolCallId, params, signal) {
|
|
94
132
|
const data = await searchWeb(cfg, params.query, params.maxResults, signal);
|
|
95
133
|
const lines = [];
|
|
@@ -275,6 +313,18 @@ export function createFetchTool(cfg) {
|
|
|
275
313
|
parameters: Type.Object({
|
|
276
314
|
url: Type.String({ description: "Absolute http(s) URL to fetch." }),
|
|
277
315
|
}),
|
|
316
|
+
// 精简展示:收起时一行摘要(🌐 url · N 字符 · ☁ 渲染),ctrl+o 展开全文
|
|
317
|
+
renderShell: "self",
|
|
318
|
+
renderCall() {
|
|
319
|
+
return new Text("", 0, 0);
|
|
320
|
+
},
|
|
321
|
+
renderResult(result, options, theme, context) {
|
|
322
|
+
const d = result.details;
|
|
323
|
+
const u = previewLine(d?.url ?? "…", 90);
|
|
324
|
+
const n = typeof d?.chars === "number" ? ` · ${d.chars} 字符` : "";
|
|
325
|
+
const cloud = d?.via === "render" ? " · ☁ 浏览器渲染" : "";
|
|
326
|
+
return compactResultRender(result, options, theme, context, `🌐 ${u}${n}${cloud}`);
|
|
327
|
+
},
|
|
278
328
|
async execute(_toolCallId, params, signal) {
|
|
279
329
|
let url;
|
|
280
330
|
try {
|