@trim21/personal-pi-extensions 0.0.329 → 0.0.331

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trim21/personal-pi-extensions",
3
- "version": "0.0.329",
3
+ "version": "0.0.331",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
@@ -38,6 +38,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
38
38
  import { Type } from "typebox";
39
39
  import { Value } from "typebox/value";
40
40
 
41
+ import { type ToolPendant } from "./lib/pendant.js";
41
42
  import { createSeqState } from "./lib/seq-state.js";
42
43
 
43
44
  interface GhResult {
@@ -304,6 +305,25 @@ function toToolResult(
304
305
  };
305
306
  }
306
307
 
308
+ /**
309
+ * Pendant subtitle for a tool result: `repo=x/y` (when provided) plus the
310
+ * tool's id parameter, e.g. `repo=x/y number=123`. Returns undefined when
311
+ * neither is available, so the pendant is omitted rather than shown empty.
312
+ */
313
+ function subtitlePendant(
314
+ params: { repo?: string } & Record<string, unknown>,
315
+ idKey?: string,
316
+ ): ToolPendant | undefined {
317
+ const parts: string[] = [];
318
+ if (params.repo) parts.push(`repo=${params.repo}`);
319
+ if (idKey) {
320
+ const id = params[idKey];
321
+ if (typeof id === "string" || typeof id === "number") parts.push(`${idKey}=${id}`);
322
+ }
323
+ if (parts.length === 0) return undefined;
324
+ return { subtitle: parts.join(" ") };
325
+ }
326
+
307
327
  interface ListFilters {
308
328
  repo?: string;
309
329
  keywords?: string;
@@ -1120,7 +1140,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1120
1140
  }),
1121
1141
  async execute(_id, params, signal, _onUpdate, ctx) {
1122
1142
  const { number, repo } = params;
1123
- return toToolResult(
1143
+ const result = toToolResult(
1124
1144
  await ghExec(
1125
1145
  [
1126
1146
  "issue",
@@ -1134,6 +1154,8 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1134
1154
  ),
1135
1155
  params,
1136
1156
  );
1157
+ result.details.pendant = subtitlePendant(params, "number");
1158
+ return result;
1137
1159
  },
1138
1160
  });
1139
1161
 
@@ -1155,10 +1177,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1155
1177
  limit: Type.Optional(Type.Number({ description: "Max results (default 30)" })),
1156
1178
  }),
1157
1179
  async execute(_id, params, signal, _onUpdate, ctx) {
1158
- return toToolResult(
1180
+ const result = toToolResult(
1159
1181
  await listGithub("issue", params, { cwd: ctx.cwd, signal, input: params }),
1160
1182
  params,
1161
1183
  );
1184
+ result.details.pendant = subtitlePendant(params);
1185
+ return result;
1162
1186
  },
1163
1187
  });
1164
1188
 
@@ -1174,7 +1198,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1174
1198
  }),
1175
1199
  async execute(_id, params, signal, _onUpdate, ctx) {
1176
1200
  const { number, repo } = params;
1177
- return toToolResult(
1201
+ const result = toToolResult(
1178
1202
  await ghExec(
1179
1203
  [
1180
1204
  "pr",
@@ -1188,6 +1212,8 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1188
1212
  ),
1189
1213
  params,
1190
1214
  );
1215
+ result.details.pendant = subtitlePendant(params, "number");
1216
+ return result;
1191
1217
  },
1192
1218
  });
1193
1219
 
@@ -1211,10 +1237,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1211
1237
  limit: Type.Optional(Type.Number({ description: "Max results (default 30)" })),
1212
1238
  }),
1213
1239
  async execute(_id, params, signal, _onUpdate, ctx) {
1214
- return toToolResult(
1240
+ const result = toToolResult(
1215
1241
  await listGithub("pr", params, { cwd: ctx.cwd, signal, input: params }),
1216
1242
  params,
1217
1243
  );
1244
+ result.details.pendant = subtitlePendant(params);
1245
+ return result;
1218
1246
  },
1219
1247
  });
1220
1248
 
@@ -1231,7 +1259,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1231
1259
  async execute(_id, params, signal, _onUpdate, ctx) {
1232
1260
  const { number, repo } = params;
1233
1261
  const args = ["pr", "diff", String(number), ...repoArgs(repo)];
1234
- return toToolResult(await ghExec(args, { cwd: ctx.cwd, signal, input: params }), params);
1262
+ const result = toToolResult(
1263
+ await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
1264
+ params,
1265
+ );
1266
+ result.details.pendant = subtitlePendant(params, "number");
1267
+ return result;
1235
1268
  },
1236
1269
  });
1237
1270
 
@@ -1259,7 +1292,9 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1259
1292
  // Anything else is a real error (cancelled, auth, network, ...)
1260
1293
  throw new GhError(args, result, params);
1261
1294
  }
1262
- return toToolResult(result.stdout, params);
1295
+ const toolResult = toToolResult(result.stdout, params);
1296
+ toolResult.details.pendant = subtitlePendant(params, "number");
1297
+ return toolResult;
1263
1298
  },
1264
1299
  });
1265
1300
 
@@ -1321,9 +1356,10 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1321
1356
  );
1322
1357
  }
1323
1358
  const { text, truncated } = truncate(out);
1359
+ const pendant = subtitlePendant(params, "number");
1324
1360
  return {
1325
1361
  content: [{ type: "text", text }],
1326
- details: { input: params, truncated },
1362
+ details: { input: params, truncated, ...(pendant && { pendant }) },
1327
1363
  };
1328
1364
  },
1329
1365
  });
@@ -1340,7 +1376,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1340
1376
  }),
1341
1377
  async execute(_id, params, signal, _onUpdate, ctx) {
1342
1378
  const { number, repo } = params;
1343
- return toToolResult(
1379
+ const result = toToolResult(
1344
1380
  await ghExec(["issue", "view", String(number), ...repoArgs(repo), "--json", "comments"], {
1345
1381
  cwd: ctx.cwd,
1346
1382
  signal,
@@ -1348,6 +1384,8 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1348
1384
  }),
1349
1385
  params,
1350
1386
  );
1387
+ result.details.pendant = subtitlePendant(params, "number");
1388
+ return result;
1351
1389
  },
1352
1390
  });
1353
1391
 
@@ -1371,7 +1409,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1371
1409
  if (limit) args.push("--limit", String(limit));
1372
1410
  if (status) args.push("--status", status);
1373
1411
  if (workflow) args.push("--workflow", workflow);
1374
- return toToolResult(await ghExec(args, { cwd: ctx.cwd, signal, input: params }), params);
1412
+ const result = toToolResult(
1413
+ await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
1414
+ params,
1415
+ );
1416
+ result.details.pendant = subtitlePendant(params);
1417
+ return result;
1375
1418
  },
1376
1419
  });
1377
1420
 
@@ -1424,6 +1467,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1424
1467
  async execute(_id, params, signal, onUpdate, ctx) {
1425
1468
  const { run_id, repo, job, step, offset, limit, full, output_file } = params;
1426
1469
 
1470
+ const pendant = subtitlePendant(params, "run_id");
1427
1471
  const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
1428
1472
  const jobsOut = await ghExec(["api", `/repos/${effectiveRepo}/actions/runs/${run_id}/jobs`], {
1429
1473
  cwd: ctx.cwd,
@@ -1437,13 +1481,14 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1437
1481
 
1438
1482
  // ── Write the complete log to a file ───────────────────────────────
1439
1483
  if (output_file !== undefined && output_file !== null && output_file !== "") {
1440
- return writeLogFile(
1484
+ const result = await writeLogFile(
1441
1485
  { runId: String(run_id), job, step, outputFile: output_file },
1442
1486
  jobs,
1443
1487
  fetchJobLog,
1444
1488
  ctx.cwd,
1445
1489
  params,
1446
1490
  );
1491
+ return { ...result, details: { ...result.details, ...(pendant && { pendant }) } };
1447
1492
  }
1448
1493
 
1449
1494
  // ── Fetch a specific step's logs (requires `job`) ─────────────────
@@ -1458,7 +1503,10 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1458
1503
  fetchJobLog,
1459
1504
  onUpdate,
1460
1505
  );
1461
- return { ...stepResult, details: { ...stepResult.details, input: params } };
1506
+ return {
1507
+ ...stepResult,
1508
+ details: { ...stepResult.details, input: params, ...(pendant && { pendant }) },
1509
+ };
1462
1510
  }
1463
1511
 
1464
1512
  // ── List jobs/steps, with failed step logs expanded ────────────────
@@ -1471,7 +1519,10 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1471
1519
  jobs,
1472
1520
  fetchJobLog,
1473
1521
  );
1474
- return { ...jobsResult, details: { ...jobsResult.details, input: params } };
1522
+ return {
1523
+ ...jobsResult,
1524
+ details: { ...jobsResult.details, input: params, ...(pendant && { pendant }) },
1525
+ };
1475
1526
  },
1476
1527
  });
1477
1528
 
@@ -1489,7 +1540,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1489
1540
  async execute(_id, params, signal, _onUpdate, ctx) {
1490
1541
  const { run_id, repo } = params;
1491
1542
  const effectiveRepo = await resolveRepo(repo, signal, ctx.cwd, params);
1492
- return toToolResult(
1543
+ const result = toToolResult(
1493
1544
  await ghExec(["api", `/repos/${effectiveRepo}/actions/runs/${run_id}/jobs`], {
1494
1545
  cwd: ctx.cwd,
1495
1546
  signal,
@@ -1497,6 +1548,8 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1497
1548
  }),
1498
1549
  params,
1499
1550
  );
1551
+ result.details.pendant = subtitlePendant(params, "run_id");
1552
+ return result;
1500
1553
  },
1501
1554
  });
1502
1555
 
@@ -1513,7 +1566,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1513
1566
  const { repo } = params;
1514
1567
  const args = ["repo", "view"];
1515
1568
  if (repo) args.push(repo);
1516
- return toToolResult(await ghExec(args, { cwd: ctx.cwd, signal, input: params }), params);
1569
+ const result = toToolResult(
1570
+ await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
1571
+ params,
1572
+ );
1573
+ result.details.pendant = subtitlePendant(params);
1574
+ return result;
1517
1575
  },
1518
1576
  });
1519
1577
 
@@ -1531,7 +1589,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1531
1589
  const { repo, limit } = params;
1532
1590
  const args = ["release", "list", ...repoArgs(repo)];
1533
1591
  if (limit) args.push("--limit", String(limit));
1534
- return toToolResult(await ghExec(args, { cwd: ctx.cwd, signal, input: params }), params);
1592
+ const result = toToolResult(
1593
+ await ghExec(args, { cwd: ctx.cwd, signal, input: params }),
1594
+ params,
1595
+ );
1596
+ result.details.pendant = subtitlePendant(params);
1597
+ return result;
1535
1598
  },
1536
1599
  });
1537
1600
 
@@ -1547,7 +1610,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1547
1610
  }),
1548
1611
  async execute(_id, params, signal, _onUpdate, ctx) {
1549
1612
  const { tag, repo } = params;
1550
- return toToolResult(
1613
+ const result = toToolResult(
1551
1614
  await ghExec(["release", "view", tag, ...repoArgs(repo)], {
1552
1615
  cwd: ctx.cwd,
1553
1616
  signal,
@@ -1555,6 +1618,8 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1555
1618
  }),
1556
1619
  params,
1557
1620
  );
1621
+ result.details.pendant = subtitlePendant(params, "tag");
1622
+ return result;
1558
1623
  },
1559
1624
  });
1560
1625
 
@@ -1576,6 +1641,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1576
1641
  async execute(_id, params, signal, onUpdate, ctx) {
1577
1642
  const { number, repo, fail_fast } = params;
1578
1643
 
1644
+ const pendant = subtitlePendant(params, "number");
1579
1645
  onUpdate?.({
1580
1646
  content: [{ type: "text", text: `Watching CI checks for PR #${number}...` }],
1581
1647
  details: {},
@@ -1657,7 +1723,12 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1657
1723
  text: `## PR #${number} CI Checks\n\nNo workflow runs found for head commit ${headRefOid.slice(0, 7)}.`,
1658
1724
  },
1659
1725
  ],
1660
- details: { status: "no-jobs", totalJobs: 0, input: params },
1726
+ details: {
1727
+ status: "no-jobs",
1728
+ totalJobs: 0,
1729
+ input: params,
1730
+ ...(pendant && { pendant }),
1731
+ },
1661
1732
  };
1662
1733
  }
1663
1734
 
@@ -1681,6 +1752,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1681
1752
  totalJobs,
1682
1753
  failedJobs,
1683
1754
  input: params,
1755
+ ...(pendant && { pendant }),
1684
1756
  },
1685
1757
  };
1686
1758
  }
@@ -1692,7 +1764,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1692
1764
  text: `## PR #${number} CI Checks - PASSED\n\nAll ${totalJobs} job(s) succeeded.`,
1693
1765
  },
1694
1766
  ],
1695
- details: { status: "success", totalJobs, input: params },
1767
+ details: { status: "success", totalJobs, input: params, ...(pendant && { pendant }) },
1696
1768
  };
1697
1769
  },
1698
1770
  });
@@ -1712,6 +1784,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1712
1784
  async execute(_id, params, signal, onUpdate, ctx) {
1713
1785
  const { run_id, repo } = params;
1714
1786
 
1787
+ const pendant = subtitlePendant(params, "run_id");
1715
1788
  onUpdate?.({
1716
1789
  content: [{ type: "text", text: `Watching workflow run ${run_id}...` }],
1717
1790
  details: {},
@@ -1731,7 +1804,7 @@ export default function ghReadonlyTools(pi: ExtensionAPI) {
1731
1804
  content: [
1732
1805
  { type: "text", text: `## Workflow Run ${run_id} Completed\n\n${result.stdout}` },
1733
1806
  ],
1734
- details: { exitCode: 0, input: params },
1807
+ details: { exitCode: 0, input: params, ...(pendant && { pendant }) },
1735
1808
  };
1736
1809
  },
1737
1810
  });
@@ -16,7 +16,10 @@ export interface ToolPendant {
16
16
  * 面板副标题
17
17
  */
18
18
  subtitle?: string;
19
- markdown: string;
19
+ /**
20
+ * 面板正文(完整 markdown),建议以 `## ` 标题开头、末尾 trim
21
+ */
22
+ markdown?: string;
20
23
  /**
21
24
  * @default false
22
25
  */