@trim21/personal-pi-extensions 0.1.681 → 0.1.684
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 +13 -9
- package/package.json +1 -1
- package/src/aft/schemas.ts +246 -0
- package/src/aft/tools.ts +275 -235
- package/src/claude-code/shell.ts +167 -96
- package/src/codemode/tool.ts +8 -1
- package/src/opencode/bash.ts +158 -105
package/README.md
CHANGED
|
@@ -36,10 +36,12 @@
|
|
|
36
36
|
- **嵌套调用经工具总线**:`call("Bash", { command })` 最终执行的是 `Bash` 工具自己的
|
|
37
37
|
`execute`,所以工具的审批照常生效(Bash 沙箱外执行会弹自己的提权确认)。codemode
|
|
38
38
|
不额外加确认层:脚本里连发十次调用就是十次工具自己的审批(需要审批的那些)。
|
|
39
|
-
- **可调用集合** =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
- **可调用集合** = 总线上实际注册的工具减去排除名单,执行时再与当前 active 列表求交,
|
|
40
|
+
所以 `personalExtensions.disabledTools`、pi 的 `defaultTools` / `--tools`、子代理的工具
|
|
41
|
+
白名单都同样约束脚本。排除名单:`codemode` 自身与 `spawn-agent`;两套文件工具集的
|
|
42
|
+
读写工具(`Read`/`Edit`/`Write` 与 `read`/`edit`/`write`);两套工具集的搜索工具
|
|
43
|
+
(`Grep`/`Glob` 与 `grep`/`glob`)——脚本搜文件用 `call("Bash", { command: "rg …" })`,
|
|
44
|
+
走同一个沙箱、拿得到退出码,还能拼管道,而那两个工具是给模型看结果的。
|
|
43
45
|
- **文件读写只有 `fs` 一条路**:`fs.read(path)` 返回文件全文的原始 UTF-8 文本(不加行号、
|
|
44
46
|
不截断、不设大小上限,只有内容不是合法 UTF-8 时报错),`fs.write(path, content)` 整体写入并自动创建
|
|
45
47
|
父目录,相对路径相对当前 cwd。`fs.write` 与写类工具共用同一套保护:写前要求「已读且读后
|
|
@@ -49,10 +51,12 @@
|
|
|
49
51
|
直接改,不进脚本)。
|
|
50
52
|
- **只有脚本输出进上下文**:`text(value)` / `console.log(...)` 与 `return` 值进入工具结果,
|
|
51
53
|
中间的工具调用与它们的返回内容不会(也不在会话记录里留下工具调用条目)。
|
|
52
|
-
- **返回值**:声明了 `structuredSchema`
|
|
53
|
-
|
|
54
|
-
`
|
|
55
|
-
|
|
54
|
+
- **返回值**:声明了 `structuredSchema` 的工具把结果放在 `structuredResult` 里,`call()`
|
|
55
|
+
解包成对象给脚本——gh-readonly 的读类工具给解析后的 JSON,`Bash` / `bash` 给
|
|
56
|
+
`{ exitCode, output }`(`exitCode` 为 `null` 表示命令被超时/中止杀掉;命令非零退出是正常
|
|
57
|
+
结果,直接读 `exitCode` 分支即可)。`{ ok: false, error }` 会 reject 成 `CallFailedError`
|
|
58
|
+
(脚本可按 `instanceof CallFailedError` 区分调用失败与自身运行期错误)。没有声明输出
|
|
59
|
+
结构的工具回退成工具输出的文本。
|
|
56
60
|
- **脚本接口**:`call` / `CallFailedError` / `ALL_TOOLS` / `fs.read` / `fs.write` /
|
|
57
61
|
`text` / `image` / `exit` / `console.*` / `store.set` / `store.get` / `store.list`
|
|
58
62
|
(会话内持久的键值表);首行可选 `// @options: {"max_output_tokens": 10000}`。
|
|
@@ -425,7 +429,7 @@ Claude Code 风格工具集:`Read` / `Edit` / `Write` / `Grep` / `Glob` / `Bas
|
|
|
425
429
|
|
|
426
430
|
- **`Read` / `Edit` / `Write`**:与 opencode 风格共享 read-before-write 记账与文案(`File has not been read yet...` / `File has been modified since read...`),差异是三者都要求先 `Read`(`Edit` 用空 `old_string` 创建新文件、`Write` 创建新文件例外)。`Read` 支持 offset / limit 分页与 PDF `pages`
|
|
427
431
|
- **`Grep` / `Glob`**:ripgrep 实现,行为跟随 Claude Code(`Glob` 带 `--no-ignore` / `--hidden` / `--sort=modified`,与 opencode 风格 `glob` 的差异是各自跟随上游)
|
|
428
|
-
- **`Bash`**:与 opencode 风格 `bash` 共享 bwrap 运行时与 `dangerouslyDisableSandbox` 提权,默认超时 120
|
|
432
|
+
- **`Bash`**:与 opencode 风格 `bash` 共享 bwrap 运行时与 `dangerouslyDisableSandbox` 提权,默认超时 120 秒,只支持同步执行。结构化结果给 `{ exitCode, output }`:`output` 是命令的**完整**输出(文本该截断还截断,载荷里是全文),`exitCode` 为 `null` 表示被超时/中止杀掉;命令非零退出不是失败,脚本直接读 `exitCode` 分支
|
|
429
433
|
- **`TodoWrite`**:任务列表工具(`merge` 语义),与 opencode 风格 `todowrite` 的完整替换语义不同,不要混用
|
|
430
434
|
- **`AskUserQuestion`**:阻塞式向用户提问
|
|
431
435
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AFT 感知工具的结构化结果 schema。
|
|
3
|
+
*
|
|
4
|
+
* 载荷就是引擎自己的响应字段(去掉 envelope 的 request id),外加一个 `text`——我们自己
|
|
5
|
+
* 渲染(或引擎渲染)的文本,与工具输出一致。字段名与类型来自三处证据:
|
|
6
|
+
*
|
|
7
|
+
* - 本仓库对真引擎的实测响应(outline 两种模式、zoom,见 `test/fixtures/aft/`);
|
|
8
|
+
* - `@cortexkit/aft-bridge` 自己的格式化器读哪些字段(callgraph 各 op、zoom 的注解);
|
|
9
|
+
* - 引擎的 `ListEnvelope` / 截断字段(walk_truncated、collection_truncated、truncated)。
|
|
10
|
+
*
|
|
11
|
+
* 两条刻意的宽松:
|
|
12
|
+
*
|
|
13
|
+
* 1. 所有引擎字段都是可选、且允许额外字段(`additionalProperties: true`)。引擎不归我们
|
|
14
|
+
* 管,它的响应会加字段、换字段名;声明成必需会让版本一升级就把工具调用变成失败。
|
|
15
|
+
* 2. 嵌套条目(callgraph 的调用点、搜索命中等)把已知字段列全但全部可选——引擎自己也用
|
|
16
|
+
* `?? "(unknown)"` 兜底,说明这些字段并非永远在场。
|
|
17
|
+
*
|
|
18
|
+
* 载荷只经总线 `Value.Parse` 复核一次(见 `src/lib/tool-bus.ts`),因此「宽松」不等于
|
|
19
|
+
* 不校验:`text` 必需,列出的字段类型必须对得上。
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Type } from "typebox";
|
|
23
|
+
|
|
24
|
+
/** 引擎渲染的文本,与工具输出一致。 */
|
|
25
|
+
const text = Type.String({ description: "引擎渲染的文本,与工具输出一致" });
|
|
26
|
+
|
|
27
|
+
/** 行号区间(zoom):引擎的 Range 序列化时行号从 1 开始。 */
|
|
28
|
+
const rangeSchema = Type.Object(
|
|
29
|
+
{
|
|
30
|
+
start_line: Type.Number(),
|
|
31
|
+
end_line: Type.Number(),
|
|
32
|
+
start_col: Type.Optional(Type.Number()),
|
|
33
|
+
end_col: Type.Optional(Type.Number()),
|
|
34
|
+
},
|
|
35
|
+
{ additionalProperties: true },
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
/** 调用图注解里的一条引用(zoom 的 calls_out / called_by)。 */
|
|
39
|
+
const callRefSchema = Type.Object(
|
|
40
|
+
{
|
|
41
|
+
name: Type.String(),
|
|
42
|
+
line: Type.Number(),
|
|
43
|
+
/** 同一行上还有多少条同类引用被折叠。 */
|
|
44
|
+
extra_count: Type.Optional(Type.Number()),
|
|
45
|
+
},
|
|
46
|
+
{ additionalProperties: true },
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
/** `aft_outline`:单文件模式只有 text(引擎不返回符号树),files 模式带文件条目。 */
|
|
50
|
+
export const aftOutlineStructuredSchema = Type.Object(
|
|
51
|
+
{
|
|
52
|
+
text,
|
|
53
|
+
/** 引擎是否确定给全了结果。 */
|
|
54
|
+
complete: Type.Optional(Type.Boolean()),
|
|
55
|
+
/** files 模式(目录 + files: true)的文件条目。 */
|
|
56
|
+
files: Type.Optional(
|
|
57
|
+
Type.Array(
|
|
58
|
+
Type.Object(
|
|
59
|
+
{
|
|
60
|
+
path: Type.String(),
|
|
61
|
+
language: Type.String(),
|
|
62
|
+
/** 顶层符号数;未知时引擎省略该字段。 */
|
|
63
|
+
symbols: Type.Optional(Type.Number()),
|
|
64
|
+
/** 行数;null 表示不在索引里(line_count_gaps 列出这些文件)。 */
|
|
65
|
+
lines: Type.Union([Type.Number(), Type.Null()]),
|
|
66
|
+
},
|
|
67
|
+
{ additionalProperties: true },
|
|
68
|
+
),
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
/** 目录遍历触到上限。 */
|
|
72
|
+
walk_truncated: Type.Optional(Type.Boolean()),
|
|
73
|
+
/** 条目收集触到上限。 */
|
|
74
|
+
collection_truncated: Type.Optional(Type.Boolean()),
|
|
75
|
+
},
|
|
76
|
+
{ additionalProperties: true },
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
/** `aft_zoom`:单符号源码 + 行号区间 + 同文件调用注解。 */
|
|
80
|
+
export const aftZoomStructuredSchema = Type.Object(
|
|
81
|
+
{
|
|
82
|
+
text,
|
|
83
|
+
/** 符号名;行范围模式是 "lines X-Y",符号歧义时缺省。 */
|
|
84
|
+
name: Type.Optional(Type.String()),
|
|
85
|
+
/** function / class / method / lines / ambiguous_symbol … */
|
|
86
|
+
kind: Type.Optional(Type.String()),
|
|
87
|
+
range: Type.Optional(rangeSchema),
|
|
88
|
+
/** 符号源码(不含上下文行)。 */
|
|
89
|
+
content: Type.Optional(Type.String()),
|
|
90
|
+
context_before: Type.Optional(Type.Array(Type.String())),
|
|
91
|
+
context_after: Type.Optional(Type.Array(Type.String())),
|
|
92
|
+
annotations: Type.Optional(
|
|
93
|
+
Type.Object(
|
|
94
|
+
{
|
|
95
|
+
calls_out: Type.Optional(Type.Array(callRefSchema)),
|
|
96
|
+
called_by: Type.Optional(Type.Array(callRefSchema)),
|
|
97
|
+
},
|
|
98
|
+
{ additionalProperties: true },
|
|
99
|
+
),
|
|
100
|
+
),
|
|
101
|
+
},
|
|
102
|
+
{ additionalProperties: true },
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
/** 调用图上的一条位置(callers 的调用点、impact 的受害点)。 */
|
|
106
|
+
const callgraphSiteSchema = Type.Object(
|
|
107
|
+
{
|
|
108
|
+
file: Type.Optional(Type.String()),
|
|
109
|
+
line: Type.Optional(Type.Number()),
|
|
110
|
+
/** callers 分组的调用符号名。 */
|
|
111
|
+
symbol: Type.Optional(Type.String()),
|
|
112
|
+
/** impact 的调用点符号名(与 caller_file 成对)。 */
|
|
113
|
+
caller_symbol: Type.Optional(Type.String()),
|
|
114
|
+
caller_file: Type.Optional(Type.String()),
|
|
115
|
+
/** impact:该调用点自身是入口(脚本常据此过滤)。 */
|
|
116
|
+
is_entry_point: Type.Optional(Type.Boolean()),
|
|
117
|
+
/** 仅按名字解析出来的边(可能指向同名符号)。 */
|
|
118
|
+
approximate: Type.Optional(Type.Boolean()),
|
|
119
|
+
/** "name_match" 等解析来源。 */
|
|
120
|
+
resolved_by: Type.Optional(Type.String()),
|
|
121
|
+
},
|
|
122
|
+
{ additionalProperties: true },
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
/** 调用链上的一跳(trace_to / trace_to_symbol)。 */
|
|
126
|
+
const callgraphHopSchema = Type.Object(
|
|
127
|
+
{
|
|
128
|
+
symbol: Type.Optional(Type.String()),
|
|
129
|
+
file: Type.Optional(Type.String()),
|
|
130
|
+
line: Type.Optional(Type.Number()),
|
|
131
|
+
is_entry_point: Type.Optional(Type.Boolean()),
|
|
132
|
+
/** trace_data:该跳流转的变量名与流向。 */
|
|
133
|
+
variable: Type.Optional(Type.String()),
|
|
134
|
+
flow_type: Type.Optional(Type.String()),
|
|
135
|
+
approximate: Type.Optional(Type.Boolean()),
|
|
136
|
+
resolved_by: Type.Optional(Type.String()),
|
|
137
|
+
},
|
|
138
|
+
{ additionalProperties: true },
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* `aft_callgraph`:一个工具名下 6 个 op,响应形状各不同(callers 是分组列表、call_tree 是
|
|
143
|
+
* 树、impact 是扁平调用点、trace_to 是路径列表、trace_to_symbol 是单条路径、trace_data 是
|
|
144
|
+
* 数据流跳)。这里把各 op 的锚点与列表都列为可选字段,脚本按 op 取用。
|
|
145
|
+
*/
|
|
146
|
+
export const aftCallgraphStructuredSchema = Type.Object(
|
|
147
|
+
{
|
|
148
|
+
text,
|
|
149
|
+
/** 被查询的符号(callers / impact 的锚点)。 */
|
|
150
|
+
symbol: Type.Optional(Type.String()),
|
|
151
|
+
file: Type.Optional(Type.String()),
|
|
152
|
+
/** call_tree 根节点的锚点。 */
|
|
153
|
+
name: Type.Optional(Type.String()),
|
|
154
|
+
line: Type.Optional(Type.Number()),
|
|
155
|
+
signature: Type.Optional(Type.String()),
|
|
156
|
+
/** callers:按文件分组的调用点。 */
|
|
157
|
+
callers: Type.Optional(
|
|
158
|
+
Type.Array(
|
|
159
|
+
Type.Object(
|
|
160
|
+
{
|
|
161
|
+
file: Type.Optional(Type.String()),
|
|
162
|
+
callers: Type.Optional(Type.Array(callgraphSiteSchema)),
|
|
163
|
+
},
|
|
164
|
+
{ additionalProperties: true },
|
|
165
|
+
),
|
|
166
|
+
),
|
|
167
|
+
),
|
|
168
|
+
/** call_tree 根节点的直接子节点(整棵树在 payload 里,这里只标出形状)。 */
|
|
169
|
+
children: Type.Optional(Type.Array(Type.Unknown())),
|
|
170
|
+
/** call_tree 节点是否解析到定义;false 且无子节点 = 未解析的叶子。 */
|
|
171
|
+
resolved: Type.Optional(Type.Boolean()),
|
|
172
|
+
total_callers: Type.Optional(Type.Number()),
|
|
173
|
+
total_affected: Type.Optional(Type.Number()),
|
|
174
|
+
affected_files: Type.Optional(Type.Number()),
|
|
175
|
+
/** impact 的参数表(改签名时要知道)。 */
|
|
176
|
+
parameters: Type.Optional(Type.Array(Type.String())),
|
|
177
|
+
/** trace_to:到目标符号的路径,每条路径是一串跳。 */
|
|
178
|
+
paths: Type.Optional(
|
|
179
|
+
Type.Array(
|
|
180
|
+
Type.Object(
|
|
181
|
+
{ hops: Type.Optional(Type.Array(callgraphHopSchema)) },
|
|
182
|
+
{ additionalProperties: true },
|
|
183
|
+
),
|
|
184
|
+
),
|
|
185
|
+
),
|
|
186
|
+
total_paths: Type.Optional(Type.Number()),
|
|
187
|
+
/** trace_to_symbol:单条最短路径(没有路径时为 null)。 */
|
|
188
|
+
path: Type.Optional(Type.Union([Type.Array(callgraphHopSchema), Type.Null()])),
|
|
189
|
+
/** trace_data:值在赋值/参数/返回间的流转。 */
|
|
190
|
+
hops: Type.Optional(Type.Array(callgraphHopSchema)),
|
|
191
|
+
depth_limited: Type.Optional(Type.Boolean()),
|
|
192
|
+
/** 因结果上限被折叠的条目数(引擎给的是数字,不是布尔)。 */
|
|
193
|
+
truncated: Type.Optional(Type.Number()),
|
|
194
|
+
/** 软失败(symbol_not_found / callgraph_building …)的错误码。 */
|
|
195
|
+
code: Type.Optional(Type.String()),
|
|
196
|
+
},
|
|
197
|
+
{ additionalProperties: true },
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
/** 搜索命中:常规 ranking 条目(symbol)与降级时的 grep 行共用一份宽条目。 */
|
|
201
|
+
const searchHitSchema = Type.Object(
|
|
202
|
+
{
|
|
203
|
+
file: Type.Optional(Type.String()),
|
|
204
|
+
name: Type.Optional(Type.String()),
|
|
205
|
+
kind: Type.Optional(Type.String()),
|
|
206
|
+
start_line: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
207
|
+
end_line: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
208
|
+
/** "matching line" / "line range" / "[file summary]" / "GrepLine"。 */
|
|
209
|
+
location: Type.Optional(Type.String()),
|
|
210
|
+
score: Type.Optional(Type.Number()),
|
|
211
|
+
source: Type.Optional(Type.String()),
|
|
212
|
+
semantic_score: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
213
|
+
lexical_score: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
214
|
+
exact: Type.Optional(Type.Boolean()),
|
|
215
|
+
snippet: Type.Optional(Type.String()),
|
|
216
|
+
/** grep 行条目:行号、列号与命中文本。 */
|
|
217
|
+
line: Type.Optional(Type.Number()),
|
|
218
|
+
column: Type.Optional(Type.Number()),
|
|
219
|
+
line_text: Type.Optional(Type.String()),
|
|
220
|
+
match_text: Type.Optional(Type.String()),
|
|
221
|
+
},
|
|
222
|
+
{ additionalProperties: true },
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
/** `aft_search`:查询解释 + 命中列表 + 截断/降级状态。 */
|
|
226
|
+
export const aftSearchStructuredSchema = Type.Object(
|
|
227
|
+
{
|
|
228
|
+
text,
|
|
229
|
+
query: Type.Optional(Type.String()),
|
|
230
|
+
/** 引擎对查询的最终解释(regex / literal / semantic / hybrid)。 */
|
|
231
|
+
interpreted_as: Type.Optional(Type.String()),
|
|
232
|
+
result_count: Type.Optional(Type.Number()),
|
|
233
|
+
complete: Type.Optional(Type.Boolean()),
|
|
234
|
+
/** 还有更多命中没给(与分页上限的区别由引擎的 envelope 说明)。 */
|
|
235
|
+
more_available: Type.Optional(Type.Boolean()),
|
|
236
|
+
engine_capped: Type.Optional(Type.Boolean()),
|
|
237
|
+
/** 语义索引状态:ready / building / disabled / unavailable / external。 */
|
|
238
|
+
semantic_status: Type.Optional(Type.String()),
|
|
239
|
+
results: Type.Optional(Type.Array(searchHitSchema)),
|
|
240
|
+
/** 引擎给出的警告(索引降级等),原样转发。 */
|
|
241
|
+
warnings: Type.Optional(Type.Array(Type.String())),
|
|
242
|
+
/** 软失败(search_lanes_unavailable …)的错误码。 */
|
|
243
|
+
code: Type.Optional(Type.String()),
|
|
244
|
+
},
|
|
245
|
+
{ additionalProperties: true },
|
|
246
|
+
);
|