@gavin-hu/my-pi-agent 0.16.0 → 0.17.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.
- package/README.md +14 -8
- package/README.zh-CN.md +14 -9
- package/extensions/bytefly/README.md +174 -101
- package/extensions/bytefly/footer/collect/entries.ts +1 -6
- package/extensions/bytefly/footer/collect/snapshot.ts +23 -9
- package/extensions/bytefly/footer/price/price.ts +12 -8
- package/extensions/bytefly/footer/register.ts +13 -1
- package/extensions/bytefly/footer/types.ts +11 -0
- package/extensions/bytefly/footer/unpriced.ts +36 -0
- package/extensions/bytefly/header/component.ts +15 -29
- package/extensions/bytefly/header/identity.ts +71 -0
- package/extensions/bytefly/header/register.ts +9 -3
- package/extensions/bytefly/index.ts +13 -5
- package/extensions/bytefly/message/format.ts +20 -13
- package/extensions/bytefly/message/register.ts +8 -7
- package/extensions/bytefly/panel/commands.ts +46 -25
- package/extensions/bytefly/panel/format.ts +49 -14
- package/extensions/bytefly/panel/join.ts +35 -9
- package/extensions/bytefly/panel/settings.ts +10 -27
- package/extensions/bytefly/panel/skills.ts +51 -0
- package/extensions/bytefly/panel/tui/extensions-view.ts +7 -61
- package/extensions/bytefly/panel/tui/frame.ts +9 -1
- package/extensions/bytefly/panel/tui/list-view.ts +72 -0
- package/extensions/bytefly/panel/tui/nav.ts +71 -3
- package/extensions/bytefly/panel/tui/settings-section.ts +250 -0
- package/extensions/bytefly/panel/tui/skills-view.ts +50 -0
- package/extensions/bytefly/panel/tui.ts +223 -331
- package/extensions/bytefly/panel/types.ts +26 -8
- package/extensions/bytefly/picker/discovery.ts +32 -27
- package/extensions/bytefly/picker/resources.ts +16 -8
- package/extensions/bytefly/picker/runtime.ts +62 -34
- package/extensions/bytefly/picker/toggle.ts +16 -10
- package/extensions/bytefly/picker/types.ts +31 -13
- package/extensions/bytefly/update/format.ts +66 -8
- package/extensions/bytefly/update/patch.ts +66 -0
- package/extensions/bytefly/update/register.ts +4 -11
- package/extensions/bytefly/update/release.ts +65 -0
- package/extensions/bytefly/update/state.ts +14 -0
- package/extensions/bytefly/update/suppress.ts +47 -29
- package/extensions/bytefly/update/types.ts +15 -5
- package/extensions/check/tui.ts +2 -0
- package/extensions/context/README.md +21 -11
- package/extensions/context/format.ts +10 -8
- package/extensions/context/report.ts +21 -8
- package/extensions/context/tui.ts +26 -10
- package/extensions/context/types.ts +5 -3
- package/extensions/file-browse/README.md +29 -1
- package/extensions/file-browse/client.ts +16 -463
- package/extensions/file-browse/html.ts +7 -5
- package/extensions/file-browse/palette.ts +224 -0
- package/extensions/file-browse/router.ts +2 -2
- package/extensions/file-browse/styles.ts +8 -3
- package/extensions/file-browse/tree.ts +381 -0
- package/extensions/file-read/README.md +4 -1
- package/extensions/file-read/extract/odt.ts +7 -5
- package/extensions/goal/tools.ts +6 -11
- package/extensions/job/index.ts +20 -45
- package/extensions/job/tools.ts +51 -77
- package/extensions/memory/tools.ts +4 -6
- package/extensions/memory/tui.ts +5 -1
- package/extensions/plan/README.md +88 -33
- package/extensions/plan/commands.ts +19 -4
- package/extensions/plan/config.ts +27 -0
- package/extensions/plan/plan-index.ts +3 -1
- package/extensions/plan/plans.ts +31 -13
- package/extensions/plan/review.ts +34 -14
- package/extensions/plan/runtime.ts +3 -1
- package/extensions/plan/steps.ts +43 -14
- package/extensions/plan/tools/cancel.ts +79 -0
- package/extensions/plan/tools/enter.ts +10 -10
- package/extensions/plan/tools/exit.ts +54 -43
- package/extensions/plan/tools/steps.ts +7 -19
- package/extensions/plan/tools/write.ts +22 -29
- package/extensions/plan/tools.ts +5 -2
- package/extensions/plan/tui.ts +9 -7
- package/extensions/plan/types.ts +8 -0
- package/extensions/plan/web-chrome.ts +101 -0
- package/extensions/plan/web-client.ts +98 -311
- package/extensions/plan/web-markdown.ts +222 -0
- package/extensions/plan/web-page.ts +28 -2
- package/extensions/plan/web-router.ts +2 -2
- package/extensions/rewind/checklist.ts +4 -0
- package/extensions/rewind/review-tui.ts +3 -1
- package/extensions/rewind/rewind-tui.ts +4 -0
- package/extensions/subagent/README.md +25 -12
- package/extensions/subagent/format.ts +72 -25
- package/extensions/subagent/index.ts +21 -47
- package/extensions/subagent/orchestrate.ts +18 -41
- package/extensions/subagent/render.ts +29 -42
- package/extensions/subagent/stream.ts +24 -18
- package/extensions/subagent/types.ts +7 -0
- package/extensions/todo/tools.ts +5 -6
- package/extensions/todo/tui.ts +5 -1
- package/extensions/watch/index.ts +10 -35
- package/extensions/watch/tools.ts +31 -59
- package/extensions/wechat/README.md +40 -18
- package/extensions/wechat/bridge.ts +38 -40
- package/extensions/wechat/client.ts +1 -4
- package/extensions/wechat/commands.ts +1 -1
- package/extensions/wechat/interaction.ts +25 -4
- package/extensions/wechat/login-screen.ts +2 -3
- package/extensions/wechat/notices.ts +7 -5
- package/extensions/wechat/prompt.ts +19 -4
- package/extensions/wechat/qrcode.ts +9 -9
- package/extensions/wechat/slash.ts +14 -0
- package/extensions/wechat/status-screen.ts +2 -2
- package/extensions/wechat/tools.ts +3 -11
- package/extensions/worktree/README.md +48 -12
- package/extensions/worktree/commands.ts +109 -65
- package/extensions/worktree/enter.ts +1 -1
- package/extensions/worktree/exit.ts +11 -1
- package/extensions/worktree/lifecycle.ts +9 -1
- package/extensions/worktree/screen.ts +263 -0
- package/extensions/worktree/status.ts +84 -38
- package/lib/README.md +7 -6
- package/lib/config.ts +12 -0
- package/lib/format.ts +6 -2
- package/lib/interaction.ts +18 -1
- package/lib/report.ts +75 -2
- package/lib/tool-result.ts +54 -4
- package/lib/tui/README.md +16 -8
- package/lib/tui/chrome.ts +27 -6
- package/lib/tui/dock-screen.ts +6 -2
- package/lib/tui/gauge.ts +9 -5
- package/lib/usage.ts +26 -0
- package/lib/web/README.md +131 -0
- package/lib/web/base.ts +19 -2
- package/lib/web/components.ts +10 -6
- package/lib/web/layout.ts +2 -0
- package/lib/web/markup.ts +2 -1
- package/lib/web/runtime.ts +103 -25
- package/lib/web/tokens.ts +23 -7
- package/package.json +3 -1
- package/skills/changelog/SKILL.md +57 -45
- package/skills/next/SKILL.md +184 -0
package/lib/web/runtime.ts
CHANGED
|
@@ -10,10 +10,16 @@
|
|
|
10
10
|
/** localStorage key for the browser's explicit light/dark choice, shared by both surfaces. */
|
|
11
11
|
export const WEB_THEME_STORAGE_KEY = "pi-web-theme";
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Where both routers serve {@link THEME_JS}. `docHead` emits the same path, so
|
|
15
|
+
* the script tag and the route cannot drift apart.
|
|
16
|
+
*/
|
|
17
|
+
export const THEME_JS_PATH = "/theme.js";
|
|
18
|
+
|
|
13
19
|
/**
|
|
14
20
|
* A tiny head script that applies the saved theme before the body is painted,
|
|
15
|
-
* so an explicit choice does not flash the system theme on load. Served
|
|
16
|
-
*
|
|
21
|
+
* so an explicit choice does not flash the system theme on load. Served at
|
|
22
|
+
* {@link THEME_JS_PATH} and shared by both pages.
|
|
17
23
|
*/
|
|
18
24
|
export const THEME_JS = `(function(){try{var t=localStorage.getItem("${WEB_THEME_STORAGE_KEY}");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t);}catch(e){}})();`;
|
|
19
25
|
|
|
@@ -67,52 +73,124 @@ export const THEME_TOGGLE_JS = String.raw`(function () {
|
|
|
67
73
|
}
|
|
68
74
|
})();`;
|
|
69
75
|
|
|
76
|
+
/** Options for {@link dialogScript}. */
|
|
77
|
+
export interface DialogOptions {
|
|
78
|
+
/** Id of the dialog root: the element carrying `.bf-dialog` and `hidden`. */
|
|
79
|
+
dialogId: string;
|
|
80
|
+
/** Id of the dialog's own close button, when the markup has one. */
|
|
81
|
+
closeId?: string;
|
|
82
|
+
/** Id of the page's trigger button, when the dialog opens from one. */
|
|
83
|
+
triggerId?: string;
|
|
84
|
+
/** Property to expose on `window`, so the page can open and close it. */
|
|
85
|
+
globalName?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Everything inside a dialog that can take focus, in DOM order. */
|
|
89
|
+
const FOCUSABLE =
|
|
90
|
+
'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
91
|
+
|
|
70
92
|
/**
|
|
71
|
-
* The
|
|
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`.
|
|
93
|
+
* The wiring every modal in the kit shares: open and close, the backdrop, the
|
|
94
|
+
* `Tab` trap, `Esc`, and focus returning to whatever opened it.
|
|
78
95
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
96
|
+
* A dialog is modal before this script runs too — `aria-modal` and `hidden` are
|
|
97
|
+
* in the markup — so a page without JavaScript still shows it closed rather
|
|
98
|
+
* than half-open.
|
|
82
99
|
*
|
|
83
|
-
* Value-only: the open state is the dialog's own `hidden` attribute,
|
|
84
|
-
*
|
|
100
|
+
* Value-only: the open state is the dialog's own `hidden` attribute, and the
|
|
101
|
+
* element that opened it lives in this script's closure.
|
|
85
102
|
*/
|
|
86
|
-
export function
|
|
103
|
+
export function dialogScript(options: DialogOptions): string {
|
|
104
|
+
const trigger = options.triggerId ? `document.getElementById("${options.triggerId}")` : "null";
|
|
105
|
+
const closer = options.closeId ? `document.getElementById("${options.closeId}")` : "null";
|
|
106
|
+
const expose = options.globalName
|
|
107
|
+
? `window.${options.globalName} = {
|
|
108
|
+
open: function () { toggle(true); },
|
|
109
|
+
toggle: toggle,
|
|
110
|
+
close: function () { toggle(false); },
|
|
111
|
+
isOpen: isOpen
|
|
112
|
+
};`
|
|
113
|
+
: "";
|
|
87
114
|
return `(function () {
|
|
88
115
|
"use strict";
|
|
89
|
-
var dialog = document.getElementById("
|
|
116
|
+
var dialog = document.getElementById("${options.dialogId}");
|
|
90
117
|
if (!dialog) return;
|
|
118
|
+
var opener = null;
|
|
91
119
|
|
|
92
120
|
function isOpen() {
|
|
93
121
|
return !dialog.hidden;
|
|
94
122
|
}
|
|
123
|
+
// A button inside a closed dialog has no boxes, so the rects are the test that
|
|
124
|
+
// survives a hidden attribute, a collapsed panel, and a stylesheet swap alike.
|
|
125
|
+
function focusables() {
|
|
126
|
+
return Array.prototype.filter.call(dialog.querySelectorAll('${FOCUSABLE}'), function (node) {
|
|
127
|
+
return node.getClientRects && node.getClientRects().length > 0;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
95
130
|
function toggle(force) {
|
|
96
131
|
var open = force === undefined ? dialog.hidden : force;
|
|
132
|
+
if (open === isOpen()) return;
|
|
97
133
|
dialog.hidden = !open;
|
|
98
134
|
if (open) {
|
|
99
|
-
|
|
100
|
-
|
|
135
|
+
opener = document.activeElement;
|
|
136
|
+
var first = focusables()[0];
|
|
137
|
+
if (first) first.focus();
|
|
138
|
+
} else if (opener && opener.focus) {
|
|
139
|
+
opener.focus();
|
|
140
|
+
opener = null;
|
|
101
141
|
}
|
|
102
142
|
}
|
|
103
143
|
|
|
104
|
-
var trigger =
|
|
144
|
+
var trigger = ${trigger};
|
|
105
145
|
if (trigger) trigger.addEventListener("click", function () { toggle(); });
|
|
106
|
-
var closer =
|
|
146
|
+
var closer = ${closer};
|
|
107
147
|
if (closer) closer.addEventListener("click", function () { toggle(false); });
|
|
108
148
|
dialog.addEventListener("click", function (event) {
|
|
109
149
|
if (event.target === dialog) toggle(false);
|
|
110
150
|
});
|
|
111
151
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
152
|
+
// Tab cycles inside the dialog: leaving it would put focus behind the scrim,
|
|
153
|
+
// where the page looks inert but is not.
|
|
154
|
+
dialog.addEventListener("keydown", function (event) {
|
|
155
|
+
if (event.key !== "Tab") return;
|
|
156
|
+
var nodes = focusables();
|
|
157
|
+
if (nodes.length === 0) { event.preventDefault(); return; }
|
|
158
|
+
var first = nodes[0];
|
|
159
|
+
var last = nodes[nodes.length - 1];
|
|
160
|
+
if (event.shiftKey && document.activeElement === first) {
|
|
161
|
+
event.preventDefault();
|
|
162
|
+
last.focus();
|
|
163
|
+
} else if (!event.shiftKey && document.activeElement === last) {
|
|
164
|
+
event.preventDefault();
|
|
165
|
+
first.focus();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Capture, so Esc closes the dialog before a page handler peels another layer.
|
|
170
|
+
document.addEventListener("keydown", function (event) {
|
|
171
|
+
if (event.key !== "Escape" || !isOpen()) return;
|
|
172
|
+
toggle(false);
|
|
173
|
+
event.preventDefault();
|
|
174
|
+
event.stopPropagation();
|
|
175
|
+
}, true);
|
|
176
|
+
|
|
177
|
+
${expose}
|
|
117
178
|
})();`;
|
|
118
179
|
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* The `?` keyboard sheet's wiring, shared by both clients.
|
|
183
|
+
*
|
|
184
|
+
* `triggerId` is the page's own shortcut button, since browse opens the sheet
|
|
185
|
+
* from `#keys-open` and review from `#shortcuts`. The sheet's ids are the fixed
|
|
186
|
+
* contract in `keysSheet` (`lib/web/markup.ts`), and the page's keydown handler
|
|
187
|
+
* calls in through `window.bfKeys`.
|
|
188
|
+
*/
|
|
189
|
+
export function keysDialogScript(triggerId: string): string {
|
|
190
|
+
return dialogScript({
|
|
191
|
+
dialogId: "keys-dialog",
|
|
192
|
+
closeId: "keys-close",
|
|
193
|
+
triggerId,
|
|
194
|
+
globalName: "bfKeys",
|
|
195
|
+
});
|
|
196
|
+
}
|
package/lib/web/tokens.ts
CHANGED
|
@@ -21,12 +21,11 @@ interface ThemeJson {
|
|
|
21
21
|
const DARK = darkTheme as unknown as ThemeJson;
|
|
22
22
|
const LIGHT = lightTheme as unknown as ThemeJson;
|
|
23
23
|
|
|
24
|
-
/** Web custom property -> Bytefly theme var. `--accent-soft
|
|
24
|
+
/** Web custom property -> Bytefly theme var. `--accent-soft`, `--on-accent`, `--scrim`,
|
|
25
|
+
* and `--shadow` are derived, so no appearance-only colour enters the kit. */
|
|
25
26
|
const VAR_TOKENS: ReadonlyArray<readonly [string, string]> = [
|
|
26
27
|
["--canvas", "canvas"],
|
|
27
28
|
["--surface", "canvasSubtle"],
|
|
28
|
-
["--surface-raised", "selectionBg"],
|
|
29
|
-
["--selected", "selectionBg"],
|
|
30
29
|
["--border", "borderMuted"],
|
|
31
30
|
["--border-strong", "border"],
|
|
32
31
|
["--text", "text"],
|
|
@@ -90,19 +89,34 @@ function rgba(hex: string, alpha: number): string {
|
|
|
90
89
|
return `rgba(${r},${g},${b},${alpha})`;
|
|
91
90
|
}
|
|
92
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Overlays are not palette entries: a scrim dims what is behind it and a shadow
|
|
94
|
+
* lifts a panel off it, so each appearance needs its own alpha rather than the
|
|
95
|
+
* theme's colours.
|
|
96
|
+
*/
|
|
97
|
+
const OVERLAYS: Record<"dark" | "light", { scrim: string; shadow: string }> = {
|
|
98
|
+
dark: { scrim: "rgba(0,0,0,.5)", shadow: "0 8px 24px rgba(0,0,0,.4)" },
|
|
99
|
+
light: { scrim: "rgba(15,23,42,.3)", shadow: "0 8px 24px rgba(15,23,42,.14)" },
|
|
100
|
+
};
|
|
101
|
+
|
|
93
102
|
/** The full custom-property set for one appearance. */
|
|
94
|
-
function paletteOf(theme: ThemeJson, accentAlpha: number): Record<string, string> {
|
|
103
|
+
function paletteOf(theme: ThemeJson, appearance: "dark" | "light", accentAlpha: number): Record<string, string> {
|
|
95
104
|
const palette: Record<string, string> = {};
|
|
96
105
|
for (const [token, name] of VAR_TOKENS) palette[token] = theme.vars[name];
|
|
97
106
|
palette["--accent-soft"] = rgba(palette["--accent"] ?? "#000000", accentAlpha);
|
|
107
|
+
// A label on the accent fill is the canvas colour: a light blue button takes dark
|
|
108
|
+
// text, and the same derivation gives white on the light theme's darker blue.
|
|
109
|
+
palette["--on-accent"] = palette["--canvas"];
|
|
110
|
+
palette["--scrim"] = OVERLAYS[appearance].scrim;
|
|
111
|
+
palette["--shadow"] = OVERLAYS[appearance].shadow;
|
|
98
112
|
for (const [token, name] of SYNTAX_TOKENS) palette[token] = resolve(theme, theme.colors[name] ?? "");
|
|
99
113
|
return palette;
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
/** Every token value per appearance, for tests and for building the CSS. */
|
|
103
117
|
export const WEB_THEME_TOKENS: { dark: Record<string, string>; light: Record<string, string> } = {
|
|
104
|
-
dark: paletteOf(DARK, 0.15),
|
|
105
|
-
light: paletteOf(LIGHT, 0.1),
|
|
118
|
+
dark: paletteOf(DARK, "dark", 0.15),
|
|
119
|
+
light: paletteOf(LIGHT, "light", 0.1),
|
|
106
120
|
};
|
|
107
121
|
|
|
108
122
|
/** `a{color:var(--tok-keyword)}…` for each syntax token. */
|
|
@@ -125,4 +139,6 @@ export const WEB_THEME_CSS = `:root{${declarations(WEB_THEME_TOKENS.dark)};${SCA
|
|
|
125
139
|
:root[data-theme="light"]{${declarations(WEB_THEME_TOKENS.light)};color-scheme:light}
|
|
126
140
|
:root[data-theme="dark"]{color-scheme:dark}
|
|
127
141
|
@media (prefers-color-scheme:light){:root:not([data-theme]){${declarations(WEB_THEME_TOKENS.light)};color-scheme:light}}
|
|
128
|
-
${SYNTAX_RULES}
|
|
142
|
+
${SYNTAX_RULES}
|
|
143
|
+
/* Paper is white: print the light palette whatever the screen is showing. */
|
|
144
|
+
@media print{:root{${declarations(WEB_THEME_TOKENS.light)};color-scheme:light}}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gavin-hu/my-pi-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
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, file-read, check, memory, context, wechat, and bytefly.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"compat:versions": "bun run scripts/peer-versions.ts",
|
|
128
128
|
"bench:render": "bun run scripts/render-bench.ts",
|
|
129
129
|
"screenshot:file-browse": "bun run scripts/file-browse-shot.ts",
|
|
130
|
+
"screenshot:plan-flow": "bun run scripts/plan-flow-shot.ts",
|
|
130
131
|
"screenshot:plan": "bun run scripts/plan-review-shot.ts",
|
|
131
132
|
"screenshot:tools": "bun run scripts/tool-renderings.ts gallery assets/tool-renderings.png",
|
|
132
133
|
"screenshot:tool-pngs": "bun run scripts/tool-renderings.ts tools assets/tools",
|
|
@@ -158,6 +159,7 @@
|
|
|
158
159
|
"@types/bun": "latest",
|
|
159
160
|
"@types/qrcode": "^1.5.5",
|
|
160
161
|
"get-east-asian-width": "^1.6.0",
|
|
162
|
+
"playwright-core": "^1.64.1",
|
|
161
163
|
"typebox": "^1.3.27",
|
|
162
164
|
"typescript": "^5.6.0"
|
|
163
165
|
}
|
|
@@ -1,48 +1,37 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: changelog
|
|
3
|
-
description: "Maintain a Keep a Changelog file:
|
|
3
|
+
description: "Maintain a Keep a Changelog file: record one user-visible bullet in the same commit, audit commits since the last tag for missing or weak entries, and curate a release section from the project's own rules. Use when writing, auditing, or releasing a changelog, not for ordinary code edits."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Maintain the changelog
|
|
7
7
|
|
|
8
8
|
This is a procedure, not a second policy. Read the project's instructions first;
|
|
9
|
-
where they disagree with this skill, the project wins. There are
|
|
10
|
-
**
|
|
11
|
-
|
|
12
|
-
`... release` name the others; with no mode, infer draft versus record from
|
|
13
|
-
whether the behavior already exists.
|
|
9
|
+
where they disagree with this skill, the project wins. There are three modes:
|
|
10
|
+
**record** (the default), **audit**, and **release**. `/skill:changelog` records;
|
|
11
|
+
`... audit` and `... release` name the others.
|
|
14
12
|
|
|
15
13
|
## 1. Read the project profile
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
In this package the profile is written down; read it rather than rediscover it:
|
|
18
16
|
|
|
19
|
-
- the
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
17
|
+
- [`../../CHANGELOG.md`](../../CHANGELOG.md) — the preamble, the scope prefixes,
|
|
18
|
+
and the bullet shape in use;
|
|
19
|
+
- [`../../AGENTS.md`](../../AGENTS.md) — the entry lands in the same commit as the
|
|
20
|
+
change, and a behavior change also updates the two entry READMEs and `docs/`;
|
|
21
|
+
- [`../../docs/development.md#release`](../../docs/development.md#release) — the
|
|
22
|
+
normative release procedure: version bump, link refs, tag and push order;
|
|
23
|
+
- [`../../test/release.test.ts`](../../test/release.test.ts) — the guard on
|
|
24
|
+
subsection names, order, emptiness, and the version pin.
|
|
25
|
+
|
|
26
|
+
Everywhere else, find the same six things: the changelog and its preamble, the
|
|
27
|
+
category spelling and order, the scope prefix and one-bullet-per-unit rule,
|
|
28
|
+
whether the entry ships with the change, the release document with its bump and
|
|
29
|
+
push order, and the check command with any release-consistency test.
|
|
25
30
|
|
|
26
31
|
State the profile in one short paragraph. Do not invent a rule the project never
|
|
27
32
|
stated; ask instead.
|
|
28
33
|
|
|
29
|
-
## 2.
|
|
30
|
-
|
|
31
|
-
For a new feature, draft the bullet in the plan or a scratchpad, not in
|
|
32
|
-
`CHANGELOG.md`.
|
|
33
|
-
|
|
34
|
-
- Write one line in the project's shape: ``- `scope`: <what the user can now do>``.
|
|
35
|
-
- If you cannot state the outcome, or need several unrelated bullets, the feature
|
|
36
|
-
is not scoped yet; split it or ask before coding.
|
|
37
|
-
- Name the intended category and any migration, breaking change, or required
|
|
38
|
-
action now, while the scope is still open.
|
|
39
|
-
- Use the draft as the acceptance criterion: implementation is done when the
|
|
40
|
-
behavior it describes is true and tested.
|
|
41
|
-
- Keep it out of the changelog until the code lands; a draft is not a shipped
|
|
42
|
-
claim. Update it when the outcome changes, then move it into `[Unreleased]` in
|
|
43
|
-
the same commit as the code (**Record**).
|
|
44
|
-
|
|
45
|
-
## 3. Classify the change
|
|
34
|
+
## 2. Classify the change
|
|
46
35
|
|
|
47
36
|
It qualifies when a user can observe it: behavior, a CLI/tool/command surface, a
|
|
48
37
|
config default, packaging, security, or a documented promise that is now true or
|
|
@@ -57,7 +46,7 @@ be one bullet if users see one outcome; two observable changes are two bullets.
|
|
|
57
46
|
Ask when the outcome is unclear. Never invent an entry to make an audit look
|
|
58
47
|
complete.
|
|
59
48
|
|
|
60
|
-
##
|
|
49
|
+
## 3. Record
|
|
61
50
|
|
|
62
51
|
- Write the entry in the same commit as the change. If the change is already
|
|
63
52
|
pushed without one, add a follow-up commit rather than rewriting history.
|
|
@@ -68,24 +57,40 @@ complete.
|
|
|
68
57
|
- Exclude file names, internal helpers, test counts, commit hashes, and vague
|
|
69
58
|
words such as "various" or "improvements".
|
|
70
59
|
- Match the file's voice and tense. Do not add marketing.
|
|
60
|
+
- A behavior change also updates its row in the catalog tables of
|
|
61
|
+
[`../../README.md`](../../README.md) and
|
|
62
|
+
[`../../README.zh-CN.md`](../../README.zh-CN.md) plus the `docs/` guide it
|
|
63
|
+
belongs to; the changelog is this skill's subject, not its only file. A skill's
|
|
64
|
+
change updates its `SKILL.md` and its README row together.
|
|
71
65
|
- Re-read immediately before editing, append within the category, and preserve
|
|
72
66
|
other bullets and concurrent edits. Never create a second category heading.
|
|
73
67
|
|
|
68
|
+
Shape: one blank-line-separated bullet per outcome, wrapped near 80 columns, the
|
|
69
|
+
scope in backticks followed by a colon. The scope is the extension or module name,
|
|
70
|
+
spelled as this package spells it — `bytefly`, `plan`, `wechat`, `todo` — or
|
|
71
|
+
`lib`, `docs`, `test`, `ci`, `skills`. A bullet with no scope, or with a name the
|
|
72
|
+
package does not use, is a defect. A bullet may run several sentences — say what
|
|
73
|
+
the user sees, what it replaced, and any required action. Brevity is not the
|
|
74
|
+
goal; vagueness is the defect.
|
|
75
|
+
|
|
74
76
|
Good:
|
|
75
77
|
|
|
76
78
|
```text
|
|
77
|
-
- `
|
|
78
|
-
|
|
79
|
+
- `config`: the report now says what its percentages are shares of. A
|
|
80
|
+
`Composition · 11k estimate` header sits above the rows, and a disabled
|
|
81
|
+
compaction no longer prints a headroom figure for a threshold that will never
|
|
82
|
+
fire.
|
|
83
|
+
- `cli`: `oldKey` is no longer read; run `bun run config:migrate`.
|
|
79
84
|
```
|
|
80
85
|
|
|
81
86
|
Bad:
|
|
82
87
|
|
|
83
88
|
```text
|
|
84
|
-
- `
|
|
89
|
+
- `config`: refactored invoice rendering and added tests.
|
|
85
90
|
- `misc`: improvements.
|
|
86
91
|
```
|
|
87
92
|
|
|
88
|
-
##
|
|
93
|
+
## 4. Audit (read-only)
|
|
89
94
|
|
|
90
95
|
1. Find the last tag: `git describe --tags --abbrev=0`, or the project's
|
|
91
96
|
equivalent.
|
|
@@ -107,29 +112,36 @@ since the tag contain user-visible changes.
|
|
|
107
112
|
Do not edit during the audit unless the user asks. If they do, return to
|
|
108
113
|
**Record** and make only the entries the evidence supports.
|
|
109
114
|
|
|
110
|
-
##
|
|
115
|
+
## 5. Release (only when asked)
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
The project's release document is normative — in this package
|
|
118
|
+
[`../../docs/development.md#release`](../../docs/development.md#release), guarded
|
|
119
|
+
by [`../../test/release.test.ts`](../../test/release.test.ts). This is a
|
|
120
|
+
checklist, not a replacement:
|
|
114
121
|
|
|
115
122
|
- Confirm the version and the SemVer reason with the user.
|
|
116
123
|
- Move every `[Unreleased]` entry under `## [X.Y.Z] - YYYY-MM-DD`; leave an empty
|
|
117
124
|
`[Unreleased]` heading.
|
|
118
|
-
- Bump every manifest and update the compare and release link refs
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
- Bump every manifest and update the compare and release link refs, in the same
|
|
126
|
+
commit as the movable part; the version in the manifest and the newest dated
|
|
127
|
+
heading must agree or the release test fails.
|
|
128
|
+
- Run the project's release checks, then `bun test test/release.test.ts` for the
|
|
129
|
+
version and subsection rules.
|
|
130
|
+
- Tag, push, and publish only with explicit approval, in the project's order. The
|
|
131
|
+
order matters: push the tag with `main`, never after it.
|
|
121
132
|
- Keep the release commit mechanical: no behavior, code, or unrelated docs.
|
|
122
|
-
- Use that section as the release body
|
|
133
|
+
- Use that section as the release body (`bun run release:notes X.Y.Z` prints it);
|
|
134
|
+
do not add extra prose.
|
|
123
135
|
|
|
124
|
-
##
|
|
136
|
+
## 6. Quality gate
|
|
125
137
|
|
|
126
138
|
- One bullet per user-visible change; every bullet starts with a scope and a user
|
|
127
|
-
outcome.
|
|
139
|
+
outcome, and may take several sentences to state it.
|
|
128
140
|
- No internal-only or duplicate entries, and no empty category headings.
|
|
129
141
|
- No entry for a change that shipped before its heading.
|
|
130
142
|
- Links and versions agree; the project check passes.
|
|
131
143
|
|
|
132
|
-
##
|
|
144
|
+
## 7. Report and stop
|
|
133
145
|
|
|
134
146
|
Say what was recorded, what the audit found, or what the release moved. List what
|
|
135
147
|
was deliberately left out and why. When nothing qualifies, say so. Stop before
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: next
|
|
3
|
+
description: "Decide what to do next from a project's real state, or from the current conversation: loose work in the tree, commits since the last tag, unreleased changelog entries, roadmap or plan items still open, and the project's check command. Returns a short ranked list with the evidence for each item and the command that starts it; read-only, it never edits, commits, or begins the work. Use when asked what to do next, where to pick up, what is left, or what to work on now."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Decide what to do next
|
|
7
|
+
|
|
8
|
+
This is a triage, not a work session. The deliverable is a short ranked list with
|
|
9
|
+
evidence; do not edit, commit, tag, or start the top item. The skill is
|
|
10
|
+
model-invoked when a request matches the description; `/skill:next` is the
|
|
11
|
+
explicit fallback. Read the project's own instructions first; where they disagree
|
|
12
|
+
with this skill, the project wins.
|
|
13
|
+
|
|
14
|
+
Two sibling skills own a narrower question: an audit of *where to refactor* is
|
|
15
|
+
`refactor`, and *what the last tag owes the changelog* is `changelog`. When the
|
|
16
|
+
request is already scoped to one of those, name the skill that answers it and
|
|
17
|
+
hand over, instead of returning a generic list.
|
|
18
|
+
|
|
19
|
+
A next-steps block that the host draws itself is not this skill's output: that is
|
|
20
|
+
the reply's suggested follow-up, a turn-level hint. This skill inspects state, so
|
|
21
|
+
its list survives the conversation that produced it.
|
|
22
|
+
|
|
23
|
+
## 1. Read the request
|
|
24
|
+
|
|
25
|
+
The host appends the text after the command to these instructions as the request.
|
|
26
|
+
It is `<prompt>` in `/skill:next <prompt>`, it comes before any reading, and it
|
|
27
|
+
carries up to three parts:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
/skill:next [session] [what you want] [@path ...]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- **`session`, first word** — session mode (section 3). The rest of the prompt
|
|
34
|
+
keeps its own meaning: `/skill:next session what is left?` is session mode with
|
|
35
|
+
a filter, not a filter of `session`.
|
|
36
|
+
- **What you want** — a question, a goal, or a topic: "what is left before
|
|
37
|
+
0.17?", "plan file outline". It chooses what the shortlist is about and keeps
|
|
38
|
+
only the sources that can answer it; say which ones you kept. A named release,
|
|
39
|
+
file, or feature is the filter.
|
|
40
|
+
- **One or more paths** — `@src`, `src`, `packages/api`, or one inside the
|
|
41
|
+
sentence. Resolve each from the working directory, and take the evidence from
|
|
42
|
+
there: that path's diffs, plan steps, roadmap items, and changelog scope. A path
|
|
43
|
+
that does not exist is reported and asked about, never guessed.
|
|
44
|
+
- **Both** — the usual case. `/skill:next plan file outline @extensions/plan/`
|
|
45
|
+
asks what to do next about the plan file outline, with `@extensions/plan/` as
|
|
46
|
+
the evidence, so a roadmap item, a plan step, or a changelog entry outside that
|
|
47
|
+
path is not a candidate.
|
|
48
|
+
- **An imperative** — "fix the failing test" names one piece of work, and the
|
|
49
|
+
prompt is not approval for it. Answer with that item alone — evidence, starting
|
|
50
|
+
command, effort — and ask before starting, instead of producing a list.
|
|
51
|
+
- **No prompt** — triage of the current project.
|
|
52
|
+
- **Anything unreadable** — triage anyway, and say in one clause how you read the
|
|
53
|
+
prompt, so a misreading is visible in the report rather than silently narrowing
|
|
54
|
+
the list.
|
|
55
|
+
|
|
56
|
+
## 2. Read the project profile
|
|
57
|
+
|
|
58
|
+
With the request read, find:
|
|
59
|
+
|
|
60
|
+
- the instruction files, and whether they require isolation (a worktree, a
|
|
61
|
+
branch) or a specific check;
|
|
62
|
+
- the check command — the one that proves the tree is green; the triage quotes it
|
|
63
|
+
and never runs it (section 4);
|
|
64
|
+
- where work is tracked: a roadmap, an issue tracker, `TODO` docs, a plans
|
|
65
|
+
directory, a changelog;
|
|
66
|
+
- the release path: what a tag, a version bump, or an unreleased entry owes;
|
|
67
|
+
- the VCS, its branch model, and the last tag if there is one.
|
|
68
|
+
|
|
69
|
+
State the profile in one or two lines. Do not invent a source the project does
|
|
70
|
+
not have; a project with no roadmap is triaged from git and the check alone.
|
|
71
|
+
|
|
72
|
+
## 3. Choose the mode
|
|
73
|
+
|
|
74
|
+
- **Triage** — what the tree says. Use git, the changelog, the roadmap or issues,
|
|
75
|
+
and the plans directory. This is the default.
|
|
76
|
+
- **Session** — what this conversation left open. Read the conversation's own
|
|
77
|
+
record: the todo list, the goal, the approved plan and its ticked steps, what
|
|
78
|
+
subagents and jobs returned, and the diff this session produced. Then list the
|
|
79
|
+
loose ends it left: uncommitted files, an unapproved plan, a claim that was
|
|
80
|
+
never run, a documented behavior that changed without a doc or changelog edit.
|
|
81
|
+
- When both apply, run triage and read the session for context; the tree wins,
|
|
82
|
+
because it is where the work actually is.
|
|
83
|
+
|
|
84
|
+
Mode and scope are independent: session mode still honours a path, and triage
|
|
85
|
+
with a path reads the whole tree's evidence before narrowing. State the mode, the
|
|
86
|
+
scope, and the prompt as read, at the top of the report.
|
|
87
|
+
|
|
88
|
+
## 4. Gather evidence
|
|
89
|
+
|
|
90
|
+
Read only; nothing in this stage writes. Follow the project's own tool
|
|
91
|
+
discipline, and say what you could not read.
|
|
92
|
+
|
|
93
|
+
| Source | What it proves |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `git status --short`, `git diff --stat` | Work in flight, and whose it is |
|
|
96
|
+
| `git log --oneline <last-tag>..HEAD` | What has landed unreleased |
|
|
97
|
+
| `git worktree list`, `git branch --no-merged` | An isolated tree left behind, a branch never merged |
|
|
98
|
+
| The changelog's `[Unreleased]` | Whether a landed change is recorded, and whether the window is empty |
|
|
99
|
+
| The roadmap, issue tracker, or `TODO` docs | The project's stated priorities, and which are already done |
|
|
100
|
+
| The plans directory (`.pi/plans` or the project's equivalent) | An approved plan whose steps remain |
|
|
101
|
+
| The todo list, the goal, job and subagent results | What the session promised and did not finish |
|
|
102
|
+
| The check command | Whether the tree is green — cite the last known result, and make running it the item's starting command rather than running it here |
|
|
103
|
+
|
|
104
|
+
A roadmap, a changelog, and a plan all lag the tree. Verify a candidate against
|
|
105
|
+
the code before recommending it, and drop one that is already done.
|
|
106
|
+
|
|
107
|
+
## 5. Verify and filter
|
|
108
|
+
|
|
109
|
+
A candidate is not a suggestion until it has one concrete artifact: a path with
|
|
110
|
+
line numbers, a command's output, a diff hunk, or a failing test name. If you
|
|
111
|
+
cannot point at it, drop it.
|
|
112
|
+
|
|
113
|
+
- Reject anything already done, already documented as a deliberate non-goal, or
|
|
114
|
+
blocked on a decision the user has not made — say which, and ask if it matters.
|
|
115
|
+
- Keep a bug separate from a preference, and a refactor separate from a fix.
|
|
116
|
+
- Prefer the candidate with a fast verification command.
|
|
117
|
+
- Never invent work to fill the list. An empty list is a valid answer.
|
|
118
|
+
|
|
119
|
+
## 6. Rank by cost of loss
|
|
120
|
+
|
|
121
|
+
Order by what it would cost to lose, cheapest loss first:
|
|
122
|
+
|
|
123
|
+
- **Loose work** — a dirty tree, an unapproved plan, a check that has not been
|
|
124
|
+
run, an unmerged branch, a worktree left behind, a stopped job.
|
|
125
|
+
- **A broken promise** — a README, roadmap, or doc claim the code no longer
|
|
126
|
+
meets, a released behavior with no test.
|
|
127
|
+
- **An unfinished promise** — a stated roadmap item, the remaining steps of an
|
|
128
|
+
approved plan, a documented limitation with no item, an unreleased change with
|
|
129
|
+
no changelog entry.
|
|
130
|
+
- **New reach** — a capability nobody has asked for comes last, and only when the
|
|
131
|
+
three above are empty.
|
|
132
|
+
|
|
133
|
+
Label each item with the ceremony it needs. The label is not a second ordering:
|
|
134
|
+
cost of loss decides the order, and the label says how much work the item takes.
|
|
135
|
+
|
|
136
|
+
- **Do next** — cheap, safe, and unblocks the rest.
|
|
137
|
+
- **Worth planning** — high value, but it spans files, changes a public surface,
|
|
138
|
+
or needs a decision first.
|
|
139
|
+
- **Later** — real, but not now.
|
|
140
|
+
|
|
141
|
+
Cap the list at three to five items, and let a tier be empty. A roadmap restated
|
|
142
|
+
as ten suggestions is not a triage. Do not invent a numeric score; the reason
|
|
143
|
+
must be readable.
|
|
144
|
+
|
|
145
|
+
## 7. Report
|
|
146
|
+
|
|
147
|
+
- **State** — one paragraph: the mode, the scope and how the prompt was read,
|
|
148
|
+
the branch or worktree, what is dirty, what is unreleased, and whether the
|
|
149
|
+
check passes. Name anything you could not read.
|
|
150
|
+
- **The shortlist** — each item with its label, the action, the evidence at
|
|
151
|
+
`path:line` or the command output that proves it, the command that starts it,
|
|
152
|
+
and effort (S/M/L). Link the file the item lives in.
|
|
153
|
+
- **Rejected or stale** — one line each, with the reason the roadmap, changelog,
|
|
154
|
+
or plan entry no longer applies.
|
|
155
|
+
- **Next step** — ask which item to start. Do not start it, and do not open with
|
|
156
|
+
an edit.
|
|
157
|
+
|
|
158
|
+
If the host expects a closing next-steps block, keep it to the top two or three
|
|
159
|
+
choices as one line each; the evidence stays in the list above, never repeated
|
|
160
|
+
there.
|
|
161
|
+
|
|
162
|
+
## 8. Handoff
|
|
163
|
+
|
|
164
|
+
When the user picks an item, the audit is over:
|
|
165
|
+
|
|
166
|
+
- Restate the chosen item as a task with its acceptance test.
|
|
167
|
+
- Enter plan mode when the host provides it and the item spans files, changes a
|
|
168
|
+
public surface, or has an unknown step list. Track a small one in a todo list.
|
|
169
|
+
- Run the project's check first for a baseline, and finish with the full check.
|
|
170
|
+
- Do not commit unless the user asks.
|
|
171
|
+
|
|
172
|
+
## 9. Stop conditions
|
|
173
|
+
|
|
174
|
+
- Nothing worth doing: say so, with what was checked, instead of inventing work.
|
|
175
|
+
- The tree is mid-rebase, mid-merge, mid-bisect, or has a conflict: reconciling it
|
|
176
|
+
is the only next item; nothing else is safe to suggest.
|
|
177
|
+
- The project has no work tracking: say the list is derived from git and the check
|
|
178
|
+
only, and suggest recording the plan or roadmap the project is missing.
|
|
179
|
+
- A candidate needs a destructive command (a branch delete, a worktree prune, a
|
|
180
|
+
history rewrite) to start: name it as a decision for the user, not as a step.
|
|
181
|
+
|
|
182
|
+
The triage is done when the mode is stated, every item has evidence and a
|
|
183
|
+
starting command, the list is capped, rejected candidates are explained, and no
|
|
184
|
+
file was modified.
|