@gavin-hu/my-pi-agent 0.16.0 → 0.18.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 +29 -15
- package/README.zh-CN.md +27 -15
- package/extensions/bytefly/README.md +195 -115
- 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/notify/types.ts +1 -1
- 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 +29 -39
- 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 +89 -22
- package/extensions/file-browse/chrome.ts +83 -0
- package/extensions/file-browse/client.ts +74 -459
- package/extensions/file-browse/config.ts +12 -3
- package/extensions/file-browse/diff-html.ts +94 -0
- package/extensions/file-browse/html.ts +26 -152
- package/extensions/file-browse/live-client.ts +47 -1
- package/extensions/file-browse/live.ts +35 -14
- package/extensions/file-browse/palette.ts +224 -0
- package/extensions/file-browse/rev.ts +42 -0
- package/extensions/file-browse/router.ts +27 -6
- package/extensions/file-browse/server.ts +7 -0
- package/extensions/file-browse/styles.ts +10 -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/plan-route.ts +8 -2
- package/extensions/goal/tools.ts +6 -11
- package/extensions/job/README.md +7 -5
- package/extensions/job/index.ts +35 -52
- package/extensions/job/tools.ts +51 -77
- package/extensions/memory/README.md +3 -3
- package/extensions/memory/tools.ts +4 -6
- package/extensions/memory/tui.ts +5 -1
- package/extensions/plan/README.md +333 -84
- package/extensions/plan/commands.ts +73 -7
- package/extensions/plan/feedback.ts +300 -63
- package/extensions/plan/index.ts +1 -1
- package/extensions/plan/plan-index.ts +4 -2
- package/extensions/plan/plan-text.ts +18 -1
- package/extensions/plan/plans.ts +184 -58
- package/extensions/plan/review-prompt.ts +93 -0
- package/extensions/plan/review.ts +95 -95
- package/extensions/plan/runtime.ts +4 -2
- package/extensions/plan/split.ts +87 -0
- package/extensions/plan/steps.ts +123 -107
- package/extensions/plan/tools/cancel.ts +79 -0
- package/extensions/plan/tools/enter.ts +17 -12
- package/extensions/plan/tools/exit.ts +148 -59
- package/extensions/plan/tools/steps.ts +7 -19
- package/extensions/plan/tools/write.ts +29 -31
- package/extensions/plan/tools.ts +6 -3
- package/extensions/plan/tui.ts +60 -15
- package/extensions/plan/types.ts +45 -3
- package/extensions/plan/web-chrome.ts +102 -0
- package/extensions/plan/web-client.ts +177 -446
- package/extensions/plan/web-collab.ts +207 -0
- package/extensions/plan/web-comments.ts +269 -0
- package/extensions/plan/web-markdown.ts +222 -0
- package/extensions/plan/web-page.ts +131 -19
- package/extensions/plan/web-router.ts +148 -32
- package/extensions/plan/web-share-session.ts +197 -0
- package/extensions/plan/web-share.ts +169 -0
- package/extensions/plan/web-streams.ts +124 -0
- package/extensions/plan/web-tokens.ts +63 -0
- package/extensions/plan/web.ts +193 -45
- package/extensions/question/README.md +3 -0
- package/extensions/question/dialogs.ts +91 -1
- package/extensions/question/tools.ts +2 -1
- 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/session-bus/README.md +247 -0
- package/extensions/session-bus/commands.ts +165 -0
- package/extensions/session-bus/format.ts +124 -0
- package/extensions/session-bus/index.ts +69 -0
- package/extensions/session-bus/notice.ts +58 -0
- package/extensions/session-bus/protocol.ts +134 -0
- package/extensions/session-bus/result.ts +243 -0
- package/extensions/session-bus/rows.ts +169 -0
- package/extensions/session-bus/runtime.ts +575 -0
- package/extensions/session-bus/store.ts +329 -0
- package/extensions/session-bus/team.ts +102 -0
- package/extensions/session-bus/tools.ts +227 -0
- package/extensions/session-bus/tui.ts +394 -0
- package/extensions/session-bus/types.ts +98 -0
- package/extensions/subagent/README.md +26 -13
- 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/README.md +9 -5
- package/extensions/watch/index.ts +25 -44
- package/extensions/watch/tools.ts +31 -59
- package/extensions/wechat/README.md +45 -36
- package/extensions/wechat/bridge.ts +46 -48
- package/extensions/wechat/client.ts +1 -4
- package/extensions/wechat/commands.ts +3 -3
- package/extensions/wechat/deliver.ts +57 -37
- package/extensions/wechat/interaction.ts +54 -18
- package/extensions/wechat/login-screen.ts +2 -3
- package/extensions/wechat/notices.ts +9 -7
- package/extensions/wechat/peer-worker.ts +19 -34
- package/extensions/wechat/presence.ts +3 -4
- package/extensions/wechat/prompt.ts +53 -23
- package/extensions/wechat/reply-pipeline.ts +12 -4
- 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/git.ts +5 -0
- package/extensions/worktree/lifecycle.ts +9 -1
- package/extensions/worktree/registry.ts +11 -5
- package/extensions/worktree/screen.ts +263 -0
- package/extensions/worktree/status.ts +84 -40
- package/lib/README.md +12 -7
- package/lib/claims/overlap.ts +43 -0
- package/lib/config.ts +12 -0
- package/lib/format.ts +6 -2
- package/lib/http/router.ts +40 -13
- package/lib/http/server.ts +27 -13
- package/lib/interaction.ts +28 -1
- package/lib/notice.ts +29 -2
- package/lib/plan-entry.ts +7 -2
- package/lib/plans/sections.ts +172 -0
- package/lib/plans/setting.ts +52 -0
- package/lib/plans/split.ts +215 -0
- package/lib/plans/store.ts +19 -0
- package/lib/plans/team.ts +151 -0
- package/lib/qr.ts +64 -0
- package/lib/repo-key.ts +74 -0
- package/lib/report.ts +117 -25
- package/lib/requirements.ts +1 -2
- package/lib/tool-result.ts +54 -4
- package/lib/tui/README.md +30 -8
- package/lib/tui/chrome.ts +27 -6
- package/lib/tui/dock-screen.ts +91 -19
- package/lib/tui/gauge.ts +9 -5
- package/lib/tui/line-pane.ts +15 -4
- package/lib/tui/tool.ts +23 -4
- 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 +5 -2
- package/skills/changelog/SKILL.md +57 -45
- package/skills/init/SKILL.md +80 -45
- package/skills/init/references/agents-md-quality.md +26 -2
- package/skills/init/references/interview-questions.md +36 -14
- package/skills/next/SKILL.md +209 -0
- package/skills/parallel-dev/SKILL.md +150 -0
- package/extensions/wechat/qrcode.ts +0 -46
package/extensions/plan/tui.ts
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* the active Markdown theme, so headings, lists, code, links, and quotes match
|
|
7
7
|
* the rest of the application; plan-authored control characters are stripped
|
|
8
8
|
* first so the file cannot drive the terminal. Task checkboxes are recolored
|
|
9
|
-
* and the footer colors the primary actions.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* and the footer colors the primary actions. Approving leaves plan mode and
|
|
10
|
+
* starts the work, so it asks `y/N` first through the shared `ConfirmState`;
|
|
11
|
+
* the plan stays mounted, and `Esc` backs out of the question before it backs
|
|
12
|
+
* out of the review. It returns the chosen action through `onClose` so the
|
|
13
|
+
* caller can act only after the screen is gone and input focus is free again.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
import { basename } from "node:path";
|
|
@@ -27,6 +29,7 @@ import {
|
|
|
27
29
|
type TuiMouseEventResult,
|
|
28
30
|
} from "@earendil-works/pi-tui";
|
|
29
31
|
import { sanitizeLine } from "../../lib/format.ts";
|
|
32
|
+
import { renderTeam, type PlanUnit } from "../../lib/plans/team.ts";
|
|
30
33
|
import {
|
|
31
34
|
editorTheme,
|
|
32
35
|
screenHint,
|
|
@@ -35,17 +38,18 @@ import {
|
|
|
35
38
|
type ViewportRowsSource,
|
|
36
39
|
} from "../../lib/tui/chrome.ts";
|
|
37
40
|
import { isCloseKey } from "../../lib/tui/cursor.ts";
|
|
41
|
+
import { ConfirmState } from "../../lib/tui/confirm.ts";
|
|
38
42
|
import { gaugeBar } from "../../lib/tui/gauge.ts";
|
|
39
43
|
import { GLYPHS } from "../../lib/tui/glyphs.ts";
|
|
40
|
-
import { titleRule } from "../../lib/tui/rules.ts";
|
|
44
|
+
import { plainRule, titleRule } from "../../lib/tui/rules.ts";
|
|
41
45
|
import { emptyState, checkbox } from "../../lib/tui/rows.ts";
|
|
42
46
|
import { paint } from "../../lib/tui/tokens.ts";
|
|
43
47
|
import { planTitle, type StoredPlan } from "./plans.ts";
|
|
44
|
-
import { changedSections,
|
|
48
|
+
import { changedSections, planDisplayText, type SectionDigest } from "./plan-text.ts";
|
|
45
49
|
import { extractPlanSections } from "./steps.ts";
|
|
46
50
|
|
|
47
51
|
/** What the user chose from the read/review screen. */
|
|
48
|
-
export type PlanViewAction = "approve" | "refine" | "keep" | "browser";
|
|
52
|
+
export type PlanViewAction = "approve" | "refine" | "keep" | "browser" | "cancel";
|
|
49
53
|
|
|
50
54
|
/** A plan section's rendered start line, for navigation and the current-section label. */
|
|
51
55
|
interface SectionOffset {
|
|
@@ -83,11 +87,16 @@ export interface PlanViewOptions {
|
|
|
83
87
|
tui?: TUI;
|
|
84
88
|
/** Markdown theme for the body; defaults to Pi's active theme. */
|
|
85
89
|
markdownTheme?: MarkdownTheme;
|
|
90
|
+
/**
|
|
91
|
+
* The split approval would write. Rendered as a read-only section after the
|
|
92
|
+
* plan, because the `## Team` section itself only exists after approval.
|
|
93
|
+
*/
|
|
94
|
+
split?: { lead: string; units: readonly PlanUnit[]; verdict: "pair" | "team" };
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
/** Rows the screen shows when the terminal height is unknown. */
|
|
89
98
|
const DEFAULT_ROWS = 20;
|
|
90
|
-
/** Header, blanks, footer, and
|
|
99
|
+
/** Header, blanks, footer, and closing rule around a non-empty plan. */
|
|
91
100
|
const CHROME_ROWS = 5;
|
|
92
101
|
/** Narrowest width where Markdown's 2-column padding still fits the body. */
|
|
93
102
|
const MIN_PADDED_WIDTH = 6;
|
|
@@ -97,13 +106,14 @@ const BODY_PADDING = 2;
|
|
|
97
106
|
const GAUGE_SEGMENTS = 10;
|
|
98
107
|
/** Footer hints shared by the review and the inline editor's primary actions. */
|
|
99
108
|
const PRIMARY_HINTS: ScreenHint[] = [
|
|
100
|
-
"Esc keep
|
|
101
|
-
{ text: "a approve
|
|
109
|
+
"Esc keep plan",
|
|
110
|
+
{ text: "a approve", color: "success" },
|
|
102
111
|
{ text: "r refine", color: "accent" },
|
|
103
112
|
{ text: "w browser", color: "accent" },
|
|
113
|
+
{ text: "x exit plan", color: "warning" },
|
|
104
114
|
];
|
|
105
115
|
/** Scroll keys appended to the review footer while the plan overflows. */
|
|
106
|
-
const SCROLL_HINTS: ScreenHint[] = ["
|
|
116
|
+
const SCROLL_HINTS: ScreenHint[] = ["j/k scroll", "space page", "g/G ends"];
|
|
107
117
|
/** Section-jump hint, shown when the plan has more than one heading section. */
|
|
108
118
|
const SECTION_HINTS: ScreenHint[] = ["n/p section"];
|
|
109
119
|
|
|
@@ -174,6 +184,8 @@ export class PlanViewComponent implements Component {
|
|
|
174
184
|
private cache: BodyCache | null = null;
|
|
175
185
|
/** True while the inline refine editor owns the keyboard. */
|
|
176
186
|
private editing = false;
|
|
187
|
+
/** The y/N approval question, shared with the other destructive screens. */
|
|
188
|
+
private readonly confirm = new ConfirmState();
|
|
177
189
|
/** The inline refine editor, built lazily once a TUI handle is available. */
|
|
178
190
|
private editor: Editor | null = null;
|
|
179
191
|
|
|
@@ -194,7 +206,7 @@ export class PlanViewComponent implements Component {
|
|
|
194
206
|
const padding = width >= MIN_PADDED_WIDTH ? BODY_PADDING : 0;
|
|
195
207
|
const base = this.options.markdownTheme ?? getMarkdownTheme();
|
|
196
208
|
const theme = planMarkdownTheme(this.theme, base);
|
|
197
|
-
const current =
|
|
209
|
+
const current = planDisplayText(this.options.plan.content);
|
|
198
210
|
const changed = changedSections(this.options.baseline, current);
|
|
199
211
|
const chunks = extractPlanSections(current);
|
|
200
212
|
const lines: string[] = [];
|
|
@@ -215,10 +227,31 @@ export class PlanViewComponent implements Component {
|
|
|
215
227
|
// chunk omits before the next section.
|
|
216
228
|
if (index < chunks.length - 1 && lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
|
|
217
229
|
});
|
|
230
|
+
const split = this.splitSection();
|
|
231
|
+
if (split !== undefined) {
|
|
232
|
+
if (lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
|
|
233
|
+
const rendered = new Markdown(split, padding, 0, theme)
|
|
234
|
+
.render(width)
|
|
235
|
+
.map((line) => truncateToWidth(line.trimEnd(), width));
|
|
236
|
+
sections.push({ title: "Split", offset: lines.length });
|
|
237
|
+
lines.push(...rendered);
|
|
238
|
+
}
|
|
218
239
|
this.cache = { width, lines, sections, changedCount: changed.filter(Boolean).length };
|
|
219
240
|
return this.cache;
|
|
220
241
|
}
|
|
221
242
|
|
|
243
|
+
/**
|
|
244
|
+
* The split as a read-only section: the same table approval writes, so what the
|
|
245
|
+
* user approves is what the plan file will carry.
|
|
246
|
+
*/
|
|
247
|
+
private splitSection(): string | undefined {
|
|
248
|
+
const split = this.options.split;
|
|
249
|
+
if (split === undefined) return undefined;
|
|
250
|
+
const owners = split.units.filter((unit) => !unit.lead).length;
|
|
251
|
+
const summary = `${split.verdict} · lead + ${owners} owner${owners === 1 ? "" : "s"} · written on approval`;
|
|
252
|
+
return ["## Split", "", summary, "", renderTeam({ lead: split.lead, units: [...split.units] })].join("\n");
|
|
253
|
+
}
|
|
254
|
+
|
|
222
255
|
/** The section whose heading is at or above the viewport top. */
|
|
223
256
|
private currentSection(sections: SectionOffset[]): SectionOffset | undefined {
|
|
224
257
|
let current: SectionOffset | undefined;
|
|
@@ -313,6 +346,12 @@ export class PlanViewComponent implements Component {
|
|
|
313
346
|
this.options.requestRender();
|
|
314
347
|
return;
|
|
315
348
|
}
|
|
349
|
+
// A pending question owns the keyboard, so a scroll key cannot slip past it
|
|
350
|
+
// and `Esc` backs out of the question rather than the review.
|
|
351
|
+
if (this.confirm.pending) {
|
|
352
|
+
if (this.confirm.resolve(data) !== undefined) this.options.requestRender();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
316
355
|
if (isCloseKey(data)) {
|
|
317
356
|
this.options.onClose("keep");
|
|
318
357
|
return;
|
|
@@ -329,9 +368,12 @@ export class PlanViewComponent implements Component {
|
|
|
329
368
|
else if (matchesKey(data, Key.end) || data === "G") this.scrollTo(this.maxOffset);
|
|
330
369
|
else if (data === "n") this.jumpSection(1);
|
|
331
370
|
else if (data === "p") this.jumpSection(-1);
|
|
332
|
-
else if (data === "a")
|
|
333
|
-
|
|
371
|
+
else if (data === "a") {
|
|
372
|
+
this.confirm.ask("Approve and run the plan? y/N", () => this.options.onClose("approve"));
|
|
373
|
+
this.options.requestRender();
|
|
374
|
+
} else if (data === "r") this.startRefine();
|
|
334
375
|
else if (data === "w") this.options.onClose("browser");
|
|
376
|
+
else if (data === "x") this.options.onClose("cancel");
|
|
335
377
|
}
|
|
336
378
|
|
|
337
379
|
/** Wheel scrolling in fullscreen; regular mode leaves the wheel to the terminal. */
|
|
@@ -398,12 +440,15 @@ export class PlanViewComponent implements Component {
|
|
|
398
440
|
} else {
|
|
399
441
|
if (this.maxOffset > 0) lines.push(scrollRow(theme, w, this.offset, end, body.length, sectionLabel));
|
|
400
442
|
else lines.push("");
|
|
443
|
+
const pending = this.confirm.pending;
|
|
401
444
|
const sectionHints = sections.length > 1 ? SECTION_HINTS : [];
|
|
402
445
|
const hints: ScreenHint[] =
|
|
403
446
|
this.maxOffset > 0 ? [...PRIMARY_HINTS, ...SCROLL_HINTS, ...sectionHints] : PRIMARY_HINTS;
|
|
404
|
-
lines.push(
|
|
447
|
+
lines.push(
|
|
448
|
+
pending ? truncateToWidth(` ${paint(theme, "warn", pending.prompt)}`, w) : screenHint(theme, w, hints),
|
|
449
|
+
);
|
|
405
450
|
}
|
|
406
|
-
lines.push(
|
|
451
|
+
lines.push(plainRule(theme, w));
|
|
407
452
|
return lines;
|
|
408
453
|
}
|
|
409
454
|
}
|
package/extensions/plan/types.ts
CHANGED
|
@@ -6,6 +6,32 @@ import type { PlanAnnotation } from "./feedback.ts";
|
|
|
6
6
|
import type { SectionDigest } from "./plan-text.ts";
|
|
7
7
|
import type { StepUpdate } from "./steps.ts";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Who is looking at a running review: the session that opened it (`owner`, the
|
|
11
|
+
* only role that can approve), or someone the link was shared with (`reviewer`,
|
|
12
|
+
* who may comment).
|
|
13
|
+
*/
|
|
14
|
+
export type ReviewRole = "owner" | "reviewer";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* What a review token names: its role, and — for a reviewer — the name it posts
|
|
18
|
+
* under, bound the first time that link writes.
|
|
19
|
+
*/
|
|
20
|
+
export interface ReviewCaller {
|
|
21
|
+
role: ReviewRole;
|
|
22
|
+
/** The reviewer's name, once this link has written; absent for the owner and
|
|
23
|
+
* for a reviewer that has not commented yet. */
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* One frame on the review's event stream. `comment`, `plan`, and `share` say a
|
|
29
|
+
* page should re-read the island; `closed` ends the review for everyone, and
|
|
30
|
+
* `revoked` tells a reviewer the owner stopped sharing. The frame carries no
|
|
31
|
+
* state of its own, so the island stays the one contract.
|
|
32
|
+
*/
|
|
33
|
+
export type ReviewFrame = "comment" | "plan" | "share" | "closed" | "revoked";
|
|
34
|
+
|
|
9
35
|
/** Persisted (custom entry) plan-mode state. */
|
|
10
36
|
export interface PlanModeEntry {
|
|
11
37
|
enabled: boolean;
|
|
@@ -38,7 +64,7 @@ export interface EnterPlanModeDetails {
|
|
|
38
64
|
export interface WritePlanDetails {
|
|
39
65
|
/** Absolute path of the written plan file. */
|
|
40
66
|
path: string;
|
|
41
|
-
/**
|
|
67
|
+
/** How the path is shown: `~`-shortened, since plans live outside the project. */
|
|
42
68
|
relativePath: string;
|
|
43
69
|
/** Size of the written plan in bytes. */
|
|
44
70
|
bytes: number;
|
|
@@ -48,7 +74,7 @@ export interface WritePlanDetails {
|
|
|
48
74
|
export interface SetPlanStepsDetails {
|
|
49
75
|
/** Absolute path of the plan file that was updated. */
|
|
50
76
|
path: string;
|
|
51
|
-
/**
|
|
77
|
+
/** How the path is shown: `~`-shortened. */
|
|
52
78
|
relativePath: string;
|
|
53
79
|
/** The checkbox changes that were applied, in call order. */
|
|
54
80
|
updates: StepUpdate[];
|
|
@@ -66,7 +92,7 @@ export interface ExitPlanModeDetails {
|
|
|
66
92
|
plan: string;
|
|
67
93
|
/** Absolute path of the reviewed plan file. */
|
|
68
94
|
planPath?: string;
|
|
69
|
-
/**
|
|
95
|
+
/** How the path is shown: `~`-shortened. */
|
|
70
96
|
relativePath?: string;
|
|
71
97
|
/** True when the user asked to refine the plan instead of approving. */
|
|
72
98
|
refined?: boolean;
|
|
@@ -74,6 +100,22 @@ export interface ExitPlanModeDetails {
|
|
|
74
100
|
refinement?: string;
|
|
75
101
|
/** Comments the review carried when it approved or requested a refinement. */
|
|
76
102
|
annotations?: PlanAnnotation[];
|
|
103
|
+
/** True when the user left plan mode without approving the plan. */
|
|
104
|
+
cancelled?: boolean;
|
|
77
105
|
/** True when no interactive UI was available to ask for approval. */
|
|
78
106
|
unavailable?: boolean;
|
|
107
|
+
/** The team approval wrote into the plan, when the plan was split. */
|
|
108
|
+
team?: {
|
|
109
|
+
lead: string;
|
|
110
|
+
units: Array<{ name: string; paths: string[]; test: string; dependsOn: string[] }>;
|
|
111
|
+
verdict: "pair" | "team";
|
|
112
|
+
};
|
|
113
|
+
/** True when the model proposed a split while `plan.split` was off. */
|
|
114
|
+
splitOff?: boolean;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Structured result carried in `cancel_plan_mode`'s `details`. */
|
|
118
|
+
export interface CancelPlanModeDetails {
|
|
119
|
+
/** True when plan mode was on and has now been turned off. */
|
|
120
|
+
cancelled: boolean;
|
|
79
121
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The review page's chrome: what the page says about itself.
|
|
3
|
+
*
|
|
4
|
+
* It is a fragment of the same IIFE `web-client.ts` ships (`WEB_CHROME_JS` is
|
|
5
|
+
* interpolated into `REVIEW_CLIENT_JS`), kept in its own module so the state
|
|
6
|
+
* chip, the status line, and the header are read together and away from the
|
|
7
|
+
* document rendering. It paints only text it was handed.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const WEB_CHROME_JS = String.raw` function setStatus(text, kind) {
|
|
11
|
+
if (!statusEl) return;
|
|
12
|
+
statusEl.textContent = text || "";
|
|
13
|
+
statusEl.title = text || "";
|
|
14
|
+
statusEl.className = kind ? "bf-status bf-status--" + kind : "bf-status";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// The always-visible header chip: connection, comment count, and whether
|
|
18
|
+
// there are edits the file does not have yet.
|
|
19
|
+
function updateState() {
|
|
20
|
+
if (!stateEl) return;
|
|
21
|
+
var label;
|
|
22
|
+
var tone = "";
|
|
23
|
+
if (approved) {
|
|
24
|
+
label = "Approved";
|
|
25
|
+
tone = "success";
|
|
26
|
+
} else if (saved) {
|
|
27
|
+
label = "Saved";
|
|
28
|
+
tone = "success";
|
|
29
|
+
} else if (closed) {
|
|
30
|
+
// Settled by the user, not by a dropped stream: never flash Offline.
|
|
31
|
+
label = "Closed";
|
|
32
|
+
} else if (connected === true) {
|
|
33
|
+
label = "Connected";
|
|
34
|
+
tone = "success";
|
|
35
|
+
} else if (everConnected) {
|
|
36
|
+
// Only after the stream has opened once: an error before that is a
|
|
37
|
+
// transient initial connect, so keep showing Connecting rather than Offline.
|
|
38
|
+
label = "Offline";
|
|
39
|
+
tone = "danger";
|
|
40
|
+
} else {
|
|
41
|
+
label = "Connecting\u2026";
|
|
42
|
+
}
|
|
43
|
+
var count = annotations.length;
|
|
44
|
+
label += " \u00b7 " + count + (count === 1 ? " comment" : " comments");
|
|
45
|
+
if (dirty && !saved && !approved && !closed) {
|
|
46
|
+
label += " \u00b7 " + (role === "reviewer" ? "unposted" : "unsaved");
|
|
47
|
+
if (!tone) tone = "warn";
|
|
48
|
+
}
|
|
49
|
+
stateEl.textContent = label;
|
|
50
|
+
stateEl.className = "bf-chip bf-chip--accent review-state" + (tone ? " bf-chip--" + tone : "");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function renderHeader() {
|
|
54
|
+
var titleEl = document.getElementById("plan-title");
|
|
55
|
+
if (titleEl && data.title) {
|
|
56
|
+
titleEl.textContent = data.title;
|
|
57
|
+
titleEl.title = data.title;
|
|
58
|
+
}
|
|
59
|
+
if (data.title) document.title = "Plan review \u00b7 " + data.title;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function updateProgress() {
|
|
63
|
+
if (!progressEl) return;
|
|
64
|
+
var doc = document.scrollingElement || document.documentElement;
|
|
65
|
+
var top = doc ? doc.scrollTop : 0;
|
|
66
|
+
var height = doc ? doc.scrollHeight : 0;
|
|
67
|
+
var view = doc ? doc.clientHeight : 0;
|
|
68
|
+
if (planEl && planEl.scrollHeight > planEl.clientHeight + 4) {
|
|
69
|
+
top = planEl.scrollTop; height = planEl.scrollHeight; view = planEl.clientHeight;
|
|
70
|
+
}
|
|
71
|
+
var max = height - view;
|
|
72
|
+
var percent = max > 0 ? Math.min(100, Math.max(0, (top / max) * 100)) : 0;
|
|
73
|
+
progressEl.style.width = percent + "%";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function lockActions() {
|
|
77
|
+
if (approveButton) approveButton.disabled = true;
|
|
78
|
+
if (saveButton) saveButton.disabled = true;
|
|
79
|
+
if (postButton) postButton.disabled = true;
|
|
80
|
+
if (cancelButton) cancelButton.disabled = true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A conflict means the file moved under the page; only a reload can re-anchor.
|
|
84
|
+
function offerReload() {
|
|
85
|
+
if (document.getElementById("reload")) return;
|
|
86
|
+
var controls = document.querySelector(".review-controls");
|
|
87
|
+
if (!controls) return;
|
|
88
|
+
var reload = el("button");
|
|
89
|
+
reload.type = "button";
|
|
90
|
+
reload.id = "reload";
|
|
91
|
+
reload.className = "bf-btn bf-btn--primary";
|
|
92
|
+
reload.textContent = "Reload";
|
|
93
|
+
reload.addEventListener("click", function () { window.location.reload(); });
|
|
94
|
+
controls.appendChild(reload);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// The stream exists only to notice a closed tab. Once the review is settled it
|
|
98
|
+
// has no job, and leaving it open retries a dead port until the tab closes.
|
|
99
|
+
function settleStream() {
|
|
100
|
+
if (stream && stream.close) { stream.close(); stream = null; }
|
|
101
|
+
}
|
|
102
|
+
`;
|