@groeponline/pi-wishcraft 1.6.0 → 1.8.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/AGENTS.md +315 -97
- package/CHANGELOG.md +94 -9
- package/README.md +33 -33
- package/bash-mode/editor.ts +82 -10
- package/bash-mode/pty-session.ts +64 -16
- package/bash-mode/transcript.ts +67 -2
- package/docs/architecture/codebase-graph.md +660 -0
- package/docs/bash-mode.md +4 -0
- package/docs/commands.md +1 -1
- package/docs/segments.md +2 -2
- package/package.json +2 -2
- package/src/config/presets.ts +59 -1
- package/src/config/segment-options.ts +98 -83
- package/src/config/structural-preset-data.ts +69 -0
- package/src/config/structural-preset-table.ts +445 -0
- package/src/config/structural-presets.ts +9 -499
- package/src/config/types.ts +8 -1
- package/src/extension/skills/global-registry.ts +63 -0
- package/src/extension/skills/skill-registry.ts +56 -4
- package/src/extension/ui/custom-editor.ts +22 -1
- package/src/extension/ui/deck/component.ts +17 -5
- package/src/extension/ui/deck/render.ts +26 -7
- package/src/extension/ui/status-line-renderers.ts +6 -2
- package/src/motion/catalog-extra.ts +24 -0
- package/src/motion/catalog.ts +4 -0
- package/src/motion/index.ts +1 -0
- package/src/motion/policy.ts +28 -1
- package/src/motion/scheduler.ts +7 -0
- package/src/render/layout.ts +44 -2
- package/src/render/motion-candidates.ts +52 -0
- package/src/render/motion-rail.ts +80 -50
- package/src/render/paint.ts +32 -8
- package/src/render/v2-adapter.ts +2 -0
- package/src/render/v2-entry.ts +1 -1
- package/src/segments/system.ts +13 -6
- package/src/signal/controller.ts +45 -29
- package/src/studio/component.ts +213 -37
- package/src/studio/deepwiki/cache.ts +80 -6
- package/src/studio/list.ts +11 -1
- package/src/studio/open.ts +207 -15
- package/src/theme/colors.ts +2 -6
- package/src/theme/icons.ts +21 -0
- package/src/theme/separators.ts +20 -0
- package/tsconfig.test.json +7 -0
- package/src/tools/patch.ts +0 -179
- package/src/tools/ripgrep.ts +0 -104
package/src/config/presets.ts
CHANGED
|
@@ -31,6 +31,18 @@ const CHEF_COLORS: ColorScheme = {
|
|
|
31
31
|
queue: "dim",
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
// chef-calm: same operational essentials, visually quieter. Accent stays
|
|
35
|
+
// reserved for state (context/token states), everything else blends into
|
|
36
|
+
// text/dim so the line reads as one row instead of a rainbow.
|
|
37
|
+
const CHEF_CALM_COLORS: ColorScheme = {
|
|
38
|
+
...DEFAULT_COLORS,
|
|
39
|
+
model: "text",
|
|
40
|
+
path: "text",
|
|
41
|
+
gitClean: "dim",
|
|
42
|
+
queue: "dim",
|
|
43
|
+
context: "accent",
|
|
44
|
+
};
|
|
45
|
+
|
|
34
46
|
// ---------------------------------------------------------------------------
|
|
35
47
|
// 10 vNext Structural Signature Presets
|
|
36
48
|
// ---------------------------------------------------------------------------
|
|
@@ -346,9 +358,19 @@ export const PRESETS: Record<StatusLinePreset, PresetDef> = {
|
|
|
346
358
|
"shell_mode",
|
|
347
359
|
"path",
|
|
348
360
|
"git",
|
|
361
|
+
"session",
|
|
349
362
|
"queue",
|
|
350
363
|
],
|
|
351
|
-
rightSegments: [
|
|
364
|
+
rightSegments: [
|
|
365
|
+
"tps",
|
|
366
|
+
"open_ports",
|
|
367
|
+
"token_out",
|
|
368
|
+
"cache_read",
|
|
369
|
+
"subagents",
|
|
370
|
+
"cost",
|
|
371
|
+
"context_pct",
|
|
372
|
+
"time",
|
|
373
|
+
],
|
|
352
374
|
separator: "slash",
|
|
353
375
|
colors: CHEF_COLORS,
|
|
354
376
|
segmentOptions: {
|
|
@@ -372,6 +394,42 @@ export const PRESETS: Record<StatusLinePreset, PresetDef> = {
|
|
|
372
394
|
},
|
|
373
395
|
},
|
|
374
396
|
|
|
397
|
+
// chef-calm: five segments, dot separator, quiet motion. The operational
|
|
398
|
+
// row without the noise — tps/open_ports/subagents/cost/hostname dropped,
|
|
399
|
+
// git commit subjects off (ahead/behind stays). Colours: text/dim with a
|
|
400
|
+
// single accent for context so the line reads as one calm row.
|
|
401
|
+
"chef-calm": {
|
|
402
|
+
leftSegments: ["model", "path", "git"],
|
|
403
|
+
rightSegments: ["context_pct", "time"],
|
|
404
|
+
secondarySegments: [],
|
|
405
|
+
separator: "dot",
|
|
406
|
+
colors: CHEF_CALM_COLORS,
|
|
407
|
+
segmentOptions: {
|
|
408
|
+
model: { showThinkingLevel: false },
|
|
409
|
+
path: { mode: "basename" },
|
|
410
|
+
git: {
|
|
411
|
+
showBranch: true,
|
|
412
|
+
showStaged: false,
|
|
413
|
+
showUnstaged: false,
|
|
414
|
+
showUntracked: false,
|
|
415
|
+
polling: "branch",
|
|
416
|
+
hostIcon: false,
|
|
417
|
+
showAheadBehind: true,
|
|
418
|
+
showCommit: false,
|
|
419
|
+
},
|
|
420
|
+
context: { format: "percent" },
|
|
421
|
+
time: { format: "24h", showSeconds: false },
|
|
422
|
+
},
|
|
423
|
+
motion: {
|
|
424
|
+
idle: "nimbus",
|
|
425
|
+
thinking: "nimbus",
|
|
426
|
+
streaming: "nimbus",
|
|
427
|
+
"tool.end": "copper-switch",
|
|
428
|
+
success: "copper-switch",
|
|
429
|
+
error: "copper-switch",
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
|
|
375
433
|
// 10 vNext Structural Presets
|
|
376
434
|
lanternwake: {
|
|
377
435
|
leftSegments: ["model", "thinking", "shell_mode", "path", "git", "session", "queue"],
|
|
@@ -2,132 +2,147 @@ import { normalizeCostCurrency } from "../usage/rates.ts";
|
|
|
2
2
|
import { isRecord } from "./primitives.ts";
|
|
3
3
|
import type { StatusLineSegmentOptions } from "./types.ts";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes raw segment configuration into supported status-line segment options.
|
|
7
|
+
*
|
|
8
|
+
* Invalid values are ignored, numeric limits are normalized, string values are trimmed,
|
|
9
|
+
* and non-empty template overrides are preserved for supported option groups.
|
|
10
|
+
*
|
|
11
|
+
* @param raw - Raw segment configuration to normalize
|
|
12
|
+
* @returns The validated and normalized segment options
|
|
13
|
+
*/
|
|
5
14
|
export function normalizeSegmentOptions(
|
|
6
15
|
raw: Record<string, unknown>,
|
|
7
16
|
): StatusLineSegmentOptions {
|
|
8
17
|
const options: StatusLineSegmentOptions = {};
|
|
9
18
|
|
|
10
19
|
if (isRecord(raw.model)) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
const model: NonNullable<StatusLineSegmentOptions["model"]> = {};
|
|
21
|
+
if (typeof raw.model.showThinkingLevel === "boolean") {
|
|
22
|
+
model.showThinkingLevel = raw.model.showThinkingLevel;
|
|
23
|
+
}
|
|
24
|
+
if (raw.model.display === "name" || raw.model.display === "qualified") {
|
|
25
|
+
model.display = raw.model.display;
|
|
26
|
+
}
|
|
27
|
+
options.model = model;
|
|
19
28
|
}
|
|
20
29
|
|
|
21
30
|
if (isRecord(raw.path)) {
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
const path: NonNullable<StatusLineSegmentOptions["path"]> = {};
|
|
32
|
+
if (
|
|
33
|
+
raw.path.mode === "basename" ||
|
|
24
34
|
raw.path.mode === "abbreviated" ||
|
|
25
35
|
raw.path.mode === "full"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
36
|
+
) {
|
|
37
|
+
path.mode = raw.path.mode;
|
|
38
|
+
}
|
|
39
|
+
if (
|
|
40
|
+
typeof raw.path.maxLength === "number" &&
|
|
29
41
|
Number.isFinite(raw.path.maxLength) &&
|
|
30
42
|
raw.path.maxLength > 0
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
43
|
+
) {
|
|
44
|
+
path.maxLength = Math.floor(raw.path.maxLength);
|
|
45
|
+
}
|
|
46
|
+
options.path = path;
|
|
34
47
|
}
|
|
35
48
|
|
|
36
49
|
if (isRecord(raw.git)) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
? { showUntracked: raw.git.showUntracked }
|
|
49
|
-
: {}),
|
|
50
|
-
...(raw.git.polling === "full" ||
|
|
50
|
+
const git: NonNullable<StatusLineSegmentOptions["git"]> = {};
|
|
51
|
+
if (typeof raw.git.showBranch === "boolean") git.showBranch = raw.git.showBranch;
|
|
52
|
+
if (typeof raw.git.showStaged === "boolean") git.showStaged = raw.git.showStaged;
|
|
53
|
+
if (typeof raw.git.showUnstaged === "boolean") {
|
|
54
|
+
git.showUnstaged = raw.git.showUnstaged;
|
|
55
|
+
}
|
|
56
|
+
if (typeof raw.git.showUntracked === "boolean") {
|
|
57
|
+
git.showUntracked = raw.git.showUntracked;
|
|
58
|
+
}
|
|
59
|
+
if (
|
|
60
|
+
raw.git.polling === "full" ||
|
|
51
61
|
raw.git.polling === "branch" ||
|
|
52
62
|
raw.git.polling === "off"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
: {}),
|
|
64
|
-
...(typeof raw.git.maxCommitSubjectLength === "number" &&
|
|
63
|
+
) {
|
|
64
|
+
git.polling = raw.git.polling;
|
|
65
|
+
}
|
|
66
|
+
if (typeof raw.git.hostIcon === "boolean") git.hostIcon = raw.git.hostIcon;
|
|
67
|
+
if (typeof raw.git.showAheadBehind === "boolean") {
|
|
68
|
+
git.showAheadBehind = raw.git.showAheadBehind;
|
|
69
|
+
}
|
|
70
|
+
if (typeof raw.git.showCommit === "boolean") git.showCommit = raw.git.showCommit;
|
|
71
|
+
if (
|
|
72
|
+
typeof raw.git.maxCommitSubjectLength === "number" &&
|
|
65
73
|
Number.isFinite(raw.git.maxCommitSubjectLength) &&
|
|
66
74
|
raw.git.maxCommitSubjectLength > 0
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
75
|
+
) {
|
|
76
|
+
git.maxCommitSubjectLength = Math.floor(raw.git.maxCommitSubjectLength);
|
|
77
|
+
}
|
|
78
|
+
options.git = git;
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
if (isRecord(raw.time)) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
const time: NonNullable<StatusLineSegmentOptions["time"]> = {};
|
|
83
|
+
if (raw.time.format === "12h" || raw.time.format === "24h") {
|
|
84
|
+
time.format = raw.time.format;
|
|
85
|
+
}
|
|
86
|
+
if (typeof raw.time.showSeconds === "boolean") {
|
|
87
|
+
time.showSeconds = raw.time.showSeconds;
|
|
88
|
+
}
|
|
89
|
+
options.time = time;
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
if (isRecord(raw.cost)) {
|
|
84
93
|
const currency = normalizeCostCurrency(raw.cost.currency);
|
|
85
|
-
|
|
86
|
-
|
|
94
|
+
const cost: NonNullable<StatusLineSegmentOptions["cost"]> = {};
|
|
95
|
+
if (
|
|
96
|
+
raw.cost.subscriptionDisplay === "subscription" ||
|
|
87
97
|
raw.cost.subscriptionDisplay === "reported-cost" ||
|
|
88
98
|
raw.cost.subscriptionDisplay === "both"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
) {
|
|
100
|
+
cost.subscriptionDisplay = raw.cost.subscriptionDisplay;
|
|
101
|
+
}
|
|
102
|
+
if (currency) cost.currency = currency;
|
|
103
|
+
options.cost = cost;
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
if (isRecord(raw.context)) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
const context: NonNullable<StatusLineSegmentOptions["context"]> = {};
|
|
108
|
+
if (raw.context.format === "full" || raw.context.format === "percent") {
|
|
109
|
+
context.format = raw.context.format;
|
|
110
|
+
}
|
|
111
|
+
options.context = context;
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
if (isRecord(raw.cache_read)) {
|
|
104
|
-
|
|
105
|
-
|
|
115
|
+
const cacheRead: NonNullable<StatusLineSegmentOptions["cache_read"]> = {};
|
|
116
|
+
if (
|
|
117
|
+
raw.cache_read.format === "tokens" ||
|
|
106
118
|
raw.cache_read.format === "percent" ||
|
|
107
119
|
raw.cache_read.format === "both"
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
120
|
+
) {
|
|
121
|
+
cacheRead.format = raw.cache_read.format;
|
|
122
|
+
}
|
|
123
|
+
options.cache_read = cacheRead;
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
if (isRecord(raw.openPorts)) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
const openPorts: NonNullable<StatusLineSegmentOptions["openPorts"]> = {};
|
|
128
|
+
if (typeof raw.openPorts.includeUdp === "boolean") {
|
|
129
|
+
openPorts.includeUdp = raw.openPorts.includeUdp;
|
|
130
|
+
}
|
|
131
|
+
if (typeof raw.openPorts.host === "string" && raw.openPorts.host.trim()) {
|
|
132
|
+
openPorts.host = raw.openPorts.host.trim();
|
|
133
|
+
}
|
|
134
|
+
options.openPorts = openPorts;
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
if (isRecord(raw.tps)) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
const tps: NonNullable<StatusLineSegmentOptions["tps"]> = {};
|
|
139
|
+
if (typeof raw.tps.windowMs === "number" && Number.isFinite(raw.tps.windowMs)) {
|
|
140
|
+
tps.windowMs = Math.min(5000, Math.max(500, Math.floor(raw.tps.windowMs)));
|
|
141
|
+
}
|
|
142
|
+
if (raw.tps.mode === "both" || raw.tps.mode === "out" || raw.tps.mode === "in") {
|
|
143
|
+
tps.mode = raw.tps.mode;
|
|
144
|
+
}
|
|
145
|
+
options.tps = tps;
|
|
131
146
|
}
|
|
132
147
|
|
|
133
148
|
// Generic `template` override for every segment option group:
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* structural-preset-data.ts
|
|
3
|
+
* ---------------------------------------------------------------------------
|
|
4
|
+
* Shared helpers and chrome/deck/welcome constants for the structural presets.
|
|
5
|
+
* The preset definitions live in structural-preset-table.ts; the public API
|
|
6
|
+
* (getStructuralPreset, etc.) stays in structural-presets.ts.
|
|
7
|
+
* ---------------------------------------------------------------------------
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ChromeSpec, DeckSpec, MotionRef, WelcomeSpec, WishcraftTokens } from "./types.ts";
|
|
11
|
+
import type { MotionEvent } from "../motion/types.ts";
|
|
12
|
+
|
|
13
|
+
export function tokens(partial: Partial<WishcraftTokens>): Partial<WishcraftTokens> {
|
|
14
|
+
return partial;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function motion(
|
|
18
|
+
signature: MotionRef,
|
|
19
|
+
overrides?: Partial<Record<MotionEvent, MotionRef>>,
|
|
20
|
+
): Partial<Record<MotionEvent, MotionRef>> {
|
|
21
|
+
const base: Partial<Record<MotionEvent, MotionRef>> = {
|
|
22
|
+
idle: "wisp",
|
|
23
|
+
thinking: signature,
|
|
24
|
+
streaming: signature,
|
|
25
|
+
"tool.start": signature,
|
|
26
|
+
"tool.end": "rune-bloom",
|
|
27
|
+
"idea.capture": "rune-bloom",
|
|
28
|
+
"skill.insert": "rune-bloom",
|
|
29
|
+
"policy.deny": "rune-bloom",
|
|
30
|
+
repair: signature,
|
|
31
|
+
compact: "bar",
|
|
32
|
+
success: "rune-bloom",
|
|
33
|
+
warning: "rune-bloom",
|
|
34
|
+
error: "rune-bloom",
|
|
35
|
+
};
|
|
36
|
+
return { ...base, ...overrides };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const ROUNDED_CHROME: ChromeSpec = {
|
|
40
|
+
frame: "rounded",
|
|
41
|
+
corners: { tl: "╭", tr: "╮", bl: "╰", br: "╯" },
|
|
42
|
+
dividers: { horizontal: "─", vertical: "│", cross: "┼" },
|
|
43
|
+
density: "medium",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const MINIMAL_CHROME: ChromeSpec = {
|
|
47
|
+
frame: "minimal",
|
|
48
|
+
corners: { tl: " ", tr: " ", bl: " ", br: " " },
|
|
49
|
+
dividers: { horizontal: "─", vertical: " ", cross: " " },
|
|
50
|
+
density: "spacious",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const BORDERLESS_CHROME: ChromeSpec = {
|
|
54
|
+
frame: "borderless",
|
|
55
|
+
corners: { tl: "", tr: "", bl: "", br: "" },
|
|
56
|
+
dividers: { horizontal: "─", vertical: " ", cross: " " },
|
|
57
|
+
density: "spacious",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const DEFAULT_DECK: DeckSpec = {
|
|
61
|
+
navigation: "tabs",
|
|
62
|
+
panelStyle: "framed",
|
|
63
|
+
activityStyle: "pulse",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const DEFAULT_WELCOME: WelcomeSpec = {
|
|
67
|
+
lantern: true,
|
|
68
|
+
ambient: true,
|
|
69
|
+
};
|