@gavin-hu/my-pi-agent 0.14.0 → 0.15.0

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.
Files changed (222) hide show
  1. package/README.md +55 -33
  2. package/README.zh-CN.md +44 -27
  3. package/extensions/bytefly/README.md +193 -140
  4. package/extensions/bytefly/block/component.ts +7 -15
  5. package/extensions/bytefly/block/register.ts +6 -1
  6. package/extensions/bytefly/doctor/register.ts +24 -5
  7. package/extensions/bytefly/doctor/tools.ts +4 -0
  8. package/extensions/bytefly/footer/collect/snapshot.ts +6 -1
  9. package/extensions/bytefly/footer/config.ts +10 -6
  10. package/extensions/bytefly/footer/price/price.ts +5 -3
  11. package/extensions/bytefly/footer/price/rates.ts +63 -26
  12. package/extensions/bytefly/footer/render/status.ts +3 -3
  13. package/extensions/bytefly/header/component.ts +3 -2
  14. package/extensions/bytefly/index.ts +3 -3
  15. package/extensions/bytefly/notice/component.ts +8 -3
  16. package/extensions/bytefly/notify/config.ts +6 -11
  17. package/extensions/bytefly/notify/dispatch.ts +13 -5
  18. package/extensions/bytefly/panel/commands.ts +21 -1
  19. package/extensions/bytefly/panel/format.ts +5 -2
  20. package/extensions/bytefly/panel/settings-runtime.ts +26 -6
  21. package/extensions/bytefly/panel/settings.ts +41 -4
  22. package/extensions/bytefly/panel/themes.ts +32 -0
  23. package/extensions/bytefly/panel/tui/editing.ts +77 -0
  24. package/extensions/bytefly/panel/tui/entries.ts +24 -0
  25. package/extensions/bytefly/panel/tui/extensions-view.ts +13 -8
  26. package/extensions/bytefly/panel/tui/frame.ts +121 -4
  27. package/extensions/bytefly/panel/tui/settings-view.ts +54 -15
  28. package/extensions/bytefly/panel/tui.ts +94 -152
  29. package/extensions/bytefly/picker/discovery.ts +1 -0
  30. package/extensions/bytefly/picker/types.ts +2 -0
  31. package/extensions/bytefly/separator/component.ts +14 -4
  32. package/extensions/bytefly/update/cache.ts +58 -19
  33. package/extensions/bytefly/update/check.ts +35 -0
  34. package/extensions/bytefly/update/format.ts +76 -35
  35. package/extensions/bytefly/update/register.ts +144 -55
  36. package/extensions/bytefly/update/state.ts +4 -2
  37. package/extensions/bytefly/update/suppress.ts +66 -0
  38. package/extensions/bytefly/update/types.ts +15 -0
  39. package/extensions/check/README.md +253 -0
  40. package/extensions/check/commands.ts +128 -0
  41. package/extensions/check/config.ts +39 -0
  42. package/extensions/check/detect.ts +269 -0
  43. package/extensions/check/failures.ts +230 -0
  44. package/extensions/check/format.ts +135 -0
  45. package/extensions/check/index.ts +26 -0
  46. package/extensions/check/render.ts +185 -0
  47. package/extensions/check/runner.ts +176 -0
  48. package/extensions/check/runtime.ts +244 -0
  49. package/extensions/check/source.ts +80 -0
  50. package/extensions/check/tools.ts +173 -0
  51. package/extensions/check/tui.ts +195 -0
  52. package/extensions/check/types.ts +99 -0
  53. package/extensions/document/README.md +1 -1
  54. package/extensions/document/extract/pdf.ts +8 -16
  55. package/extensions/document/formats.ts +2 -2
  56. package/extensions/file-browse/README.md +66 -32
  57. package/extensions/file-browse/client.ts +95 -32
  58. package/extensions/file-browse/config.ts +9 -9
  59. package/extensions/file-browse/git.ts +37 -47
  60. package/extensions/file-browse/html.ts +39 -58
  61. package/extensions/file-browse/markdown.ts +110 -92
  62. package/extensions/file-browse/raw-html.ts +478 -0
  63. package/extensions/file-browse/router.ts +32 -70
  64. package/extensions/file-browse/server.ts +18 -56
  65. package/extensions/file-browse/urls.ts +80 -0
  66. package/extensions/goal/README.md +103 -47
  67. package/extensions/goal/clarify-parse.ts +4 -9
  68. package/extensions/goal/clarify.ts +27 -4
  69. package/extensions/goal/commands.ts +24 -11
  70. package/extensions/goal/format.ts +41 -10
  71. package/extensions/goal/index.ts +39 -16
  72. package/extensions/goal/plan-route.ts +51 -0
  73. package/extensions/goal/schema.ts +6 -23
  74. package/extensions/goal/state.ts +39 -57
  75. package/extensions/goal/tools.ts +26 -20
  76. package/extensions/goal/types.ts +11 -1
  77. package/extensions/job/README.md +20 -6
  78. package/extensions/job/format.ts +18 -68
  79. package/extensions/job/index.ts +26 -41
  80. package/extensions/job/log-writer.ts +208 -0
  81. package/extensions/job/logs.ts +3 -2
  82. package/extensions/job/process.ts +6 -99
  83. package/extensions/job/runtime.ts +42 -181
  84. package/extensions/job/schema.ts +1 -4
  85. package/extensions/job/tools.ts +1 -15
  86. package/extensions/job/tui.ts +117 -307
  87. package/extensions/job/ui.ts +7 -33
  88. package/extensions/memory/README.md +1 -1
  89. package/extensions/memory/errors.ts +5 -6
  90. package/extensions/memory/tui.ts +14 -24
  91. package/extensions/plan/README.md +94 -18
  92. package/extensions/plan/commands.ts +9 -5
  93. package/extensions/plan/format.ts +87 -0
  94. package/extensions/plan/index.ts +31 -15
  95. package/extensions/plan/plans.ts +2 -3
  96. package/extensions/plan/policy.ts +0 -6
  97. package/extensions/plan/runtime.ts +4 -2
  98. package/extensions/plan/steps.ts +37 -8
  99. package/extensions/plan/todos.ts +44 -3
  100. package/extensions/plan/tools/enter.ts +94 -0
  101. package/extensions/plan/tools/exit.ts +296 -0
  102. package/extensions/plan/tools/nested.ts +21 -0
  103. package/extensions/plan/tools/steps.ts +136 -0
  104. package/extensions/plan/tools/todo-seed.ts +76 -0
  105. package/extensions/plan/tools/write.ts +127 -0
  106. package/extensions/plan/tools.ts +18 -703
  107. package/extensions/plan/web-client.ts +6 -22
  108. package/extensions/plan/web-page.ts +19 -30
  109. package/extensions/plan/web-router.ts +34 -71
  110. package/extensions/plan/web.ts +13 -40
  111. package/extensions/question/answers.ts +3 -8
  112. package/extensions/question/tui.ts +6 -6
  113. package/extensions/rewind/README.md +95 -22
  114. package/extensions/rewind/checklist.ts +185 -0
  115. package/extensions/rewind/commands.ts +8 -0
  116. package/extensions/rewind/config.ts +3 -11
  117. package/extensions/rewind/format.ts +220 -2
  118. package/extensions/rewind/git.ts +74 -7
  119. package/extensions/rewind/hunk-picker.ts +114 -0
  120. package/extensions/rewind/patch.ts +88 -0
  121. package/extensions/rewind/path-picker.ts +67 -100
  122. package/extensions/rewind/paths.ts +93 -19
  123. package/extensions/rewind/restore.ts +53 -10
  124. package/extensions/rewind/review-tui.ts +320 -0
  125. package/extensions/rewind/review.ts +397 -0
  126. package/extensions/rewind/rewind-tui.ts +4 -3
  127. package/extensions/rewind/runtime.ts +94 -17
  128. package/extensions/subagent/README.md +61 -6
  129. package/extensions/subagent/background-tui.ts +208 -0
  130. package/extensions/subagent/background.ts +470 -0
  131. package/extensions/subagent/commands.ts +80 -0
  132. package/extensions/subagent/config.ts +4 -0
  133. package/extensions/subagent/format.ts +24 -1
  134. package/extensions/subagent/index.ts +91 -2
  135. package/extensions/subagent/render.ts +13 -0
  136. package/extensions/subagent/run.ts +17 -16
  137. package/extensions/subagent/schema.ts +12 -0
  138. package/extensions/subagent/types.ts +11 -0
  139. package/extensions/subagent/ui.ts +50 -0
  140. package/extensions/todo/README.md +18 -13
  141. package/extensions/todo/format.ts +3 -2
  142. package/extensions/todo/runtime.ts +3 -2
  143. package/extensions/todo/schema.ts +8 -84
  144. package/extensions/todo/state.ts +5 -46
  145. package/extensions/todo/tools.ts +2 -1
  146. package/extensions/todo/types.ts +6 -15
  147. package/extensions/watch/README.md +14 -6
  148. package/extensions/watch/child.ts +150 -0
  149. package/extensions/watch/format.ts +8 -48
  150. package/extensions/watch/index.ts +42 -58
  151. package/extensions/watch/runtime.ts +49 -128
  152. package/extensions/watch/schema.ts +1 -4
  153. package/extensions/watch/tools.ts +1 -11
  154. package/extensions/watch/tui.ts +103 -273
  155. package/extensions/watch/ui.ts +5 -32
  156. package/extensions/web-access/README.md +1 -1
  157. package/extensions/web-access/fetch/page.ts +1 -1
  158. package/extensions/web-access/fetch/tool.ts +6 -2
  159. package/extensions/web-access/search/search.ts +2 -5
  160. package/extensions/wechat/README.md +1 -1
  161. package/extensions/wechat/client.ts +23 -0
  162. package/extensions/wechat/commands.ts +57 -42
  163. package/extensions/wechat/deliver.ts +5 -9
  164. package/extensions/wechat/errors.ts +3 -6
  165. package/extensions/wechat/inbound.ts +2 -5
  166. package/extensions/wechat/index.ts +2 -8
  167. package/extensions/wechat/outbound.ts +2 -4
  168. package/extensions/wechat/peer-worker.ts +3 -8
  169. package/extensions/wechat/poll.ts +10 -9
  170. package/extensions/wechat/presence.ts +35 -62
  171. package/extensions/wechat/reply-pipeline.ts +3 -1
  172. package/extensions/wechat/status-screen.ts +1 -1
  173. package/extensions/wechat/timer.ts +57 -0
  174. package/extensions/worktree/config.ts +8 -20
  175. package/extensions/worktree/enter.ts +7 -12
  176. package/extensions/worktree/git.ts +38 -69
  177. package/extensions/worktree/index.ts +5 -4
  178. package/extensions/worktree/registry.ts +7 -7
  179. package/extensions/worktree/root-tools.ts +2 -2
  180. package/extensions/worktree/status.ts +3 -2
  181. package/lib/README.md +22 -8
  182. package/lib/config.ts +50 -3
  183. package/lib/errors.ts +12 -0
  184. package/lib/format.ts +50 -0
  185. package/lib/git/read.ts +8 -0
  186. package/lib/goal-state.ts +23 -8
  187. package/lib/http/headers.ts +54 -0
  188. package/lib/http/index.ts +13 -0
  189. package/lib/http/response.ts +46 -0
  190. package/lib/http/router.ts +52 -0
  191. package/lib/http/server.ts +91 -0
  192. package/lib/lines.ts +77 -0
  193. package/lib/pdf.ts +82 -0
  194. package/lib/plan-entry.ts +71 -0
  195. package/lib/plan-state.ts +34 -0
  196. package/lib/report.ts +99 -0
  197. package/lib/requirements.ts +25 -19
  198. package/lib/spawn.ts +170 -0
  199. package/lib/todo-state.ts +110 -23
  200. package/lib/tool-names.ts +7 -0
  201. package/lib/tool-result.ts +33 -0
  202. package/lib/tui/README.md +68 -3
  203. package/lib/tui/chrome.ts +28 -4
  204. package/lib/tui/columns.ts +6 -1
  205. package/lib/tui/confirm.ts +65 -0
  206. package/lib/tui/dock-screen.ts +410 -0
  207. package/lib/tui/glyphs.ts +2 -1
  208. package/lib/tui/indent.ts +1 -1
  209. package/lib/tui/index.ts +2 -0
  210. package/lib/tui/rows.ts +21 -0
  211. package/lib/tui/status-controller.ts +35 -1
  212. package/lib/tui/tool.ts +59 -1
  213. package/lib/web/components.ts +20 -1
  214. package/lib/web/markup.ts +32 -0
  215. package/lib/web/runtime.ts +50 -0
  216. package/package.json +22 -5
  217. package/skills/init/SKILL.md +165 -0
  218. package/skills/init/references/agents-md-quality.md +103 -0
  219. package/skills/init/references/interview-questions.md +81 -0
  220. package/skills/refactor/SKILL.md +141 -0
  221. package/extensions/watch/process.ts +0 -63
  222. package/extensions/web-access/fetch/pdf.ts +0 -45
package/lib/tui/tool.ts CHANGED
@@ -19,7 +19,7 @@
19
19
  import type { Theme } from "@earendil-works/pi-coding-agent";
20
20
  import { type Component, truncateToWidth } from "@earendil-works/pi-tui";
21
21
  import { formatDuration, sanitizeLine, stripControlChars } from "../format.ts";
22
- import { clipMiddle } from "./columns.ts";
22
+ import { clip, clipMiddle } from "./columns.ts";
23
23
  import { expandHint, SEPARATORS } from "./glyphs.ts";
24
24
  import { paint } from "./tokens.ts";
25
25
 
@@ -134,6 +134,64 @@ export function moreHint(theme: Theme, hidden: number, noun = "lines"): string {
134
134
  return `${paint(theme, "faint", `… ${hidden} more ${noun}`)} ${expandHint(theme)}`;
135
135
  }
136
136
 
137
+ /** `… N more` and the expand affordance, for a list whose rows are items. */
138
+ export function overflowHint(theme: Theme, hidden: number): string {
139
+ return `${paint(theme, "faint", `… ${hidden} more`)} ${expandHint(theme)}`;
140
+ }
141
+
142
+ /** `… N earlier <label>` and the expand affordance, for a bounded tail. */
143
+ export function earlierHint(theme: Theme, hidden: number, label: string): string {
144
+ return `${paint(theme, "faint", `… ${hidden} earlier ${label}`)} ${expandHint(theme)}`;
145
+ }
146
+
147
+ /** The row renderer a {@link TailResult} list uses: the extension's row grammar at a width. */
148
+ export type TailRowLine<Row> = (row: Row, width: number, theme: Theme) => string;
149
+
150
+ /** What a {@link TailResult} draws: the caller's rows plus a hidden count, or a bounded tail. */
151
+ export type TailResultInput<Row> =
152
+ | { kind: "list"; rows: readonly Row[]; more: number; rowLine: TailRowLine<Row> }
153
+ | { kind: "lines"; lines: readonly string[]; earlier: number; earlierLabel: string };
154
+
155
+ /**
156
+ * The transcript result block a tool that lists rows or tails output shares.
157
+ *
158
+ * One leading blank line per the block grammar, then either the caller's rows
159
+ * (already ordered and capped) with a "more" note, or the themed tail with an
160
+ * "earlier" note. The caller owns the row renderer, so the extension's own row
161
+ * grammar — a peer-session tag, a status glyph — stays with its vocabulary.
162
+ */
163
+ export class TailResult<Row> implements Component {
164
+ private input: TailResultInput<Row>;
165
+ private theme: Theme;
166
+
167
+ constructor(input: TailResultInput<Row>, theme: Theme) {
168
+ this.input = input;
169
+ this.theme = theme;
170
+ }
171
+
172
+ /** Update in place so the transcript can reuse this component across renders. */
173
+ setInput(input: TailResultInput<Row>, theme: Theme): void {
174
+ this.input = input;
175
+ this.theme = theme;
176
+ }
177
+
178
+ invalidate(): void {}
179
+
180
+ render(width: number): string[] {
181
+ const w = Math.max(1, width);
182
+ const lines: string[] = [""];
183
+ const input = this.input;
184
+ if (input.kind === "list") {
185
+ for (const row of input.rows) lines.push(input.rowLine(row, w, this.theme));
186
+ if (input.more > 0) lines.push(clip(` ${overflowHint(this.theme, input.more)}`, w));
187
+ return lines;
188
+ }
189
+ if (input.earlier > 0) lines.push(clip(earlierHint(this.theme, input.earlier, input.earlierLabel), w));
190
+ for (const line of input.lines) lines.push(this.theme.fg("toolOutput", clip(line, w)));
191
+ return lines;
192
+ }
193
+ }
194
+
137
195
  /** The render context fields the elapsed timer needs. */
138
196
  export interface ToolRenderClock {
139
197
  /** Pi's per-call render state, opaque here: this module only ever casts it. */
@@ -59,6 +59,12 @@ export const WEB_COMPONENTS_CSS = `.bf-brand{display:inline-flex;align-items:cen
59
59
  .bf-dialog__option{padding:var(--space-1) var(--space-4);font:var(--fs-sm) var(--font-mono);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
60
60
  .bf-dialog__option[aria-selected="true"]{background:var(--accent-soft);color:var(--accent)}
61
61
  .bf-dialog mark{background:transparent;color:var(--warn);font-weight:var(--fw-semibold)}
62
+ .bf-dialog__head{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-3) var(--space-4);border-bottom:1px solid var(--border)}
63
+ .bf-dialog__head h2{margin:0;font-size:var(--fs-lg)}
64
+ .bf-keys{display:grid;grid-template-columns:auto 1fr;gap:8px var(--space-4);margin:0;padding:var(--space-4)}
65
+ .bf-keys dt{white-space:nowrap}
66
+ .bf-keys dd{margin:0;color:var(--muted);font-size:var(--fs-sm)}
67
+ .bf-kbd{display:inline-block;min-width:20px;padding:1px 6px;border:1px solid var(--border);border-bottom-width:2px;border-radius:var(--radius-sm);background:var(--surface);color:var(--text);font:var(--fs-xs) var(--font-mono);text-align:center}
62
68
  .bf-tree{font-family:var(--font-mono);font-size:var(--fs-sm);overflow-x:auto}
63
69
  .bf-tree ul{list-style:none;margin:0;padding-left:14px}
64
70
  .bf-tree>ul{padding-left:0}
@@ -114,8 +120,13 @@ th[aria-sort="descending"] .bf-sort::after{content:" \\25BC";font-size:9px;color
114
120
  .bf-md pre code{background:none;border:0;padding:0}
115
121
  .bf-md blockquote{margin-left:0;padding:0 1em;border-left:3px solid var(--border);color:var(--muted)}
116
122
  .bf-md li.task{list-style:none;margin-left:-1.4em}
117
- .bf-md .md-check{color:var(--success)}
123
+ /* The boxes are drawn rather than left native: a disabled native checkbox is UA
124
+ gray in both themes, so the done state could not carry the success colour. */
125
+ .bf-md .md-check{appearance:none;-webkit-appearance:none;width:13px;height:13px;margin:0 5px 0 0;border:1px solid var(--border-strong);border-radius:3px;background:var(--canvas);vertical-align:-2px}
126
+ .bf-md .md-check:checked{border-color:var(--success);background:var(--success) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/11px 11px no-repeat}
127
+ .bf-md .md-check:disabled{opacity:1}
118
128
  .bf-md table{margin:0;border-collapse:collapse;table-layout:auto;width:auto;font-size:var(--fs-sm)}
129
+ .bf-md .md-table-frame{position:relative}
119
130
  .bf-md .md-table-wrap{overflow-x:auto;margin:0 0 1em}
120
131
  .bf-md th,.bf-md td{border:1px solid var(--border);padding:6px 10px;text-align:left;vertical-align:top;overflow-wrap:break-word}
121
132
  .bf-md th{white-space:nowrap}
@@ -126,6 +137,14 @@ th[aria-sort="descending"] .bf-sort::after{content:" \\25BC";font-size:9px;color
126
137
  .bf-md .md-right{text-align:right}
127
138
  .bf-md img{max-width:100%;height:auto;border-radius:var(--radius-sm)}
128
139
  .bf-md hr{border:0;border-top:1px solid var(--border);margin:1.4em 0}
140
+ .bf-md details{margin:0 0 1em}
141
+ .bf-md summary{cursor:pointer;font-weight:var(--fw-medium)}
142
+ .bf-md figure{margin:0 0 1em}
143
+ .bf-md figcaption{color:var(--muted);font-size:var(--fs-sm)}
144
+ .bf-md kbd{font-family:var(--font-mono);font-size:.85em;background:var(--canvas);border:1px solid var(--border);border-bottom-width:2px;border-radius:var(--radius-sm);padding:.1em .35em}
145
+ .bf-md mark{background:var(--accent-soft);color:inherit;padding:0 .1em}
146
+ .bf-md abbr[title]{text-decoration:underline dotted;cursor:help}
147
+ .bf-md sub,.bf-md sup{font-size:.75em;line-height:0}
129
148
  .bf-comment{padding:var(--space-3) var(--space-4);background:var(--surface);border:1px solid var(--border);border-left:3px solid var(--warn);border-radius:var(--radius-md)}
130
149
  .bf-comment__quote{margin-bottom:var(--space-1);color:var(--muted);font-size:var(--fs-xs);overflow-wrap:anywhere}
131
150
  .bf-comment__body{white-space:pre-wrap;overflow-wrap:anywhere}
package/lib/web/markup.ts CHANGED
@@ -97,3 +97,35 @@ export function button(options: ButtonOptions): string {
97
97
  const rendered = attrs.map(([key, value]) => ` ${key}="${escapeHtml(value)}"`).join("");
98
98
  return `<button type="button" class="${classes}"${rendered}>${escapeHtml(options.label)}</button>`;
99
99
  }
100
+
101
+ /** One row of the keyboard sheet: the key or chord, and what it does. */
102
+ export interface KeyHint {
103
+ /** The key or chord, one `<kbd>` per entry; a single string is one key, chord, or alias run. */
104
+ keys: string | readonly string[];
105
+ /** What the key does. */
106
+ label: string;
107
+ }
108
+
109
+ /**
110
+ * The `?` keyboard sheet: the dialog of key/label rows both pages share, hidden
111
+ * until the client opens it.
112
+ *
113
+ * The ids are the contract with `keysDialogScript` in `runtime.ts` — `#keys-dialog`
114
+ * for the sheet, `#keys-close` for its own close button — and the trigger button
115
+ * is the page's own concern, since the two pages name it differently.
116
+ */
117
+ export function keysSheet(rows: readonly KeyHint[]): string {
118
+ const kbd = (key: string): string => `<kbd class="bf-kbd">${escapeHtml(key)}</kbd>`;
119
+ const body = rows
120
+ .map((row) => {
121
+ const keys = typeof row.keys === "string" ? kbd(row.keys) : row.keys.map(kbd).join(" ");
122
+ return `<div><dt>${keys}</dt><dd>${escapeHtml(row.label)}</dd></div>`;
123
+ })
124
+ .join("\n");
125
+ return `<div class="bf-dialog" id="keys-dialog" hidden>
126
+ <div class="bf-dialog__panel" role="dialog" aria-modal="true" aria-labelledby="keys-title">
127
+ <div class="bf-dialog__head"><h2 id="keys-title">Keyboard shortcuts</h2><span class="bf-spacer"></span><button type="button" class="bf-btn" id="keys-close">Close</button></div>
128
+ <dl class="bf-keys">${body}</dl>
129
+ </div>
130
+ </div>`;
131
+ }
@@ -66,3 +66,53 @@ export const THEME_TOGGLE_JS = String.raw`(function () {
66
66
  else if (query.addListener) query.addListener(sync);
67
67
  }
68
68
  })();`;
69
+
70
+ /**
71
+ * The `?` keyboard sheet's wiring, shared by both clients.
72
+ *
73
+ * It owns the sheet's pointer behavior — the page's trigger button, the sheet's
74
+ * own close button, and a click on the backdrop — and nothing else: each page
75
+ * keeps its own keyboard policy in its keydown handler, because the two differ
76
+ * (the review peels `Esc` through a composer first), and calls in through
77
+ * `window.bfKeys`.
78
+ *
79
+ * `triggerId` is the page's own shortcut button, since browse opens the sheet
80
+ * from `#keys-open` and review from `#shortcuts`. The sheet's ids are the fixed
81
+ * contract in `keysSheet` (`lib/web/markup.ts`).
82
+ *
83
+ * Value-only: the open state is the dialog's own `hidden` attribute, so this
84
+ * module holds nothing.
85
+ */
86
+ export function keysDialogScript(triggerId: string): string {
87
+ return `(function () {
88
+ "use strict";
89
+ var dialog = document.getElementById("keys-dialog");
90
+ if (!dialog) return;
91
+
92
+ function isOpen() {
93
+ return !dialog.hidden;
94
+ }
95
+ function toggle(force) {
96
+ var open = force === undefined ? dialog.hidden : force;
97
+ dialog.hidden = !open;
98
+ if (open) {
99
+ var close = document.getElementById("keys-close");
100
+ if (close && close.focus) close.focus();
101
+ }
102
+ }
103
+
104
+ var trigger = document.getElementById("${triggerId}");
105
+ if (trigger) trigger.addEventListener("click", function () { toggle(); });
106
+ var closer = document.getElementById("keys-close");
107
+ if (closer) closer.addEventListener("click", function () { toggle(false); });
108
+ dialog.addEventListener("click", function (event) {
109
+ if (event.target === dialog) toggle(false);
110
+ });
111
+
112
+ window.bfKeys = {
113
+ toggle: toggle,
114
+ close: function () { toggle(false); },
115
+ isOpen: isOpen
116
+ };
117
+ })();`;
118
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gavin-hu/my-pi-agent",
3
- "version": "0.14.0",
4
- "description": "Personal Pi customizations, packaged as a Pi package: worktree isolation and rewind snapshots, question, todo, goal, plan, subagent, job, watch, web-access, file-browse, file-open, document, memory, wechat, and bytefly.",
3
+ "version": "0.15.0",
4
+ "description": "Personal Pi customizations, packaged as a Pi package: worktree isolation and rewind snapshots, question, todo, goal, plan, subagent, job, watch, web-access, file-browse, file-open, document, check, memory, wechat, and bytefly.",
5
5
  "keywords": [
6
6
  "pi-package",
7
7
  "pi",
@@ -11,6 +11,11 @@
11
11
  "goal",
12
12
  "objective",
13
13
  "plan",
14
+ "question",
15
+ "init",
16
+ "agents-md",
17
+ "refactor",
18
+ "skill",
14
19
  "subagent",
15
20
  "agents",
16
21
  "delegation",
@@ -45,11 +50,17 @@
45
50
  "read_doc",
46
51
  "memory",
47
52
  "cross-session",
53
+ "wechat",
48
54
  "web-access",
49
55
  "bytefly",
50
56
  "footer",
51
57
  "separator",
52
- "transcript"
58
+ "transcript",
59
+ "check",
60
+ "test",
61
+ "lint",
62
+ "typecheck",
63
+ "verification"
53
64
  ],
54
65
  "type": "module",
55
66
  "license": "MIT",
@@ -61,6 +72,7 @@
61
72
  "files": [
62
73
  "extensions/**",
63
74
  "lib/**",
75
+ "skills/**",
64
76
  "themes/**",
65
77
  "!**/*.test.ts"
66
78
  ],
@@ -76,6 +88,7 @@
76
88
  "./extensions/todo/index.ts",
77
89
  "./extensions/goal/index.ts",
78
90
  "./extensions/plan/index.ts",
91
+ "./extensions/check/index.ts",
79
92
  "./extensions/subagent/index.ts",
80
93
  "./extensions/job/index.ts",
81
94
  "./extensions/watch/index.ts",
@@ -87,6 +100,9 @@
87
100
  "./extensions/wechat/index.ts",
88
101
  "./extensions/bytefly/index.ts"
89
102
  ],
103
+ "skills": [
104
+ "./skills"
105
+ ],
90
106
  "themes": [
91
107
  "./themes/*.json"
92
108
  ],
@@ -99,8 +115,9 @@
99
115
  "typecheck": "tsc --noEmit",
100
116
  "format": "biome format --write .",
101
117
  "format:check": "biome format .",
102
- "check": "bun run format:check && bun run typecheck && bun run test",
103
- "check:serial": "bun run format:check && bun run typecheck && bun run test:serial",
118
+ "check:static": "bun run format:check && bun run typecheck",
119
+ "check": "bun run check:static && bun run test",
120
+ "check:serial": "bun run check:static && bun run test:serial",
104
121
  "release:notes": "bun run scripts/release-notes.ts",
105
122
  "config:migrate": "bun run scripts/migrate-config.ts",
106
123
  "compat:versions": "bun run scripts/peer-versions.ts",
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: init
3
+ description: "Initialize or refresh AGENTS.md through a built-in interactive interview and a reviewed plan. Use when the user runs /skill:init or asks to set up project agent instructions."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Initialize AGENTS.md
8
+
9
+ Goal: create or update **`AGENTS.md` at the project root** by combining repository
10
+ evidence with a short, built-in interview. The interview captures intent the code
11
+ cannot show; the repository supplies every command, path, and convention that can
12
+ be verified. Plan mode is the review gate: no write happens before approval.
13
+
14
+ `/skill:init` loads this skill. If plan mode is not active, call
15
+ `enter_plan_mode` and wait for confirmation. Keep the interview and the plan
16
+ review in that order; do not write the file early to save a step.
17
+
18
+ ## Workflow
19
+
20
+ ```text
21
+ /skill:init
22
+ └─> plan mode (read-only)
23
+ └─> recon: manifests, docs, CI, tests, existing instructions
24
+ └─> interview: one built-in question call (at most 4)
25
+ ├─ answers ───────────────> reconcile with evidence
26
+ └─ unavailable/cancelled ─> evidence + recorded assumptions
27
+ └─> draft: new file, exact edits, or an honest no-op
28
+ └─> quality gate
29
+ └─> write_plan ──> exit_plan_mode
30
+ ├─ not approved ──> refine the same plan
31
+ └─ approved ──────> write/edit AGENTS.md
32
+ └─ read back + quality gate
33
+ ```
34
+
35
+ Read [`references/interview-questions.md`](./references/interview-questions.md)
36
+ before the interview. Read
37
+ [`references/agents-md-quality.md`](./references/agents-md-quality.md) before
38
+ drafting and again before writing the plan.
39
+
40
+ ## Repository states
41
+
42
+ | State | Interview | Outcome |
43
+ |---|---|---|
44
+ | Existing project, no `AGENTS.md` | Purpose (only if unclear; otherwise Priorities), Verify, Rules, Isolation | New smallest-useful file. |
45
+ | Existing `AGENTS.md` | Existing file, Preserve (only if sections are unclear), Priorities (only if stale), Rules | Exact edits that preserve correct instructions, or a no-op. |
46
+ | Empty or near-empty repository | Stack, Commands, Purpose, Priorities | Honest minimal file from the answers and known facts only. |
47
+ | Related instruction files exist | Swap Related docs in for Preserve or Rules | Describe the relationship; do not duplicate the other file. |
48
+ | Git repository with no guidance | Isolation, Verify, Done, External changes | Prefer this set over a generic workflow question. |
49
+ | No UI, inactive tool, or cancelled interview | Skip the call; record the gaps as assumptions | Evidence-based draft; the plan review remains the place to correct it. |
50
+
51
+ The full bank, selectable alternatives, and option wording live in
52
+ `references/interview-questions.md`. The table above is the default, not a menu to
53
+ exhaust.
54
+
55
+ ## 1. Recon
56
+
57
+ - Read existing instruction files first: `AGENTS.md`, `AGENTS.override.md`,
58
+ `CLAUDE.md`, and nested `AGENTS.md` files. Note how they relate; do not silently
59
+ absorb or replace one.
60
+ - Read the files that define the project: manifests, lockfiles, README, docs
61
+ index, source layout, tests, CI, formatter and linter configuration.
62
+ - Build a short evidence sheet: stack, layout, install/test/lint/typecheck
63
+ commands, validation gates, release path, and existing rules.
64
+ - List the gaps the interview must fill. Stop the first pass once the shape is
65
+ clear; do not investigate the whole repository before asking.
66
+ - In an empty or near-empty repository, record that evidence is absent. Never
67
+ invent a command from a language's usual tooling.
68
+ - Check that any command you plan to record is copied from a file that defines it.
69
+ - Use `read`, `grep`, `find`, and `ls`. For a large repository, delegate a
70
+ read-only survey to the `explorer` or `reviewer` subagent.
71
+ - Do not read or copy secrets, credentials, tokens, or private environment
72
+ values. If a file looks like a secret store, stop reading it.
73
+
74
+ ## 2. Interview
75
+
76
+ Use `ask_user_question` once with at most four questions from the built-in bank.
77
+ Choose the deterministic default set for the repository state.
78
+
79
+ - One call is the default. Make a second call only when an answer leaves a
80
+ material ambiguity that changes what the file says; do not ask a second round
81
+ merely to collect preferences.
82
+ - Fill option labels with evidence: the detected test command, the actual package
83
+ manager, the real instruction file names. Keep a free-form escape on every
84
+ question whose answer cannot be enumerated.
85
+ - Ask only what the evidence cannot answer. Do not ask for the stack when a
86
+ manifest states it, or for a command already documented in CI.
87
+ - Never ask for secrets, credentials, tokens, environment values, or personal
88
+ data.
89
+ - If the answers contradict the repository, keep the conflict visible in the plan
90
+ instead of silently choosing a side.
91
+ - If the user cancels or the tool is unavailable, continue from evidence and
92
+ record each unanswered gap under assumptions in the plan. In an empty
93
+ repository this means an explicit skeleton that says it is newly initialized,
94
+ with no guessed commands.
95
+ - A follow-up question that is cancelled keeps the first round's answers.
96
+
97
+ ## 3. Reconcile and draft
98
+
99
+ Treat answers and evidence as different kinds of fact:
100
+
101
+ - Commands, paths, package names, and existing behavior come from the repository.
102
+ - Purpose, priorities, scope, workflow, and preferences come from the user.
103
+ - If they conflict, record the conflict, what the draft uses, and the alternative
104
+ in the plan. Do not quietly rewrite the user's intent or invent a command to
105
+ match it.
106
+
107
+ Then choose the outcome:
108
+
109
+ - **No `AGENTS.md`** — draft the smallest useful file. Use the sections this
110
+ repository needs; omit empty ones.
111
+ - **Existing `AGENTS.md`** — preserve correct instructions and propose exact
112
+ edits for the rest. If the user chose to rewrite, the plan must still list what
113
+ is being removed.
114
+ - **Accurate `AGENTS.md`** — propose no edits and explain the no-op with evidence.
115
+ - **Empty or near-empty repository** — say plainly that it is newly initialized,
116
+ record the interview facts, and omit commands and architecture that do not
117
+ exist yet.
118
+ - **Related instruction files** — state the relationship and link them instead of
119
+ copying their content.
120
+
121
+ Prefer short rules over prose. One instruction should have one job. Link deep
122
+ documentation rather than restating it.
123
+
124
+ ## 4. Pass the quality gate
125
+
126
+ Read `references/agents-md-quality.md` before drafting and again before saving the
127
+ plan. Revise a draft that fails the checklist rather than shipping it.
128
+
129
+ For a large or unfamiliar repository, optionally ask the read-only `reviewer`
130
+ subagent to critique the draft against the checklist. Use its findings as
131
+ evidence, not as a replacement for reading the repository.
132
+
133
+ ## 5. Plan and review
134
+
135
+ - Save the proposal with `write_plan`. The plan must include:
136
+ - the recon summary and the evidence that supports the draft;
137
+ - the questions asked, the answers, and how each answer was used;
138
+ - the full draft for a new file, or the exact edits for an existing one;
139
+ - assumptions, conflicts, and unanswered gaps from a cancelled or unavailable
140
+ interview;
141
+ - a verification step that reads the written file back against the checklist.
142
+ - Call `exit_plan_mode` with the returned path.
143
+ - If the user refines or rejects the plan, stay in plan mode, rewrite the same
144
+ plan file with `write_plan` (`plan_path`), and present it again.
145
+ - No `AGENTS.md` write may happen before approval.
146
+
147
+ ## 6. Apply and verify
148
+
149
+ - Create a new file with `write`, or update an existing one with `edit`.
150
+ - Change only `AGENTS.md`. Do not touch unrelated files.
151
+ - Read the result back from disk and rerun the quality checklist against what is
152
+ actually there, not what you intended to write.
153
+ - Report the path, what the file covers, whether the interview was answered or
154
+ fell back to assumptions, and any real follow-up. Name a missing fact instead of
155
+ inventing it.
156
+
157
+ ## Boundaries
158
+
159
+ - One target: `AGENTS.md` at the project root selected in the plan.
160
+ - Plan mode is mandatory. If it is unavailable, stop and explain why instead of
161
+ writing directly.
162
+ - The built-in bank is the default; one custom gap question is allowed only when
163
+ no entry covers a material fact, and it counts toward the four-question cap.
164
+ - Reviewing an existing file never means silently accepting it, and rewriting one
165
+ never means discarding its correct instructions without saying so.
@@ -0,0 +1,103 @@
1
+ # AGENTS.md quality checklist
2
+
3
+ Use this before drafting and again after writing the file. A draft fails when any
4
+ applicable answer is no. The interview and the written file are checked together:
5
+ an answered question that never reaches the file is as much a defect as an
6
+ invented command.
7
+
8
+ ## Question-bank use
9
+
10
+ - [ ] The first call used the deterministic default set for the repository state.
11
+ - [ ] At most four questions were asked in the call.
12
+ - [ ] Options were filled from evidence where the bank names commands, files, or
13
+ instruction documents.
14
+ - [ ] No question duplicated a fact the recon already answered.
15
+ - [ ] No question asked for a secret, credential, token, environment value, or
16
+ personal data.
17
+ - [ ] A second call happened only for a material ambiguity, not to collect extra
18
+ preferences.
19
+
20
+ ## Interview quality
21
+
22
+ - [ ] Every answer is reflected in the draft, or the plan states why it was not
23
+ adopted.
24
+ - [ ] A cancelled or unavailable interview left explicit assumptions instead of
25
+ guessed facts.
26
+ - [ ] A conflict between an answer and repository evidence is visible in the
27
+ plan, with the chosen resolution.
28
+ - [ ] The plan names which questions were asked and what the user answered.
29
+
30
+ ## Evidence accuracy
31
+
32
+ - [ ] Every command is copied from a manifest, script, Makefile, CI file, or docs
33
+ page that defines it. No command is guessed.
34
+ - [ ] Every path and package name exists in the repository as written.
35
+ - [ ] Every claimed convention is visible in the code or contributor docs.
36
+ - [ ] Unknown facts are omitted or named as unknown. They are never filled with
37
+ plausible-sounding placeholders.
38
+ - [ ] An answer that contradicts the code is treated as intent, not as evidence
39
+ that the code is wrong.
40
+
41
+ ## Specificity
42
+
43
+ - [ ] The file tells an agent something it could not learn from a quick look.
44
+ - [ ] It names the actual test, lint, typecheck, and single-test commands.
45
+ - [ ] It names the real architecture boundaries and the traps that matter here.
46
+ - [ ] Isolation, verification, and completion rules say what to do, not just what
47
+ to value.
48
+ - [ ] Generic advice that would fit any repository is removed.
49
+
50
+ ## Concision
51
+
52
+ - [ ] Every section earns its place; empty sections are deleted.
53
+ - [ ] Rules are short, imperative, and one job each.
54
+ - [ ] Deep material is linked, not copied.
55
+ - [ ] The file is the smallest version that still prevents likely mistakes.
56
+
57
+ ## Actionability
58
+
59
+ - [ ] Each instruction says what to do, where, or in what order.
60
+ - [ ] Commands include their working directory when it is not the root.
61
+ - [ ] Invariants name the failure they prevent.
62
+ - [ ] There is no advice that cannot be followed.
63
+ - [ ] Dependency, network, and off-limits rules name the boundary an agent must
64
+ respect.
65
+
66
+ ## Stability
67
+
68
+ - [ ] The file avoids volatile file lists, line numbers, and transient counts.
69
+ - [ ] It favours stable paths, package names, and commands.
70
+ - [ ] It will still be mostly correct after ordinary refactoring.
71
+
72
+ ## Non-duplication
73
+
74
+ - [ ] It does not restate the README or contributor guide.
75
+ - [ ] It does not duplicate `AGENTS.override.md`, `CLAUDE.md`, or a nested
76
+ `AGENTS.md`; the relationship is stated instead.
77
+ - [ ] Two sections do not give the same instruction.
78
+
79
+ ## Existing files
80
+
81
+ - [ ] Correct existing instructions are preserved.
82
+ - [ ] Stale instructions are changed only when the replacement is supported by
83
+ repository evidence or an explicit answer.
84
+ - [ ] The plan lists exact edits, not a wholesale rewrite.
85
+ - [ ] A rewrite records what is being removed and why.
86
+ - [ ] A genuinely accurate file produces a no-op plan instead of churn.
87
+
88
+ ## Empty repository
89
+
90
+ - [ ] No commands, architecture, or conventions are invented.
91
+ - [ ] The file says the repository is newly initialized.
92
+ - [ ] Only known facts and interview answers are recorded.
93
+ - [ ] Empty sections are omitted.
94
+ - [ ] Missing commands are named as missing, not replaced with a framework
95
+ default.
96
+
97
+ ## Final read-back
98
+
99
+ - [ ] The written file matches the approved plan.
100
+ - [ ] The file was read back from disk, not recalled from memory.
101
+ - [ ] Only `AGENTS.md` changed.
102
+ - [ ] The report names the path, whether the interview was answered or fell back
103
+ to assumptions, and any real follow-up.
@@ -0,0 +1,81 @@
1
+ # Built-in init questions
2
+
3
+ The `init` skill selects from this bank. It is a menu, not a checklist: one
4
+ `ask_user_question` call with at most four entries is the default, and a second
5
+ call is allowed only for a material ambiguity. Never ask for secrets,
6
+ credentials, tokens, environment values, or personal data.
7
+
8
+ ## Consolidation rules
9
+
10
+ The bank merges questions that would otherwise create two copies of the same
11
+ answer:
12
+
13
+ - **Isolation** absorbs the workflow question: worktree, branch, or direct is the
14
+ first decision an agent makes.
15
+ - **Done** absorbs testing and documentation expectations: both define when a
16
+ task is complete.
17
+ - **Sensitive** absorbs generated, vendored, and secret-bearing paths.
18
+ - **External changes** absorbs dependency and network policy.
19
+ - **Commits** absorbs branch naming.
20
+ - **Scope** and **Related docs** stay separate because they decide where the file
21
+ applies and how it relates to another instruction file.
22
+
23
+ ## Deterministic default sets
24
+
25
+ Use the first matching row. Fill option labels with evidence before asking.
26
+
27
+ | Repository state | First four questions |
28
+ |---|---|
29
+ | Existing project, no `AGENTS.md` | Purpose (only if unclear; otherwise Priorities), Verify, Rules, Isolation |
30
+ | Existing project, `AGENTS.md` present | Existing file, Preserve (only if sections are unclear), Priorities (only if stale), Rules |
31
+ | Empty or near-empty repository | Stack, Commands, Purpose, Priorities |
32
+ | Related instruction files present | Swap Related docs in for Preserve or Rules |
33
+ | Git repository with no guidance | Isolation, Verify, Done, External changes |
34
+ | No UI, inactive tool, or cancelled interview | No call; record the gaps as assumptions |
35
+
36
+ ## Core questions
37
+
38
+ | Header | Question | Shape | Selected when |
39
+ |---|---|---|---|
40
+ | Purpose | What is this project, and who will agents work on it for? | Free-form | README and manifest do not state the purpose and audience, or the repository is empty/near-empty. |
41
+ | Verify | Which commands should an agent trust to verify a change? | Multi-select: detected install, build, test, lint, and typecheck commands, plus No reliable command yet; free-form Other for a missing command | Detected commands conflict or are ambiguous, or no command was found. |
42
+ | Rules | What should an agent know that is not obvious from the code? | Free-form | No explicit conventions, invariants, style rules, or traps are found in the source, docs, or contributor files. |
43
+ | Isolation | How should agents isolate and land work? | Single-select: Worktree per task, then PR; Branch in the current checkout, then PR; Commit directly; Follow repository instructions | The project is a Git repository with no stated isolation or branch rule. |
44
+ | Done | What must be true before a task is done? | Multi-select: Tests pass; Lint and typecheck pass; Docs and changelog updated; Diff self-reviewed; Pull request opened | No contributor guide defines done, test level, or documentation expectations. |
45
+ | Sensitive | Are any files, directories, or workflows off-limits for agents? | Free-form, including generated, vendored, and secret-bearing paths | Access boundaries are unclear, or generated, vendored, or secret-bearing paths need explicit exclusion. |
46
+ | External changes | May an agent add dependencies or use the network? | Single-select: Yes, when needed; Ask first; Offline and no new dependencies | A manifest exists and dependency, package-install, or network rules are unclear. |
47
+ | Existing file | How should the `init` skill handle the current `AGENTS.md`? | Single-select: Review and update in place; Keep it and only append missing guidance; Rewrite it from this interview | `AGENTS.md` already exists. |
48
+
49
+ ## State questions
50
+
51
+ | Header | Question | Shape | Selected when |
52
+ |---|---|---|---|
53
+ | Stack | What are you building, and with which language or framework? | Free-form | The repository is empty/near-empty, or no manifest or README states the stack. |
54
+ | Commands | What install, build, test, lint, and typecheck commands do you intend to use? | Free-form, with None yet accepted | The repository is empty/near-empty and no real command exists to copy. |
55
+ | Related docs | How should `AGENTS.md` relate to existing instruction files? | Single-select: Link to them and add only gaps; Consolidate them into `AGENTS.md`; Leave them alone | `CLAUDE.md`, `AGENTS.override.md`, or a nested `AGENTS.md` exists. |
56
+ | Preserve | Which current instructions must stay? | Free-form | `AGENTS.md` exists and its authoritative sections are unclear. |
57
+ | Scope | Where should `AGENTS.md` apply? | Single-select: Repository root only; Root plus package-level files; Follow an existing instruction file | The repository is a monorepo, has nested packages, or already has a related instruction file. |
58
+
59
+ ## Optional follow-ups
60
+
61
+ | Header | Question | Shape | Selected when |
62
+ |---|---|---|---|
63
+ | Priorities | What should agents optimize for here? | Multi-select: Correctness and safety; Small, reviewable changes; Fast iteration; Test coverage; Match existing style | No `AGENTS.md` yet, or the current priorities are absent or ambiguous. |
64
+ | Planning | When should an agent plan before acting? | Single-select: Non-trivial or multi-file work; Every task; Only when asked; Never | No plan-mode or workflow guidance exists. |
65
+ | Commits | What commit convention and branch naming should agents follow? | Single-select: Conventional Commits with type/scope; Plain descriptive messages; Repository-defined convention; No preference | No commit or branch guidance exists in docs or CI. |
66
+ | Release | What release or versioning process must an agent follow? | Single-select: Maintainer handles releases; Follow documented release steps; No release process; free-form Other | The project is published or versioned and the process is unclear. |
67
+ | Performance | Are there performance budgets or hot paths to protect? | Free-form | The project exposes performance-sensitive code or has benchmarks. |
68
+ | Environment | What local services or setup steps does an agent need? | Free-form, no secrets | Setup requires services, databases, or environment configuration that is not documented. |
69
+ | Finish | Anything else the next agent should know? | Free-form | Always optional, at most once. |
70
+
71
+ ## Selection rules
72
+
73
+ - Ask at most four questions in one call, ordered by impact: state-specific
74
+ question first, then command verification, then conventions and limits.
75
+ - Use the deterministic default set for the state. Do not pick a random subset.
76
+ - Never ask for something the recon already answered, and never ask for a secret
77
+ or credential.
78
+ - One custom gap question is allowed only when no bank entry covers a material
79
+ fact. It counts toward the four-question cap.
80
+ - One follow-up call is allowed only when an answer creates a material ambiguity.
81
+ Cancel it cleanly if the user stops; the first round's answers stay valid.