@gavin-hu/my-pi-agent 0.15.1 → 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 +22 -13
- package/README.zh-CN.md +19 -11
- package/extensions/bytefly/README.md +255 -200
- 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/notice/component.ts +6 -4
- package/extensions/bytefly/notice/config.ts +16 -2
- package/extensions/bytefly/panel/commands.ts +46 -25
- package/extensions/bytefly/panel/format.ts +52 -22
- package/extensions/bytefly/panel/join.ts +36 -15
- package/extensions/bytefly/panel/settings.ts +72 -392
- package/extensions/bytefly/panel/skills.ts +51 -0
- package/extensions/bytefly/panel/tui/entries.ts +16 -14
- package/extensions/bytefly/panel/tui/extensions-view.ts +7 -58
- package/extensions/bytefly/panel/tui/frame.ts +11 -3
- 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/settings-view.ts +8 -12
- package/extensions/bytefly/panel/tui/skills-view.ts +50 -0
- package/extensions/bytefly/panel/tui.ts +223 -333
- package/extensions/bytefly/panel/types.ts +26 -8
- package/extensions/bytefly/picker/discovery.ts +32 -27
- package/extensions/bytefly/picker/resources.ts +22 -10
- 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/bytefly/working/register.ts +2 -8
- package/extensions/check/tools.ts +2 -11
- package/extensions/check/tui.ts +2 -0
- package/extensions/context/README.md +172 -0
- package/extensions/context/collect.ts +53 -0
- package/extensions/context/commands.ts +100 -0
- package/extensions/context/format.ts +84 -0
- package/extensions/context/index.ts +16 -0
- package/extensions/context/report.ts +332 -0
- package/extensions/context/tui.ts +284 -0
- package/extensions/context/types.ts +124 -0
- package/extensions/file-browse/README.md +67 -19
- package/extensions/file-browse/client.ts +16 -463
- package/extensions/file-browse/config.ts +8 -0
- package/extensions/file-browse/html.ts +9 -7
- package/extensions/file-browse/index.ts +17 -2
- package/extensions/file-browse/live-client.ts +13 -13
- package/extensions/file-browse/live.ts +44 -10
- package/extensions/file-browse/markdown.ts +3 -10
- package/extensions/file-browse/palette.ts +224 -0
- package/extensions/file-browse/raw-html.ts +3 -10
- package/extensions/file-browse/router.ts +2 -2
- package/extensions/file-browse/server.ts +13 -2
- package/extensions/file-browse/styles.ts +8 -3
- package/extensions/file-browse/tree.ts +381 -0
- package/extensions/file-open/README.md +1 -2
- package/extensions/{document → file-read}/README.md +76 -57
- package/extensions/{document → file-read}/config.ts +12 -9
- package/extensions/{document → file-read}/extract/doc.ts +2 -2
- package/extensions/{document → file-read}/extract/docx.ts +3 -3
- package/extensions/{document → file-read}/extract/file.ts +9 -9
- package/extensions/{document → file-read}/extract/odt.ts +10 -8
- package/extensions/{document → file-read}/extract/pdf.ts +3 -3
- package/extensions/{document → file-read}/extract/rtf.ts +3 -3
- package/extensions/{document → file-read}/extract/xlsx.ts +4 -4
- package/extensions/{document → file-read}/formats.ts +11 -11
- package/extensions/file-read/index.ts +17 -0
- package/extensions/{document → file-read}/paging.ts +15 -13
- package/extensions/{document → file-read}/render.ts +17 -13
- package/extensions/{document → file-read}/schema.ts +7 -7
- package/extensions/{document → file-read}/tool.ts +36 -28
- package/extensions/goal/tools.ts +16 -25
- package/extensions/job/commands.ts +32 -46
- package/extensions/job/index.ts +20 -45
- package/extensions/job/runtime.ts +6 -8
- package/extensions/job/tools.ts +58 -103
- package/extensions/memory/commands.ts +30 -44
- package/extensions/memory/tools.ts +10 -20
- 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 +16 -17
- package/extensions/plan/tools/exit.ts +60 -50
- package/extensions/plan/tools/steps.ts +13 -26
- package/extensions/plan/tools/write.ts +30 -38
- 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/plan/web.ts +21 -12
- package/extensions/question/tools.ts +5 -4
- 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/background.ts +1 -7
- 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 +15 -20
- package/extensions/todo/tui.ts +5 -1
- package/extensions/watch/README.md +5 -5
- package/extensions/watch/commands.ts +33 -47
- package/extensions/watch/index.ts +10 -35
- package/extensions/watch/runtime.ts +5 -7
- package/extensions/watch/tools.ts +38 -77
- package/extensions/web-access/README.md +3 -3
- package/extensions/web-access/search/search.ts +9 -18
- 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/timer.ts +9 -30
- package/extensions/wechat/tools.ts +7 -18
- 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 +15 -11
- package/lib/config.ts +12 -0
- package/lib/escape.ts +15 -2
- package/lib/format.ts +6 -2
- package/lib/interaction.ts +18 -1
- package/lib/pdf.ts +2 -2
- package/lib/report.ts +75 -2
- package/lib/requirements.ts +2 -2
- package/lib/screen-session.ts +85 -0
- package/lib/timer.ts +61 -0
- package/lib/tool-result.ts +54 -4
- package/lib/tui/README.md +19 -11
- package/lib/tui/chrome.ts +27 -6
- package/lib/tui/columns.ts +33 -8
- package/lib/tui/dock-screen.ts +6 -2
- package/lib/tui/gauge.ts +9 -5
- package/lib/tui/rows.ts +15 -6
- package/lib/tui/rules.ts +4 -8
- package/lib/tui/tool.ts +55 -2
- 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 +10 -4
- package/skills/changelog/SKILL.md +148 -0
- package/skills/next/SKILL.md +184 -0
- package/extensions/document/index.ts +0 -17
- /package/extensions/{document → file-read}/deadline.ts +0 -0
- /package/extensions/{document → file-read}/extract/vendor.d.ts +0 -0
|
@@ -3,40 +3,38 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A row is one preference: an app setting from Pi's `settings.json`, or a leaf
|
|
5
5
|
* of a `bytefly.json` section. This module is pure — descriptors, a snapshot to
|
|
6
|
-
* views, cycling,
|
|
7
|
-
* one definition and the tests need no host.
|
|
6
|
+
* views, cycling, and validation — so the screen, the text listing, and the
|
|
7
|
+
* runtime share one definition and the tests need no host.
|
|
8
8
|
*
|
|
9
|
-
* The catalogue is
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* The catalogue is the shortlist a session changes, not the whole document: every
|
|
10
|
+
* row is one a workflow differs on, and each states its own rule so a value the
|
|
11
|
+
* screen accepts is a value the loader keeps. The catalogue order is the screen's
|
|
12
|
+
* order, and it is capped so the section fits a 24-row terminal (`settings.test.ts`
|
|
13
|
+
* holds the ceiling); a new row has to displace one. Everything else stays
|
|
14
|
+
* `bytefly.json` — a list (`doctor.skip`), a table (`price.rates`), a schedule
|
|
15
|
+
* (`price.peak`), and the tuning numbers and labels this screen deliberately does
|
|
16
|
+
* not carry — documented in `docs/configuration.md` and reachable from the JSON
|
|
17
|
+
* pane of any row whose section is still on the list.
|
|
15
18
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* file states them, because importing their
|
|
19
|
-
* importing another's module; each such row
|
|
20
|
-
* `test/settings-coverage.test.ts` holds the
|
|
19
|
+
* Three sections have a normalizer here, so the screen shows what the notifier,
|
|
20
|
+
* the doctor, and the footer keep. The three owned by other extensions (`rewind`,
|
|
21
|
+
* `job`, `plan`) are read as the file states them, because importing their
|
|
22
|
+
* normalizer would be one extension importing another's module; each such row
|
|
23
|
+
* declares the loader's default, and `test/settings-coverage.test.ts` holds the
|
|
24
|
+
* pair together.
|
|
21
25
|
*/
|
|
22
26
|
|
|
23
27
|
import { configSection, configValueAt } from "../../../lib/config.ts";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
DEFAULT_CONFIG as DEFAULT_DOCTOR_CONFIG,
|
|
27
|
-
normalizeConfig as normalizeDoctorConfig,
|
|
28
|
-
TIMEOUT_MS_RANGE,
|
|
29
|
-
} from "../doctor/config.ts";
|
|
28
|
+
import { DEFAULT_CONFIG as DEFAULT_DOCTOR_CONFIG, normalizeConfig as normalizeDoctorConfig } from "../doctor/config.ts";
|
|
30
29
|
import {
|
|
31
30
|
CURRENCY_DEFAULTS,
|
|
32
31
|
DEFAULT_BYTEFLY_CONFIG,
|
|
33
32
|
DEFAULT_CURRENCY,
|
|
34
33
|
MAX_BUDGET,
|
|
35
|
-
MAX_DECIMALS,
|
|
36
34
|
normalizeByteflyConfig,
|
|
37
35
|
} from "../footer/price/config.ts";
|
|
38
36
|
import type { CurrencyCode } from "../footer/price/types.ts";
|
|
39
|
-
import { DEFAULT_NOTIFY_CONFIG,
|
|
37
|
+
import { DEFAULT_NOTIFY_CONFIG, normalizeNotifyConfig } from "../notify/config.ts";
|
|
40
38
|
import type { Settings, WriteScope } from "../picker/types.ts";
|
|
41
39
|
|
|
42
40
|
/** Where a preference is stored. */
|
|
@@ -62,24 +60,8 @@ interface TextRule {
|
|
|
62
60
|
validate?: (raw: string) => string | undefined;
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
key: string;
|
|
68
|
-
label: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** The `bytefly.json` sections the Settings section can read and write. */
|
|
72
|
-
export type ConfigSectionName =
|
|
73
|
-
| "notify"
|
|
74
|
-
| "chrome"
|
|
75
|
-
| "doctor"
|
|
76
|
-
| "price"
|
|
77
|
-
| "worktree"
|
|
78
|
-
| "rewind"
|
|
79
|
-
| "job"
|
|
80
|
-
| "watch"
|
|
81
|
-
| "memory"
|
|
82
|
-
| "goal";
|
|
63
|
+
/** The `bytefly.json` sections a row still reaches. */
|
|
64
|
+
export type ConfigSectionName = "notify" | "doctor" | "price" | "rewind" | "job" | "plan";
|
|
83
65
|
|
|
84
66
|
/** Where a `bytefly.json` row lives: a section, and the path to its leaf. */
|
|
85
67
|
interface SettingConfig {
|
|
@@ -98,8 +80,6 @@ interface SettingLeaf {
|
|
|
98
80
|
export interface SettingDescriptor {
|
|
99
81
|
/** Stable identity, also the focus key. */
|
|
100
82
|
id: string;
|
|
101
|
-
/** Group key from {@link SETTING_GROUPS}. */
|
|
102
|
-
group: string;
|
|
103
83
|
label: string;
|
|
104
84
|
description: string;
|
|
105
85
|
source: SettingSource;
|
|
@@ -139,67 +119,12 @@ export interface SettingsSnapshot {
|
|
|
139
119
|
themes: readonly string[];
|
|
140
120
|
}
|
|
141
121
|
|
|
142
|
-
/** One rendered group: its heading and the rows under it. */
|
|
143
|
-
interface GroupedSettings {
|
|
144
|
-
key: string;
|
|
145
|
-
label: string;
|
|
146
|
-
views: SettingView[];
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/** Group order on screen. */
|
|
150
|
-
export const SETTING_GROUPS: readonly SettingGroup[] = [
|
|
151
|
-
{ key: "startup", label: "Startup" },
|
|
152
|
-
{ key: "notifications", label: "Notifications" },
|
|
153
|
-
{ key: "diagnostics", label: "Diagnostics" },
|
|
154
|
-
{ key: "pricing", label: "Pricing" },
|
|
155
|
-
{ key: "transcript", label: "Transcript" },
|
|
156
|
-
{ key: "terminal", label: "Terminal" },
|
|
157
|
-
{ key: "worktree", label: "Worktree" },
|
|
158
|
-
{ key: "snapshots", label: "Snapshots" },
|
|
159
|
-
{ key: "jobs", label: "Jobs and watchers" },
|
|
160
|
-
{ key: "memory", label: "Memory" },
|
|
161
|
-
];
|
|
162
|
-
|
|
163
122
|
const ON_OFF: readonly SettingOption[] = [
|
|
164
123
|
{ value: "false", label: "Off" },
|
|
165
124
|
{ value: "true", label: "On" },
|
|
166
125
|
];
|
|
167
126
|
|
|
168
127
|
/** The notify section's delivery methods, labeled by the surface each reaches. */
|
|
169
|
-
const METHOD_OPTIONS: readonly SettingOption[] = [
|
|
170
|
-
{ value: "auto", label: "Auto" },
|
|
171
|
-
{ value: "osc777", label: "OSC 777" },
|
|
172
|
-
{ value: "osc99", label: "OSC 99" },
|
|
173
|
-
{ value: "toast", label: "Windows toast" },
|
|
174
|
-
{ value: "osascript", label: "macOS" },
|
|
175
|
-
{ value: "notify-send", label: "Linux" },
|
|
176
|
-
];
|
|
177
|
-
|
|
178
|
-
/** Cost precision 0 through the loader's ceiling, the range `price` clamps `decimals` to. */
|
|
179
|
-
const DECIMALS_OPTIONS: readonly SettingOption[] = Array.from({ length: MAX_DECIMALS + 1 }, (_, value) => ({
|
|
180
|
-
value: String(value),
|
|
181
|
-
label: String(value),
|
|
182
|
-
}));
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* A text rule for a whole number inside an inclusive range.
|
|
186
|
-
*
|
|
187
|
-
* The bounds are the loader's own (`doctor.timeoutMs` is clamped to 100-30000),
|
|
188
|
-
* so an accepted value is never silently clamped on the next read. `maxLength`
|
|
189
|
-
* only stops a runaway buffer; `validate` is the rule.
|
|
190
|
-
*/
|
|
191
|
-
function integerRule(min: number, max: number): TextRule {
|
|
192
|
-
return {
|
|
193
|
-
maxLength: String(max).length + 2,
|
|
194
|
-
validate(raw) {
|
|
195
|
-
const text = raw.trim();
|
|
196
|
-
if (!/^\d+$/.test(text)) return `Use a whole number, ${min} to ${max}.`;
|
|
197
|
-
const value = Number(text);
|
|
198
|
-
if (value < min || value > max) return `Out of range: ${min} to ${max}.`;
|
|
199
|
-
return undefined;
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
128
|
|
|
204
129
|
/**
|
|
205
130
|
* A text rule for a money amount inside an inclusive range: a whole number or a
|
|
@@ -219,18 +144,16 @@ function amountRule(min: number, max: number): TextRule {
|
|
|
219
144
|
};
|
|
220
145
|
}
|
|
221
146
|
|
|
222
|
-
/**
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
/** The v1 catalogue, in screen order. */
|
|
147
|
+
/**
|
|
148
|
+
* The catalogue, in screen order.
|
|
149
|
+
*
|
|
150
|
+
* Global scope lists all thirteen; Project lists the eleven `bytefly.json` rows,
|
|
151
|
+
* because Pi's setters write the personal `settings.json` only. The list is
|
|
152
|
+
* capped so the screen keeps fitting a 24-row terminal.
|
|
153
|
+
*/
|
|
230
154
|
export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
231
155
|
{
|
|
232
156
|
id: "byteflyUi",
|
|
233
|
-
group: "startup",
|
|
234
157
|
label: "Bytefly startup TUI",
|
|
235
158
|
description: "Use bytefly's startup header in place of Pi's startup TUI.",
|
|
236
159
|
source: "app",
|
|
@@ -239,9 +162,19 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
239
162
|
json: "boolean",
|
|
240
163
|
options: ON_OFF,
|
|
241
164
|
},
|
|
165
|
+
{
|
|
166
|
+
id: "theme",
|
|
167
|
+
label: "Theme",
|
|
168
|
+
description:
|
|
169
|
+
"Pi's color theme, chosen from the palettes this package ships; `system` follows the terminal's colors. Takes effect after reload.",
|
|
170
|
+
source: "app",
|
|
171
|
+
kind: "enum",
|
|
172
|
+
fallback: "system",
|
|
173
|
+
// The host supplies this package's theme names in the snapshot; the static list stays empty.
|
|
174
|
+
options: [],
|
|
175
|
+
},
|
|
242
176
|
{
|
|
243
177
|
id: "notify.enabled",
|
|
244
|
-
group: "notifications",
|
|
245
178
|
label: "Desktop notifications",
|
|
246
179
|
description: "Raise an OS notification when a run or job finishes, or the agent asks for input.",
|
|
247
180
|
source: "bytefly",
|
|
@@ -253,7 +186,6 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
253
186
|
},
|
|
254
187
|
{
|
|
255
188
|
id: "notify.turnFinished",
|
|
256
|
-
group: "notifications",
|
|
257
189
|
label: "Turn finished",
|
|
258
190
|
description: "Announce it when a full agent run settles.",
|
|
259
191
|
source: "bytefly",
|
|
@@ -265,7 +197,6 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
265
197
|
},
|
|
266
198
|
{
|
|
267
199
|
id: "notify.needsInput",
|
|
268
|
-
group: "notifications",
|
|
269
200
|
label: "Needs input",
|
|
270
201
|
description: "Announce it when the agent opens a prompt and waits for an answer.",
|
|
271
202
|
source: "bytefly",
|
|
@@ -277,7 +208,6 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
277
208
|
},
|
|
278
209
|
{
|
|
279
210
|
id: "notify.jobFinished",
|
|
280
|
-
group: "notifications",
|
|
281
211
|
label: "Job finished",
|
|
282
212
|
description: "Announce it when a background job or watcher settles.",
|
|
283
213
|
source: "bytefly",
|
|
@@ -289,7 +219,6 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
289
219
|
},
|
|
290
220
|
{
|
|
291
221
|
id: "notify.matchFound",
|
|
292
|
-
group: "notifications",
|
|
293
222
|
label: "Watcher matched",
|
|
294
223
|
description: "Announce it when a `watch` whose `wake` is on matches while the agent is idle.",
|
|
295
224
|
source: "bytefly",
|
|
@@ -300,34 +229,40 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
300
229
|
config: { section: "notify", path: ["matchFound"] },
|
|
301
230
|
},
|
|
302
231
|
{
|
|
303
|
-
id: "
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
description: "How a notification is delivered; Auto picks from the terminal, then the platform.",
|
|
232
|
+
id: "job.wakeOnFinish",
|
|
233
|
+
label: "Wake when a job finishes",
|
|
234
|
+
description: "Start one agent turn when any background job finishes.",
|
|
307
235
|
source: "bytefly",
|
|
308
|
-
kind: "
|
|
309
|
-
fallback: "
|
|
310
|
-
|
|
311
|
-
|
|
236
|
+
kind: "boolean",
|
|
237
|
+
fallback: "false",
|
|
238
|
+
json: "boolean",
|
|
239
|
+
options: ON_OFF,
|
|
240
|
+
config: { section: "job", path: ["wakeOnFinish"] },
|
|
312
241
|
},
|
|
313
242
|
{
|
|
314
|
-
id: "
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
description: "Shown as the title of every OS notification; up to 40 characters.",
|
|
243
|
+
id: "plan.goalPrompt",
|
|
244
|
+
label: "Offer the session goal",
|
|
245
|
+
description: "Ask before recording an approved plan as the session goal; off records it without asking.",
|
|
318
246
|
source: "bytefly",
|
|
319
|
-
kind: "
|
|
320
|
-
fallback: "
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
247
|
+
kind: "boolean",
|
|
248
|
+
fallback: "true",
|
|
249
|
+
json: "boolean",
|
|
250
|
+
options: ON_OFF,
|
|
251
|
+
config: { section: "plan", path: ["goalPrompt"] },
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
id: "rewind.autoSnapshots",
|
|
255
|
+
label: "Automatic snapshots",
|
|
256
|
+
description: "Take one rewind snapshot per prompt, before the first mutating tool call.",
|
|
257
|
+
source: "bytefly",
|
|
258
|
+
kind: "boolean",
|
|
259
|
+
fallback: "true",
|
|
260
|
+
json: "boolean",
|
|
261
|
+
options: ON_OFF,
|
|
262
|
+
config: { section: "rewind", path: ["autoSnapshots"] },
|
|
327
263
|
},
|
|
328
264
|
{
|
|
329
265
|
id: "doctor.proactive",
|
|
330
|
-
group: "diagnostics",
|
|
331
266
|
label: "Proactive health check",
|
|
332
267
|
description: "Probe enabled extensions at session start and warn about a missing requirement.",
|
|
333
268
|
source: "bytefly",
|
|
@@ -337,22 +272,8 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
337
272
|
options: ON_OFF,
|
|
338
273
|
config: { section: "doctor", path: ["proactive"] },
|
|
339
274
|
},
|
|
340
|
-
{
|
|
341
|
-
id: "doctor.timeoutMs",
|
|
342
|
-
group: "diagnostics",
|
|
343
|
-
label: "Probe timeout",
|
|
344
|
-
description: `How long one doctor probe may take, in milliseconds; ${TIMEOUT_MS_RANGE.min} to ${TIMEOUT_MS_RANGE.max}.`,
|
|
345
|
-
source: "bytefly",
|
|
346
|
-
kind: "text",
|
|
347
|
-
fallback: String(DEFAULT_DOCTOR_CONFIG.timeoutMs),
|
|
348
|
-
json: "number",
|
|
349
|
-
options: [],
|
|
350
|
-
text: integerRule(TIMEOUT_MS_RANGE.min, TIMEOUT_MS_RANGE.max),
|
|
351
|
-
config: { section: "doctor", path: ["timeoutMs"] },
|
|
352
|
-
},
|
|
353
275
|
{
|
|
354
276
|
id: "price.currency.code",
|
|
355
|
-
group: "pricing",
|
|
356
277
|
label: "Currency",
|
|
357
278
|
description:
|
|
358
279
|
"CNY prices DeepSeek from its yuan rates; USD from its published dollars, falling back to Pi's recorded cost.",
|
|
@@ -365,7 +286,7 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
365
286
|
],
|
|
366
287
|
config: { section: "price", path: ["currency", "code"] },
|
|
367
288
|
// Choosing a currency also sets its default precision, so the screen and the
|
|
368
|
-
// footer agree; the precision stays overridable afterwards.
|
|
289
|
+
// footer agree; the precision stays overridable in `bytefly.json` afterwards.
|
|
369
290
|
also: (raw) => {
|
|
370
291
|
const currency = CURRENCY_DEFAULTS[raw as CurrencyCode];
|
|
371
292
|
return currency === undefined
|
|
@@ -373,21 +294,8 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
373
294
|
: [{ section: "price", path: ["currency", "decimals"], value: currency.decimals }];
|
|
374
295
|
},
|
|
375
296
|
},
|
|
376
|
-
{
|
|
377
|
-
id: "price.currency.decimals",
|
|
378
|
-
group: "pricing",
|
|
379
|
-
label: "Cost decimals",
|
|
380
|
-
description: "Digits shown after the decimal point in the footer's cost total.",
|
|
381
|
-
source: "bytefly",
|
|
382
|
-
kind: "enum",
|
|
383
|
-
fallback: "2",
|
|
384
|
-
json: "number",
|
|
385
|
-
options: DECIMALS_OPTIONS,
|
|
386
|
-
config: { section: "price", path: ["currency", "decimals"] },
|
|
387
|
-
},
|
|
388
297
|
{
|
|
389
298
|
id: "price.budget",
|
|
390
|
-
group: "pricing",
|
|
391
299
|
label: "Session budget",
|
|
392
300
|
description: "Warn once when the session's cost reaches this amount; 0 is off. It never stops a turn.",
|
|
393
301
|
source: "bytefly",
|
|
@@ -398,210 +306,6 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
398
306
|
text: amountRule(0, MAX_BUDGET),
|
|
399
307
|
config: { section: "price", path: ["budget"] },
|
|
400
308
|
},
|
|
401
|
-
{
|
|
402
|
-
id: "chrome.rail",
|
|
403
|
-
group: "transcript",
|
|
404
|
-
label: "Rail glyph",
|
|
405
|
-
description: "The single-column glyph that leads a tool result or notice body, e.g. ╎ │ ┃ ▏.",
|
|
406
|
-
source: "bytefly",
|
|
407
|
-
kind: "text",
|
|
408
|
-
fallback: DEFAULT_CHROME_CONFIG.rail,
|
|
409
|
-
options: [],
|
|
410
|
-
text: RAIL_RULE,
|
|
411
|
-
config: { section: "chrome", path: ["rail"] },
|
|
412
|
-
},
|
|
413
|
-
{
|
|
414
|
-
id: "goal.achieved",
|
|
415
|
-
group: "transcript",
|
|
416
|
-
label: "Achieved goal",
|
|
417
|
-
description: "How a completed goal renders: the dimmed rail line, or nothing.",
|
|
418
|
-
source: "bytefly",
|
|
419
|
-
kind: "enum",
|
|
420
|
-
fallback: "hide",
|
|
421
|
-
options: [
|
|
422
|
-
{ value: "show", label: "Show" },
|
|
423
|
-
{ value: "hide", label: "Hide" },
|
|
424
|
-
],
|
|
425
|
-
config: { section: "goal", path: ["achieved"] },
|
|
426
|
-
},
|
|
427
|
-
{
|
|
428
|
-
id: "outputPad",
|
|
429
|
-
group: "transcript",
|
|
430
|
-
label: "Output padding",
|
|
431
|
-
description: "Pi's transcript padding; bytefly's header and blocks follow it.",
|
|
432
|
-
source: "app",
|
|
433
|
-
kind: "enum",
|
|
434
|
-
fallback: "1",
|
|
435
|
-
json: "number",
|
|
436
|
-
options: [
|
|
437
|
-
{ value: "0", label: "0" },
|
|
438
|
-
{ value: "1", label: "1" },
|
|
439
|
-
],
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
id: "theme",
|
|
443
|
-
group: "terminal",
|
|
444
|
-
label: "Theme",
|
|
445
|
-
description:
|
|
446
|
-
"Pi's color theme, chosen from the palettes this package ships; `system` follows the terminal's colors. Takes effect after reload.",
|
|
447
|
-
source: "app",
|
|
448
|
-
kind: "enum",
|
|
449
|
-
fallback: "system",
|
|
450
|
-
// The host supplies this package's theme names in the snapshot; the static list stays empty.
|
|
451
|
-
options: [],
|
|
452
|
-
},
|
|
453
|
-
{
|
|
454
|
-
id: "showHardwareCursor",
|
|
455
|
-
group: "terminal",
|
|
456
|
-
label: "Hardware cursor",
|
|
457
|
-
description: "Use the terminal cursor instead of Pi's drawn cursor.",
|
|
458
|
-
source: "app",
|
|
459
|
-
kind: "boolean",
|
|
460
|
-
fallback: "false",
|
|
461
|
-
json: "boolean",
|
|
462
|
-
options: ON_OFF,
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
id: "worktree.baseRef",
|
|
466
|
-
group: "worktree",
|
|
467
|
-
label: "Base ref",
|
|
468
|
-
description: "Where a new worktree branches from: the remote default branch, or the current local HEAD.",
|
|
469
|
-
source: "bytefly",
|
|
470
|
-
kind: "enum",
|
|
471
|
-
fallback: "fresh",
|
|
472
|
-
options: [
|
|
473
|
-
{ value: "fresh", label: "Fresh" },
|
|
474
|
-
{ value: "head", label: "Head" },
|
|
475
|
-
],
|
|
476
|
-
config: { section: "worktree", path: ["baseRef"] },
|
|
477
|
-
},
|
|
478
|
-
{
|
|
479
|
-
id: "worktree.branchPrefix",
|
|
480
|
-
group: "worktree",
|
|
481
|
-
label: "Branch prefix",
|
|
482
|
-
description: "Prepended to every branch a managed worktree creates.",
|
|
483
|
-
source: "bytefly",
|
|
484
|
-
kind: "text",
|
|
485
|
-
fallback: "worktree-",
|
|
486
|
-
options: [],
|
|
487
|
-
text: {
|
|
488
|
-
// The loader trims and rejects an empty prefix but sets no ceiling; this
|
|
489
|
-
// only stops a runaway buffer.
|
|
490
|
-
maxLength: 80,
|
|
491
|
-
validate: (raw) => (raw.trim() === "" ? "A prefix is required." : undefined),
|
|
492
|
-
},
|
|
493
|
-
config: { section: "worktree", path: ["branchPrefix"] },
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
id: "worktree.fetchRemote",
|
|
497
|
-
group: "worktree",
|
|
498
|
-
label: "Fetch remote",
|
|
499
|
-
description: "Fetch the remote before branching, so a new worktree starts from its latest commit.",
|
|
500
|
-
source: "bytefly",
|
|
501
|
-
kind: "boolean",
|
|
502
|
-
fallback: "true",
|
|
503
|
-
json: "boolean",
|
|
504
|
-
options: ON_OFF,
|
|
505
|
-
config: { section: "worktree", path: ["fetchRemote"] },
|
|
506
|
-
},
|
|
507
|
-
{
|
|
508
|
-
id: "worktree.pruneAfterDays",
|
|
509
|
-
group: "worktree",
|
|
510
|
-
label: "Prune after (days)",
|
|
511
|
-
description: "Age at which `/worktree prune` removes a clean worktree nobody is using.",
|
|
512
|
-
source: "bytefly",
|
|
513
|
-
kind: "text",
|
|
514
|
-
fallback: "7",
|
|
515
|
-
json: "number",
|
|
516
|
-
options: [],
|
|
517
|
-
text: integerRule(0, 3650),
|
|
518
|
-
config: { section: "worktree", path: ["pruneAfterDays"] },
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
id: "rewind.autoSnapshots",
|
|
522
|
-
group: "snapshots",
|
|
523
|
-
label: "Automatic snapshots",
|
|
524
|
-
description: "Take one rewind snapshot per prompt, before the first mutating tool call.",
|
|
525
|
-
source: "bytefly",
|
|
526
|
-
kind: "boolean",
|
|
527
|
-
fallback: "true",
|
|
528
|
-
json: "boolean",
|
|
529
|
-
options: ON_OFF,
|
|
530
|
-
config: { section: "rewind", path: ["autoSnapshots"] },
|
|
531
|
-
},
|
|
532
|
-
{
|
|
533
|
-
id: "rewind.max",
|
|
534
|
-
group: "snapshots",
|
|
535
|
-
label: "Snapshots kept",
|
|
536
|
-
description: "Snapshot refs kept per repository, including pre-restore safety snapshots; 0 keeps none.",
|
|
537
|
-
source: "bytefly",
|
|
538
|
-
kind: "text",
|
|
539
|
-
fallback: "20",
|
|
540
|
-
json: "number",
|
|
541
|
-
options: [],
|
|
542
|
-
text: integerRule(0, 1000),
|
|
543
|
-
config: { section: "rewind", path: ["max"] },
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
id: "rewind.safetySnapshot",
|
|
547
|
-
group: "snapshots",
|
|
548
|
-
label: "Safety snapshot",
|
|
549
|
-
description: "Snapshot the current state before a restore, so a rewind can itself be undone.",
|
|
550
|
-
source: "bytefly",
|
|
551
|
-
kind: "boolean",
|
|
552
|
-
fallback: "true",
|
|
553
|
-
json: "boolean",
|
|
554
|
-
options: ON_OFF,
|
|
555
|
-
config: { section: "rewind", path: ["safetySnapshot"] },
|
|
556
|
-
},
|
|
557
|
-
{
|
|
558
|
-
id: "job.wakeOnFinish",
|
|
559
|
-
group: "jobs",
|
|
560
|
-
label: "Wake when a job finishes",
|
|
561
|
-
description: "Start one agent turn when any background job finishes.",
|
|
562
|
-
source: "bytefly",
|
|
563
|
-
kind: "boolean",
|
|
564
|
-
fallback: "false",
|
|
565
|
-
json: "boolean",
|
|
566
|
-
options: ON_OFF,
|
|
567
|
-
config: { section: "job", path: ["wakeOnFinish"] },
|
|
568
|
-
},
|
|
569
|
-
{
|
|
570
|
-
id: "job.detachedByDefault",
|
|
571
|
-
group: "jobs",
|
|
572
|
-
label: "Keep jobs after exit",
|
|
573
|
-
description: "Leave jobs running when the session ends, unless the job opts out.",
|
|
574
|
-
source: "bytefly",
|
|
575
|
-
kind: "boolean",
|
|
576
|
-
fallback: "false",
|
|
577
|
-
json: "boolean",
|
|
578
|
-
options: ON_OFF,
|
|
579
|
-
config: { section: "job", path: ["detachedByDefault"] },
|
|
580
|
-
},
|
|
581
|
-
{
|
|
582
|
-
id: "watch.wakeOnMatch",
|
|
583
|
-
group: "jobs",
|
|
584
|
-
label: "Wake on a match",
|
|
585
|
-
description: "Start one agent turn when a watcher matches while the agent is idle.",
|
|
586
|
-
source: "bytefly",
|
|
587
|
-
kind: "boolean",
|
|
588
|
-
fallback: "false",
|
|
589
|
-
json: "boolean",
|
|
590
|
-
options: ON_OFF,
|
|
591
|
-
config: { section: "watch", path: ["wakeOnMatch"] },
|
|
592
|
-
},
|
|
593
|
-
{
|
|
594
|
-
id: "memory.inject",
|
|
595
|
-
group: "memory",
|
|
596
|
-
label: "Inject notes",
|
|
597
|
-
description: "Put stored memory notes in context before each run.",
|
|
598
|
-
source: "bytefly",
|
|
599
|
-
kind: "boolean",
|
|
600
|
-
fallback: "true",
|
|
601
|
-
json: "boolean",
|
|
602
|
-
options: ON_OFF,
|
|
603
|
-
config: { section: "memory", path: ["inject"] },
|
|
604
|
-
},
|
|
605
309
|
];
|
|
606
310
|
|
|
607
311
|
/** The one refusal for a Project write while the project is untrusted. */
|
|
@@ -615,10 +319,10 @@ export function rowsForScope(scope: WriteScope): readonly SettingDescriptor[] {
|
|
|
615
319
|
/**
|
|
616
320
|
* Why a text row cannot store `raw`, or `undefined` when it can.
|
|
617
321
|
*
|
|
618
|
-
* The limits are the loaders' own (
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
322
|
+
* The limits are the loaders' own (the budget is clamped to `MAX_BUDGET`) so the
|
|
323
|
+
* editor cannot save a value the next read shortens. A row that is not text is
|
|
324
|
+
* refused here rather than in the caller, so a programmatic `setValue` gets the
|
|
325
|
+
* same reason the screen would show.
|
|
622
326
|
*/
|
|
623
327
|
export function textError(row: SettingDescriptor, raw: string): string | undefined {
|
|
624
328
|
const rule = row.text;
|
|
@@ -650,16 +354,6 @@ function appValue(snapshot: SettingsSnapshot, row: SettingDescriptor): { value:
|
|
|
650
354
|
const quiet = snapshot.app.quietStartup;
|
|
651
355
|
return { value: quiet === true ? "true" : row.fallback, origin: quiet === undefined ? "default" : "global" };
|
|
652
356
|
}
|
|
653
|
-
case "outputPad":
|
|
654
|
-
return {
|
|
655
|
-
value: snapshot.app.outputPad === 0 ? "0" : row.fallback,
|
|
656
|
-
origin: snapshot.app.outputPad === undefined ? "default" : "global",
|
|
657
|
-
};
|
|
658
|
-
case "showHardwareCursor":
|
|
659
|
-
return {
|
|
660
|
-
value: snapshot.app.showHardwareCursor === true ? "true" : row.fallback,
|
|
661
|
-
origin: snapshot.app.showHardwareCursor === undefined ? "default" : "global",
|
|
662
|
-
};
|
|
663
357
|
case "theme": {
|
|
664
358
|
const theme = snapshot.app.theme;
|
|
665
359
|
const set = typeof theme === "string" && theme !== "";
|
|
@@ -692,15 +386,10 @@ type SectionReader = (
|
|
|
692
386
|
path: readonly string[],
|
|
693
387
|
) => unknown;
|
|
694
388
|
|
|
695
|
-
/**
|
|
696
|
-
* The four sections bytefly owns, each read through its own normalizer so the
|
|
697
|
-
* screen shows the value the loader keeps.
|
|
698
|
-
*/
|
|
389
|
+
/** The sections bytefly owns, each read through its own normalizer so the screen shows what the loader keeps. */
|
|
699
390
|
const SECTION_READERS: Partial<Record<ConfigSectionName, SectionReader>> = {
|
|
700
391
|
notify: (globalRaw, projectRaw, path) =>
|
|
701
392
|
configValueAt(normalizeNotifyConfig(projectRaw, normalizeNotifyConfig(globalRaw, DEFAULT_NOTIFY_CONFIG)), path),
|
|
702
|
-
chrome: (globalRaw, projectRaw, path) =>
|
|
703
|
-
configValueAt(normalizeChromeConfig(projectRaw, normalizeChromeConfig(globalRaw, DEFAULT_CHROME_CONFIG)), path),
|
|
704
393
|
doctor: (globalRaw, projectRaw, path) =>
|
|
705
394
|
configValueAt(normalizeDoctorConfig(projectRaw, normalizeDoctorConfig(globalRaw, DEFAULT_DOCTOR_CONFIG)), path),
|
|
706
395
|
price: (globalRaw, projectRaw, path) =>
|
|
@@ -772,12 +461,3 @@ export function storedValue(row: SettingDescriptor, raw: string): unknown {
|
|
|
772
461
|
return raw;
|
|
773
462
|
}
|
|
774
463
|
}
|
|
775
|
-
|
|
776
|
-
/** Group views in screen order, dropping empty groups. */
|
|
777
|
-
export function groupViews(views: readonly SettingView[]): GroupedSettings[] {
|
|
778
|
-
return SETTING_GROUPS.map((group) => ({
|
|
779
|
-
key: group.key,
|
|
780
|
-
label: group.label,
|
|
781
|
-
views: views.filter((view) => view.group === group.key),
|
|
782
|
-
})).filter((group) => group.views.length > 0);
|
|
783
|
-
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill metadata for the panel.
|
|
3
|
+
*
|
|
4
|
+
* One `loadSkills` call reads every resolved `SKILL.md` and hands back the
|
|
5
|
+
* declared name, description, and model-invocation flag, keyed by file path so
|
|
6
|
+
* the row model can join it. Pi's loader also reports why it refused a file, and
|
|
7
|
+
* that reason travels with the row so the screen can say `not loaded` instead of
|
|
8
|
+
* silently showing a name. Nothing here renders or writes; the panel reads the
|
|
9
|
+
* index when the Skills section first becomes visible.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { loadSkills } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import type { Discovery } from "../picker/types.ts";
|
|
14
|
+
import type { SkillInfo } from "./types.ts";
|
|
15
|
+
|
|
16
|
+
/** Loaded skill metadata keyed by the resolved resource path. */
|
|
17
|
+
export type SkillIndex = ReadonlyMap<string, SkillInfo>;
|
|
18
|
+
|
|
19
|
+
/** Every skill file either discovery view resolves, once, for the loader. */
|
|
20
|
+
export function resolvedSkillPaths(discovery: Discovery): string[] {
|
|
21
|
+
const paths = [...discovery.skills.global, ...discovery.skills.effective].map((item) => item.path);
|
|
22
|
+
return [...new Set(paths)];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Read the metadata for every resolved skill path. A path may be a `SKILL.md`
|
|
27
|
+
* or a standalone Markdown skill; both are what the resolver hands the panel.
|
|
28
|
+
*
|
|
29
|
+
* A diagnostic names the file Pi refused, so it becomes that row's `problem`. A
|
|
30
|
+
* warning about a file that still loaded is dropped: the row's own name and
|
|
31
|
+
* description already come from the same loader, and `not loaded` would be a
|
|
32
|
+
* lie about a skill the model can use.
|
|
33
|
+
*/
|
|
34
|
+
export function loadSkillIndex(paths: readonly string[], cwd: string, agentDir: string): SkillIndex {
|
|
35
|
+
if (paths.length === 0) return new Map();
|
|
36
|
+
const { skills, diagnostics } = loadSkills({ cwd, agentDir, skillPaths: [...paths], includeDefaults: false });
|
|
37
|
+
const index = new Map<string, SkillInfo>();
|
|
38
|
+
for (const skill of skills) {
|
|
39
|
+
index.set(skill.filePath, {
|
|
40
|
+
name: skill.name,
|
|
41
|
+
description: skill.description,
|
|
42
|
+
modelHidden: skill.disableModelInvocation,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
for (const diagnostic of diagnostics) {
|
|
46
|
+
const path = diagnostic.path;
|
|
47
|
+
if (path === undefined || index.has(path)) continue;
|
|
48
|
+
index.set(path, { description: "", modelHidden: false, problem: diagnostic.message });
|
|
49
|
+
}
|
|
50
|
+
return index;
|
|
51
|
+
}
|