@trim21/personal-pi-extensions 0.1.20261012000609 → 0.1.20261012003405
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 +1 -1
- package/package.json +1 -1
- package/src/gh/base.ts +5 -11
- package/src/gh/tools/list-issues.ts +1 -1
- package/src/gh/tools/list-prs.ts +1 -1
- package/src/lib/github.ts +13 -36
package/README.md
CHANGED
|
@@ -475,7 +475,7 @@ GitHub 只读工具集。取数全部走 octokit REST(`src/lib/github-reads.ts
|
|
|
475
475
|
- **CI**:`read-github-ci-logs`、`list-github-workflow-runs`、`get-github-workflow-jobs`、`wait-github-pr-checks`、`wait-github-commit-checks`、`watch-github-run`
|
|
476
476
|
- **仓库 / 发布**:`read-github-repo`、`list-github-releases`、`read-github-release`、`download-github-release-assets`
|
|
477
477
|
|
|
478
|
-
`list-github-issues` / `list-github-prs` 带 `keywords` 时走 GitHub search API,不带 `keywords` 时走 REST 列表端点(state 缺省只搜 open,`state: "all"` 不加 state qualifier 覆盖 open + closed),输出 TSV
|
|
478
|
+
`list-github-issues` / `list-github-prs` 带 `keywords` 时走 GitHub search API,不带 `keywords` 时走 REST 列表端点(state 缺省只搜 open,`state: "all"` 不加 state qualifier 覆盖 open + closed),输出 TSV,固定列 `number,state,title,labels,updatedAt`(未给 `repo` 时最前面多一列 `repo`),默认列之外的字段从结构化载荷 `items` 里取。`wait-github-pr-checks` / `wait-github-commit-checks` 30 秒轮询、600 秒截止:任一 fail 即返回,全部 pass / skipped 才算通过,超时返回快照不抛错;检查快照还包含「已结束但没有 check run」的 check suite——fork PR 上等待维护者批准的 workflow 只存在于这一层,遇到它立即返回 `awaiting_approval`(不会自行开始,轮询无意义),条目名字取自对应的 workflow run。
|
|
479
479
|
|
|
480
480
|
出网代理:`~/.pi/agent/proxy.json`(`{ "proxy": "http://127.0.0.1:7890", "noProxy": "localhost" }`),缺省字段回退 `HTTPS_PROXY` / `HTTP_PROXY` / `ALL_PROXY` / `NO_PROXY` 环境变量。
|
|
481
481
|
|
package/package.json
CHANGED
package/src/gh/base.ts
CHANGED
|
@@ -334,8 +334,9 @@ export function withPendant<T extends ToolResult, IdKey extends string = never>(
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
/**
|
|
337
|
-
* `list-github-issues` / `list-github-prs` 共用的一套过滤参数,只有 `state`
|
|
338
|
-
*
|
|
337
|
+
* `list-github-issues` / `list-github-prs` 共用的一套过滤参数,只有 `state` 的说明文案按
|
|
338
|
+
* kind 不同。文本列是固定的(见 `renderHits`),因此没有列选择参数:默认列之外的字段
|
|
339
|
+
* 从结构化载荷里取。
|
|
339
340
|
*/
|
|
340
341
|
export function listFilterParameters(kind: "issue" | "pr") {
|
|
341
342
|
const isPr = kind === "pr";
|
|
@@ -364,11 +365,6 @@ export function listFilterParameters(kind: "issue" | "pr") {
|
|
|
364
365
|
),
|
|
365
366
|
milestone: Type.Optional(Type.String({ description: "Filter by milestone" })),
|
|
366
367
|
limit: Type.Optional(Type.Number({ description: "Max results (default 30, max 100)" })),
|
|
367
|
-
fields: Type.Optional(
|
|
368
|
-
Type.String({
|
|
369
|
-
description: `Comma-separated columns for the rows (default: number,state,title,labels,updatedAt; adds repo when no repo given). Valid: number,state,title,url,author,labels,milestone,assignees,comments,repo,createdAt,updatedAt,closedAt${isPr ? ",mergedAt" : ""}`,
|
|
370
|
-
}),
|
|
371
|
-
),
|
|
372
368
|
});
|
|
373
369
|
}
|
|
374
370
|
|
|
@@ -381,8 +377,6 @@ export interface ListFilters {
|
|
|
381
377
|
assignee?: string;
|
|
382
378
|
milestone?: string;
|
|
383
379
|
limit?: number;
|
|
384
|
-
/** Comma-separated field names for the keyword-search result rows. */
|
|
385
|
-
fields?: string;
|
|
386
380
|
}
|
|
387
381
|
|
|
388
382
|
/**
|
|
@@ -415,11 +409,11 @@ export async function browseList(
|
|
|
415
409
|
return { repo, hits: normalizeRestList(items, repo) };
|
|
416
410
|
}
|
|
417
411
|
|
|
418
|
-
/** 行列表的文本:两条分支共用一套 TSV
|
|
412
|
+
/** 行列表的文本:两条分支共用一套 TSV 渲染(列为固定默认列);空结果是成功结果。 */
|
|
419
413
|
export function renderHitList(
|
|
420
414
|
kind: "issue" | "pr",
|
|
421
415
|
hits: SearchHit[],
|
|
422
|
-
options: { repo?: string
|
|
416
|
+
options: { repo?: string },
|
|
423
417
|
): string {
|
|
424
418
|
if (hits.length === 0) {
|
|
425
419
|
return `(no matching ${kind === "issue" ? "issues" : "pull requests"})`;
|
|
@@ -26,7 +26,7 @@ async function listIssues(
|
|
|
26
26
|
const { repo, hits } = params.keywords
|
|
27
27
|
? { repo: params.repo, hits: await gh.search.search("issue", params) }
|
|
28
28
|
: await browseList(gh, "issue", params, { cwd: ctx.cwd, signal, input: params });
|
|
29
|
-
const text = renderHitList("issue", hits, { repo
|
|
29
|
+
const text = renderHitList("issue", hits, { repo });
|
|
30
30
|
const result = toToolResult(text, params);
|
|
31
31
|
// 文本可能被行数/字节预算截断,载荷给全部命中
|
|
32
32
|
return withStructuredResult(withPendant(result, params), { text, items: hits });
|
package/src/gh/tools/list-prs.ts
CHANGED
|
@@ -26,7 +26,7 @@ async function listPrs(
|
|
|
26
26
|
const { repo, hits } = params.keywords
|
|
27
27
|
? { repo: params.repo, hits: await gh.search.search("pr", params) }
|
|
28
28
|
: await browseList(gh, "pr", params, { cwd: ctx.cwd, signal, input: params });
|
|
29
|
-
const text = renderHitList("pr", hits, { repo
|
|
29
|
+
const text = renderHitList("pr", hits, { repo });
|
|
30
30
|
const result = toToolResult(text, params);
|
|
31
31
|
// 文本可能被行数/字节预算截断,载荷给全部命中
|
|
32
32
|
return withStructuredResult(withPendant(result, params), { text, items: hits });
|
package/src/lib/github.ts
CHANGED
|
@@ -146,42 +146,19 @@ function quoteQualifier(value: string): string {
|
|
|
146
146
|
return `"${value.replaceAll('"', String.raw`\"`)}"`;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
closedAt: (h) => h.closedAt,
|
|
163
|
-
mergedAt: (h) => h.mergedAt,
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
export const SEARCH_FIELDS: readonly string[] = Object.keys(FIELD_EXTRACTORS);
|
|
167
|
-
|
|
168
|
-
/** Render search hits as tab-separated rows; one row per hit, one column per field. */
|
|
169
|
-
export function renderHits(hits: SearchHit[], options: { repo?: string; fields?: string }): string {
|
|
170
|
-
const requested = options.fields
|
|
171
|
-
? options.fields
|
|
172
|
-
.split(",")
|
|
173
|
-
.map((f) => f.trim())
|
|
174
|
-
.filter(Boolean)
|
|
175
|
-
: options.repo
|
|
176
|
-
? ["number", "state", "title", "labels", "updatedAt"]
|
|
177
|
-
: ["repo", "number", "state", "title", "labels", "updatedAt"];
|
|
178
|
-
const unknown = requested.filter((f) => !(f in FIELD_EXTRACTORS));
|
|
179
|
-
if (unknown.length > 0) {
|
|
180
|
-
throw new Error(
|
|
181
|
-
`unknown field${unknown.length > 1 ? "s" : ""}: ${unknown.join(", ")} (valid: ${SEARCH_FIELDS.join(", ")})`,
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
return hits.map((hit) => requested.map((f) => FIELD_EXTRACTORS[f](hit)).join("\t")).join("\n");
|
|
149
|
+
/**
|
|
150
|
+
* Render search hits as tab-separated rows: one row per hit, fixed columns
|
|
151
|
+
* `number,state,title,labels,updatedAt`, plus a leading `repo` column when no
|
|
152
|
+
* repo is given (cross-repo search). Other fields of a hit reach the caller
|
|
153
|
+
* through the structured payload, not through the text.
|
|
154
|
+
*/
|
|
155
|
+
export function renderHits(hits: SearchHit[], options: { repo?: string }): string {
|
|
156
|
+
return hits
|
|
157
|
+
.map((hit) => {
|
|
158
|
+
const columns = [hit.number, hit.state, hit.title, hit.labels.join(","), hit.updatedAt];
|
|
159
|
+
return (options.repo ? columns : [hit.repo, ...columns]).join("\t");
|
|
160
|
+
})
|
|
161
|
+
.join("\n");
|
|
185
162
|
}
|
|
186
163
|
|
|
187
164
|
function toDate(iso: string | null | undefined): string {
|