@groeponline/pi-wishcraft 1.1.0 → 1.3.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/CHANGELOG.md +15 -0
- package/README.md +16 -7
- package/ROADMAP.md +144 -425
- package/docs/commands.md +6 -2
- package/docs/configuration.md +21 -0
- package/docs/design/accessibility.md +71 -0
- package/docs/design/deck-layout.md +69 -0
- package/docs/design/motion-gallery.md +80 -0
- package/docs/design/motion-system.md +119 -0
- package/docs/design/presets.md +196 -0
- package/docs/design/regression-testing.md +54 -0
- package/docs/design/responsive.md +53 -0
- package/docs/design/signal.md +71 -0
- package/docs/design/theme-contract.md +132 -0
- package/docs/design/vnext-overview.md +55 -0
- package/docs/design/vnext-release-plan.md +212 -0
- package/docs/index.md +19 -1
- package/docs/segments.md +1 -1
- package/package.json +2 -1
- package/src/config/appearance.ts +229 -0
- package/src/config/parse.ts +41 -0
- package/src/config/presets.ts +184 -0
- package/src/config/structural-presets.ts +555 -0
- package/src/config/tokens.ts +154 -0
- package/src/config/types.ts +210 -2
- package/src/extension/commands/commands.ts +36 -12
- package/src/extension/commands/powerline-completions.ts +4 -0
- package/src/extension/commands/queue-commands.ts +6 -0
- package/src/extension/core/segment-context.ts +27 -21
- package/src/extension/core/state.ts +16 -1
- package/src/extension/core/types.ts +11 -1
- package/src/extension/session/session-lifecycle.ts +29 -65
- package/src/extension/session/session-notifications.ts +91 -0
- package/src/extension/settings/appearance-write.ts +135 -0
- package/src/extension/settings/wishcraft-config-items.ts +119 -0
- package/src/extension/settings/wishcraft-config.ts +28 -114
- package/src/extension/skills/skill-manager.ts +5 -0
- package/src/extension/ui/deck/component.ts +371 -0
- package/src/extension/ui/deck/index.ts +34 -0
- package/src/extension/ui/deck/render.ts +260 -0
- package/src/extension/ui/deck/route-bodies.ts +209 -0
- package/src/extension/ui/deck/routes.ts +37 -0
- package/src/extension/ui/deck/session-snapshot.ts +122 -0
- package/src/extension/ui/deck/types.ts +97 -0
- package/src/extension/ui/powerline-menu-view.ts +19 -15
- package/src/extension/ui/signal-layout.ts +76 -0
- package/src/extension/ui/status-line-renderers.ts +20 -2
- package/src/motion/accessibility.ts +59 -0
- package/src/motion/catalog-extra.ts +429 -0
- package/src/motion/catalog.ts +336 -0
- package/src/motion/composer.ts +147 -0
- package/src/motion/frames.ts +84 -0
- package/src/motion/gallery.ts +77 -0
- package/src/motion/index.ts +78 -0
- package/src/motion/policy.ts +128 -0
- package/src/motion/scheduler.ts +159 -0
- package/src/motion/types.ts +132 -0
- package/src/render/timer.ts +1 -0
- package/src/signal/controller.ts +135 -0
- package/src/signal/integration.ts +46 -0
- package/src/signal/render.ts +178 -0
- package/src/theme/detect.ts +48 -0
- package/src/theme/tokens/index.ts +9 -0
- package/src/theme/tokens/mapping.ts +21 -0
- package/src/theme/tokens/types.ts +6 -0
- package/src/usage/token-budget.ts +23 -0
package/src/config/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Theme, ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { MotionEvent } from "../motion/types.ts";
|
|
2
3
|
import type { CostCurrencyCode } from "../usage/rates.ts";
|
|
3
4
|
|
|
4
5
|
// Theme color - either a pi theme color name or a custom hex color
|
|
@@ -28,6 +29,176 @@ export type SemanticColor =
|
|
|
28
29
|
// Color scheme mapping semantic names to actual colors
|
|
29
30
|
export type ColorScheme = Partial<Record<SemanticColor, ColorValue>>;
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Semantic design tokens (vNext). Presets fill abstract roles; the segment
|
|
34
|
+
* colors above are derived from them. See src/config/tokens.ts for the mapping
|
|
35
|
+
* and the default palette.
|
|
36
|
+
*/
|
|
37
|
+
export interface WishcraftTokens {
|
|
38
|
+
/** Deck background. */
|
|
39
|
+
surface: ColorValue;
|
|
40
|
+
/** Raised areas: headers, footers, selected rows. */
|
|
41
|
+
surfaceRaised: ColorValue;
|
|
42
|
+
text: ColorValue;
|
|
43
|
+
textMuted: ColorValue;
|
|
44
|
+
primary: ColorValue;
|
|
45
|
+
secondary: ColorValue;
|
|
46
|
+
accent: ColorValue;
|
|
47
|
+
success: ColorValue;
|
|
48
|
+
warning: ColorValue;
|
|
49
|
+
error: ColorValue;
|
|
50
|
+
/** Focused control or active route. */
|
|
51
|
+
focus: ColorValue;
|
|
52
|
+
/** Selected row background. */
|
|
53
|
+
selection: ColorValue;
|
|
54
|
+
/** Resting motion, e.g. a still rail. */
|
|
55
|
+
motionDim: ColorValue;
|
|
56
|
+
/** The travelling head of a sweep. */
|
|
57
|
+
motionHot: ColorValue;
|
|
58
|
+
/** Cells just behind the head. */
|
|
59
|
+
motionTrail: ColorValue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type TokenRole = keyof WishcraftTokens;
|
|
63
|
+
|
|
64
|
+
/** Motion catalog id, e.g. `ember-relay`. */
|
|
65
|
+
export type MotionRef = string;
|
|
66
|
+
|
|
67
|
+
export type StructuralPresetName =
|
|
68
|
+
| "lanternwake"
|
|
69
|
+
| "threadbound"
|
|
70
|
+
| "scryglass"
|
|
71
|
+
| "runebloom"
|
|
72
|
+
| "moonwell"
|
|
73
|
+
| "hexforge"
|
|
74
|
+
| "vellum"
|
|
75
|
+
| "wisp"
|
|
76
|
+
| "starweave"
|
|
77
|
+
| "crucible";
|
|
78
|
+
|
|
79
|
+
export const STRUCTURAL_PRESET_NAMES = [
|
|
80
|
+
"lanternwake",
|
|
81
|
+
"threadbound",
|
|
82
|
+
"scryglass",
|
|
83
|
+
"runebloom",
|
|
84
|
+
"moonwell",
|
|
85
|
+
"hexforge",
|
|
86
|
+
"vellum",
|
|
87
|
+
"wisp",
|
|
88
|
+
"starweave",
|
|
89
|
+
"crucible",
|
|
90
|
+
] as const satisfies readonly StructuralPresetName[];
|
|
91
|
+
|
|
92
|
+
export type ChromeFrame = "rounded" | "square" | "double" | "minimal" | "borderless";
|
|
93
|
+
export type ChromeDensity = "compact" | "medium" | "spacious";
|
|
94
|
+
|
|
95
|
+
export interface ChromeSpec {
|
|
96
|
+
frame: ChromeFrame;
|
|
97
|
+
corners: { tl: string; tr: string; bl: string; br: string };
|
|
98
|
+
dividers: { horizontal: string; vertical: string; cross: string };
|
|
99
|
+
density: ChromeDensity;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type SignalLayout =
|
|
103
|
+
| "standard"
|
|
104
|
+
| "capsule"
|
|
105
|
+
| "woven"
|
|
106
|
+
| "sparse"
|
|
107
|
+
| "block"
|
|
108
|
+
| "arc"
|
|
109
|
+
| "editorial"
|
|
110
|
+
| "fluid"
|
|
111
|
+
| "constellation"
|
|
112
|
+
| "cell";
|
|
113
|
+
|
|
114
|
+
export interface SignalSpec {
|
|
115
|
+
layout: SignalLayout;
|
|
116
|
+
separators: {
|
|
117
|
+
left: string;
|
|
118
|
+
right: string;
|
|
119
|
+
subLeft?: string;
|
|
120
|
+
subRight?: string;
|
|
121
|
+
};
|
|
122
|
+
caps: {
|
|
123
|
+
leftOpen?: string;
|
|
124
|
+
leftClose?: string;
|
|
125
|
+
rightOpen?: string;
|
|
126
|
+
rightClose?: string;
|
|
127
|
+
};
|
|
128
|
+
/** Signature lane animation from the motion catalog. */
|
|
129
|
+
animation: MotionRef;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export type DeckNavigation = "tabs" | "rail" | "minimal";
|
|
133
|
+
export type DeckPanelStyle = "framed" | "borderless" | "inset";
|
|
134
|
+
export type DeckActivityStyle = "pulse" | "bar" | "none";
|
|
135
|
+
|
|
136
|
+
export interface DeckSpec {
|
|
137
|
+
navigation: DeckNavigation;
|
|
138
|
+
panelStyle: DeckPanelStyle;
|
|
139
|
+
activityStyle: DeckActivityStyle;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface WelcomeSpec {
|
|
143
|
+
lantern: boolean;
|
|
144
|
+
ambient: boolean;
|
|
145
|
+
motionId?: MotionRef;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export type GlyphMode = "nerd" | "ascii" | "auto";
|
|
149
|
+
|
|
150
|
+
export interface GlyphSet {
|
|
151
|
+
mode: GlyphMode;
|
|
152
|
+
/** Leading ornament for the model segment (Nerd). */
|
|
153
|
+
model?: string;
|
|
154
|
+
/** ASCII fallback for the model ornament. */
|
|
155
|
+
modelAscii?: string;
|
|
156
|
+
/** Default segment marker (Nerd). */
|
|
157
|
+
segment?: string;
|
|
158
|
+
/** ASCII fallback for segment markers. */
|
|
159
|
+
segmentAscii?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** vNext structural personality: tokens, chrome, signal grammar, motion, deck, welcome, glyphs. */
|
|
163
|
+
export interface StructuralPresetDef {
|
|
164
|
+
name: StructuralPresetName;
|
|
165
|
+
displayName: string;
|
|
166
|
+
description: string;
|
|
167
|
+
tokens: Partial<WishcraftTokens>;
|
|
168
|
+
chrome: ChromeSpec;
|
|
169
|
+
signal: SignalSpec;
|
|
170
|
+
motion: Partial<Record<MotionEvent, MotionRef>>;
|
|
171
|
+
deck: DeckSpec;
|
|
172
|
+
welcome: WelcomeSpec;
|
|
173
|
+
glyphs: GlyphSet;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Decoupled appearance layers. Each field can point at a different structural
|
|
178
|
+
* preset so palette, signal layout, chrome, and motion stay independent.
|
|
179
|
+
*/
|
|
180
|
+
export interface AppearanceMixConfig {
|
|
181
|
+
base?: StructuralPresetName;
|
|
182
|
+
palette?: StructuralPresetName;
|
|
183
|
+
signalLayout?: StructuralPresetName;
|
|
184
|
+
chrome?: StructuralPresetName;
|
|
185
|
+
glyphs?: StructuralPresetName;
|
|
186
|
+
deck?: StructuralPresetName;
|
|
187
|
+
welcome?: StructuralPresetName;
|
|
188
|
+
motion?: StructuralPresetName | Partial<Record<MotionEvent, MotionRef>>;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface ResolvedAppearance {
|
|
192
|
+
base: StructuralPresetName;
|
|
193
|
+
tokens: WishcraftTokens;
|
|
194
|
+
chrome: ChromeSpec;
|
|
195
|
+
signal: SignalSpec;
|
|
196
|
+
motion: Partial<Record<MotionEvent, MotionRef>>;
|
|
197
|
+
deck: DeckSpec;
|
|
198
|
+
welcome: WelcomeSpec;
|
|
199
|
+
glyphs: GlyphSet;
|
|
200
|
+
}
|
|
201
|
+
|
|
31
202
|
// Built-in segment identifiers
|
|
32
203
|
export const BUILTIN_STATUS_LINE_SEGMENT_IDS = [
|
|
33
204
|
"model",
|
|
@@ -78,7 +249,24 @@ export type StatusLineSeparatorStyle =
|
|
|
78
249
|
export type PowerlinePlacement = "above" | "below";
|
|
79
250
|
|
|
80
251
|
export type StatusLinePreset =
|
|
81
|
-
|
|
252
|
+
| "default"
|
|
253
|
+
| "minimal"
|
|
254
|
+
| "compact"
|
|
255
|
+
| "full"
|
|
256
|
+
| "nerd"
|
|
257
|
+
| "ascii"
|
|
258
|
+
| "chef"
|
|
259
|
+
// vNext Structural Signature Presets
|
|
260
|
+
| "lanternwake"
|
|
261
|
+
| "threadbound"
|
|
262
|
+
| "scryglass"
|
|
263
|
+
| "runebloom"
|
|
264
|
+
| "moonwell"
|
|
265
|
+
| "hexforge"
|
|
266
|
+
| "vellum"
|
|
267
|
+
| "wisp"
|
|
268
|
+
| "starweave"
|
|
269
|
+
| "crucible";
|
|
82
270
|
|
|
83
271
|
// Optional `{value}` template override shared by all segment option groups.
|
|
84
272
|
// Replaces `{value}` in the rendered value text (e.g. "{value} tok/s").
|
|
@@ -153,7 +341,7 @@ export interface CustomStatusItem {
|
|
|
153
341
|
excludeFromExtensionStatuses: boolean;
|
|
154
342
|
}
|
|
155
343
|
|
|
156
|
-
|
|
344
|
+
|
|
157
345
|
export interface PresetDef {
|
|
158
346
|
leftSegments: StatusLineSegmentId[];
|
|
159
347
|
rightSegments: StatusLineSegmentId[];
|
|
@@ -163,6 +351,24 @@ export interface PresetDef {
|
|
|
163
351
|
segmentOptions?: StatusLineSegmentOptions;
|
|
164
352
|
/** Color scheme for this preset */
|
|
165
353
|
colors?: ColorScheme;
|
|
354
|
+
/**
|
|
355
|
+
* Semantic design tokens (vNext). When present, `colors` is derived from these
|
|
356
|
+
* and any explicit `colors` entry still wins. Optional, so the presets that
|
|
357
|
+
* predate tokens keep rendering exactly as before.
|
|
358
|
+
*/
|
|
359
|
+
tokens?: Partial<WishcraftTokens>;
|
|
360
|
+
/** Deck and overlay frame geometry (vNext). */
|
|
361
|
+
chrome?: ChromeSpec;
|
|
362
|
+
/** Signal lane grammar and separators (vNext). */
|
|
363
|
+
signal?: SignalSpec;
|
|
364
|
+
/** Per-event motion overrides (vNext). */
|
|
365
|
+
motion?: Partial<Record<MotionEvent, MotionRef>>;
|
|
366
|
+
/** Deck navigation and panel chrome (vNext). */
|
|
367
|
+
deck?: DeckSpec;
|
|
368
|
+
/** Welcome screen lantern and ambient motion (vNext). */
|
|
369
|
+
welcome?: WelcomeSpec;
|
|
370
|
+
/** Nerd / ASCII glyph grammar (vNext). */
|
|
371
|
+
glyphs?: GlyphSet;
|
|
166
372
|
}
|
|
167
373
|
|
|
168
374
|
// Separator definition
|
|
@@ -311,4 +517,6 @@ export interface CustomPresetConfig {
|
|
|
311
517
|
separator?: StatusLineSeparatorStyle;
|
|
312
518
|
colors?: ColorScheme;
|
|
313
519
|
segmentOptions?: StatusLineSegmentOptions;
|
|
520
|
+
/** Semantic design tokens; `colors` entries still win over derived values. */
|
|
521
|
+
tokens?: Partial<WishcraftTokens>;
|
|
314
522
|
}
|
|
@@ -18,7 +18,9 @@ import {
|
|
|
18
18
|
} from "../settings/settings-io.ts";
|
|
19
19
|
import { showOpenPortsList, showSelectOverlay } from "../ui/menu-views.ts";
|
|
20
20
|
import { showTpsOverlay, showUsageOverlay } from "../ui/token-overlays.ts";
|
|
21
|
-
import {
|
|
21
|
+
import { openWishcraftDeck } from "../ui/deck/index.ts";
|
|
22
|
+
import { showPowerlineClassicMenu } from "../ui/powerline-menu-view.ts";
|
|
23
|
+
import { syncAppearanceForLayoutPreset } from "../settings/appearance-write.ts";
|
|
22
24
|
import { openStashHistory } from "../shortcuts/shortcuts-router.ts";
|
|
23
25
|
import { ensureShellSession, setBashModeActive } from "./bash-mode-actions.ts";
|
|
24
26
|
import { setupCustomEditor } from "../ui/custom-editor.ts";
|
|
@@ -31,6 +33,7 @@ import { publishPowerlineStatuses } from "../core/status-export.ts";
|
|
|
31
33
|
import { config, normalizePreset } from "../core/state.ts";
|
|
32
34
|
import type { RuntimeState } from "../core/types.ts";
|
|
33
35
|
import { getPowerlineArgumentCompletions } from "./powerline-completions.ts";
|
|
36
|
+
import { settleSignal } from "../../signal/integration.ts";
|
|
34
37
|
|
|
35
38
|
export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
36
39
|
registerCdCommand(pi, () => rt.currentCtx?.cwd ?? process.cwd());
|
|
@@ -39,9 +42,9 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
39
42
|
registerSkillManagerCommand(pi, rt);
|
|
40
43
|
registerWishcraftConfigCommand(pi, rt);
|
|
41
44
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
description: "Configure
|
|
45
|
+
// `/signal` is the vNext command; `/powerline` remains a transparent alias.
|
|
46
|
+
const signalCommand: Parameters<ExtensionAPI["registerCommand"]>[1] = {
|
|
47
|
+
description: "Configure Signal status (toggle, preset, placement)",
|
|
45
48
|
getArgumentCompletions(argumentPrefix) {
|
|
46
49
|
return getPowerlineArgumentCompletions(argumentPrefix);
|
|
47
50
|
},
|
|
@@ -54,8 +57,9 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
54
57
|
rt.enabled = !rt.enabled;
|
|
55
58
|
if (rt.enabled) {
|
|
56
59
|
setupCustomEditor(pi, rt, ctx);
|
|
57
|
-
ctx.ui.notify("
|
|
60
|
+
ctx.ui.notify("Signal enabled", "info");
|
|
58
61
|
} else {
|
|
62
|
+
settleSignal(rt);
|
|
59
63
|
rt.shellSession?.dispose();
|
|
60
64
|
rt.shellSession = null;
|
|
61
65
|
rt.bashTranscript.clear();
|
|
@@ -87,12 +91,20 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
87
91
|
rt.currentEditor = null;
|
|
88
92
|
rt.statusRenderScheduler.cancel();
|
|
89
93
|
resetLayoutCache(rt);
|
|
90
|
-
ctx.ui.notify("
|
|
94
|
+
ctx.ui.notify("Signal disabled", "info");
|
|
91
95
|
}
|
|
92
96
|
return;
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
const normalizedArgs = args.trim().toLowerCase();
|
|
100
|
+
if (normalizedArgs === "menu") {
|
|
101
|
+
await showPowerlineClassicMenu(rt, ctx);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (normalizedArgs === "deck") {
|
|
105
|
+
await openWishcraftDeck(rt, ctx, "signal");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
96
108
|
if (normalizedArgs === "doctor") {
|
|
97
109
|
await runPowerlineDoctor(rt, ctx);
|
|
98
110
|
return;
|
|
@@ -123,12 +135,12 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
123
135
|
)
|
|
124
136
|
) {
|
|
125
137
|
ctx.ui.notify(
|
|
126
|
-
`
|
|
138
|
+
`Signal placement set to: ${config.placement}`,
|
|
127
139
|
"info",
|
|
128
140
|
);
|
|
129
141
|
} else {
|
|
130
142
|
ctx.ui.notify(
|
|
131
|
-
`
|
|
143
|
+
`Signal placement set to: ${config.placement} (not persisted; check settings.json)`,
|
|
132
144
|
"warning",
|
|
133
145
|
);
|
|
134
146
|
}
|
|
@@ -144,7 +156,9 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
144
156
|
setupCustomEditor(pi, rt, ctx);
|
|
145
157
|
}
|
|
146
158
|
|
|
147
|
-
|
|
159
|
+
const persisted = writePowerlinePresetSetting(preset, ctx.cwd);
|
|
160
|
+
syncAppearanceForLayoutPreset(rt, ctx.cwd, preset);
|
|
161
|
+
if (persisted) {
|
|
148
162
|
ctx.ui.notify(`Preset set to: ${preset}`, "info");
|
|
149
163
|
} else {
|
|
150
164
|
ctx.ui.notify(
|
|
@@ -159,6 +173,11 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
159
173
|
const presetList = Object.keys(PRESETS).join(", ");
|
|
160
174
|
ctx.ui.notify(`Available presets: ${presetList}`, "info");
|
|
161
175
|
},
|
|
176
|
+
};
|
|
177
|
+
pi.registerCommand("signal", signalCommand);
|
|
178
|
+
pi.registerCommand("powerline", {
|
|
179
|
+
...signalCommand,
|
|
180
|
+
description: "Compatibility alias for /signal",
|
|
162
181
|
});
|
|
163
182
|
|
|
164
183
|
pi.registerCommand("stash-history", {
|
|
@@ -250,8 +269,12 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
250
269
|
|
|
251
270
|
pi.registerCommand("usage", {
|
|
252
271
|
description: "Show session / today / week token usage overlay",
|
|
253
|
-
handler: async (
|
|
272
|
+
handler: async (args, ctx) => {
|
|
254
273
|
rt.currentCtx = ctx;
|
|
274
|
+
if (args?.trim().toLowerCase() === "deck") {
|
|
275
|
+
await openWishcraftDeck(rt, ctx, "usage");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
255
278
|
await showUsageOverlay(rt, ctx);
|
|
256
279
|
},
|
|
257
280
|
});
|
|
@@ -295,9 +318,10 @@ export function registerCommands(pi: ExtensionAPI, rt: RuntimeState): void {
|
|
|
295
318
|
// Configurable powerline shortcuts (re-bound on /reload via settings.powerlineShortcuts).
|
|
296
319
|
if (rt.resolvedShortcuts.menu) {
|
|
297
320
|
pi.registerShortcut(rt.resolvedShortcuts.menu as KeyId, {
|
|
298
|
-
description: "
|
|
321
|
+
description: "Wishcraft Deck (operator control surface)",
|
|
299
322
|
handler: async (ctx) => {
|
|
300
|
-
|
|
323
|
+
rt.currentCtx = ctx;
|
|
324
|
+
await openWishcraftDeck(rt, ctx, "home");
|
|
301
325
|
},
|
|
302
326
|
});
|
|
303
327
|
}
|
|
@@ -19,6 +19,10 @@ export const POWERLINE_SUBCOMMANDS: ReadonlyArray<{
|
|
|
19
19
|
value: "placement",
|
|
20
20
|
description: "Move the primary row above or below the editor",
|
|
21
21
|
},
|
|
22
|
+
{
|
|
23
|
+
value: "menu",
|
|
24
|
+
description: "Open Navigate / Configure / Status",
|
|
25
|
+
},
|
|
22
26
|
];
|
|
23
27
|
|
|
24
28
|
const PLACEMENT_DESCRIPTIONS: Record<(typeof POWERLINE_PLACEMENT_VALUES)[number], string> = {
|
|
@@ -15,6 +15,7 @@ import { getCurrentEditorText } from "../shortcuts/shortcuts-router.ts";
|
|
|
15
15
|
import { getQueueContext } from "../queue/queue-context.ts";
|
|
16
16
|
import { config } from "../core/state.ts";
|
|
17
17
|
import type { RuntimeState } from "../core/types.ts";
|
|
18
|
+
import { openWishcraftDeck } from "../ui/deck/index.ts";
|
|
18
19
|
|
|
19
20
|
export function registerQueueCommands(
|
|
20
21
|
pi: ExtensionAPI,
|
|
@@ -70,6 +71,11 @@ export function registerQueueCommands(
|
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
if (action === "deck") {
|
|
75
|
+
await openWishcraftDeck(rt, ctx, "ideas");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
if (action === "next") {
|
|
74
80
|
const item = findNextIdea(rt, ctx);
|
|
75
81
|
if (!item) {
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
|
|
6
6
|
import type { SegmentContext, ColorScheme } from "../../config/types.ts";
|
|
7
7
|
import { getPreset } from "../../config/presets.ts";
|
|
8
|
+
import { liveColorScheme } from "../../config/appearance.ts";
|
|
8
9
|
import {
|
|
9
10
|
collectHiddenExtensionStatusKeys,
|
|
10
11
|
deriveAutoCustomItems,
|
|
@@ -14,14 +15,8 @@ import { getDefaultColors } from "../../theme/theme.ts";
|
|
|
14
15
|
import { getGitStatus } from "../../git/status.ts";
|
|
15
16
|
import { getQueueContext } from "../queue/queue-context.ts";
|
|
16
17
|
import { getUsageTokenTotal } from "../../usage/ledger.ts";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
loadUsageFileFromDisk,
|
|
20
|
-
tokenTotal,
|
|
21
|
-
totalsForRange,
|
|
22
|
-
} from "../../usage/usage-store.ts";
|
|
23
|
-
import { parseTokenBudget } from "../../usage/token-budget.ts";
|
|
24
|
-
import { readSettings } from "../settings/settings-io.ts";
|
|
18
|
+
import { tokenBudgetSnapshotForDay } from "../../usage/token-budget.ts";
|
|
19
|
+
import { dayKey } from "../../usage/usage-store.ts";
|
|
25
20
|
import {
|
|
26
21
|
CUSTOM_COMPACTION_STATUS_KEY,
|
|
27
22
|
EDITOR_STATUS_DEFER_MS,
|
|
@@ -119,13 +114,24 @@ export function installFooterStatusRepaintHook(
|
|
|
119
114
|
};
|
|
120
115
|
}
|
|
121
116
|
|
|
117
|
+
export interface BuildSegmentContextOptions {
|
|
118
|
+
/** Omit token-budget data from lightweight UI snapshots. */
|
|
119
|
+
includeTokenBudget?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
122
|
export function buildSegmentContext(
|
|
123
123
|
rt: RuntimeState,
|
|
124
124
|
ctx: any,
|
|
125
125
|
theme: Theme,
|
|
126
|
+
options: BuildSegmentContextOptions = {},
|
|
126
127
|
): SegmentContext {
|
|
127
128
|
const presetDef = getPreset(config.preset);
|
|
128
|
-
const colors: ColorScheme =
|
|
129
|
+
const colors: ColorScheme = liveColorScheme(
|
|
130
|
+
presetDef,
|
|
131
|
+
config.appearance,
|
|
132
|
+
config.preset,
|
|
133
|
+
getDefaultColors,
|
|
134
|
+
);
|
|
129
135
|
|
|
130
136
|
// Build usage stats and get thinking level from session (cached; the full
|
|
131
137
|
// event list is only re-scanned when events are appended or the trailing
|
|
@@ -199,6 +205,10 @@ export function buildSegmentContext(
|
|
|
199
205
|
getQueueContext(ctx),
|
|
200
206
|
rt.powerlineCompacting,
|
|
201
207
|
);
|
|
208
|
+
const budgetSnapshot = tokenBudgetSnapshotForDay(
|
|
209
|
+
rt.tokenBudgetSnapshot,
|
|
210
|
+
dayKey(Date.now()),
|
|
211
|
+
);
|
|
202
212
|
|
|
203
213
|
return {
|
|
204
214
|
model: ctx.model,
|
|
@@ -228,18 +238,14 @@ export function buildSegmentContext(
|
|
|
228
238
|
effectiveCustomItems,
|
|
229
239
|
options: segmentOptions,
|
|
230
240
|
segmentLabels: new Map(Object.entries(config.segmentLabels)),
|
|
231
|
-
tokenBudget:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
totalsForRange(loadUsageFileFromDisk(), todayStart, now + 1),
|
|
239
|
-
);
|
|
240
|
-
return { dailyLimit, dailyUsed };
|
|
241
|
-
})(),
|
|
241
|
+
tokenBudget:
|
|
242
|
+
options.includeTokenBudget === false
|
|
243
|
+
? undefined
|
|
244
|
+
: {
|
|
245
|
+
dailyLimit: budgetSnapshot.dailyLimit,
|
|
246
|
+
dailyUsed: budgetSnapshot.dailyUsed,
|
|
247
|
+
},
|
|
242
248
|
theme,
|
|
243
249
|
colors,
|
|
244
250
|
};
|
|
245
|
-
}
|
|
251
|
+
}
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
import { CoreContextUsageCache } from "../../usage/context.ts";
|
|
13
13
|
import { createWelcomeDismissScheduler } from "../../welcome/auto-dismiss.ts";
|
|
14
14
|
import { createRenderScheduler } from "../../render/timer.ts";
|
|
15
|
+
import { MotionScheduler, policyFromEnvironment } from "../../motion/index.ts";
|
|
16
|
+
import { createSignalRuntime } from "../../signal/controller.ts";
|
|
15
17
|
import {
|
|
16
18
|
resolveShortcutConfig,
|
|
17
19
|
parseBashModeSettings,
|
|
@@ -47,6 +49,8 @@ export let config: PowerlineConfig = {
|
|
|
47
49
|
segments: {},
|
|
48
50
|
presets: {},
|
|
49
51
|
segmentLabels: {},
|
|
52
|
+
appearance: {},
|
|
53
|
+
motionLevel: "full",
|
|
50
54
|
};
|
|
51
55
|
|
|
52
56
|
export function setConfig(next: PowerlineConfig): void {
|
|
@@ -113,6 +117,7 @@ export function createRuntimeState(
|
|
|
113
117
|
currentEditor: null,
|
|
114
118
|
costAlertNotified: false,
|
|
115
119
|
tokenBudgetNotifiedLevel: 0,
|
|
120
|
+
tokenBudgetSnapshot: { day: "", dailyLimit: null, dailyUsed: 0 },
|
|
116
121
|
bashModeActive: false,
|
|
117
122
|
bashTranscript: new BashTranscriptStore(bashModeSettings),
|
|
118
123
|
bashCompletionEngine: new BashCompletionEngine(),
|
|
@@ -135,6 +140,8 @@ export function createRuntimeState(
|
|
|
135
140
|
|
|
136
141
|
resolvedShortcuts,
|
|
137
142
|
bashModeSettings,
|
|
143
|
+
motionPolicy: policyFromEnvironment(process.env, config.motionLevel),
|
|
144
|
+
signal: createSignalRuntime(),
|
|
138
145
|
} as RuntimeState;
|
|
139
146
|
|
|
140
147
|
rt.welcomeDismissScheduler = createWelcomeDismissScheduler({
|
|
@@ -159,5 +166,13 @@ export function createRuntimeState(
|
|
|
159
166
|
rt.tuiRef?.requestRender();
|
|
160
167
|
}, STATUS_RENDER_DEBOUNCE_MS);
|
|
161
168
|
|
|
169
|
+
rt.motionScheduler = new MotionScheduler({
|
|
170
|
+
requestRender: () => {
|
|
171
|
+
// Motion only changes the Signal rail; segment data remains cached.
|
|
172
|
+
rt.lastLayoutResult = null;
|
|
173
|
+
rt.tuiRef?.requestRender();
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
162
177
|
return rt;
|
|
163
|
-
}
|
|
178
|
+
}
|
|
@@ -11,8 +11,11 @@ import type {
|
|
|
11
11
|
SessionTokenStatsCache,
|
|
12
12
|
} from "../../usage/ledger.ts";
|
|
13
13
|
import type { CoreContextUsageCache } from "../../usage/context.ts";
|
|
14
|
+
import type { TokenBudgetSnapshot } from "../../usage/token-budget.ts";
|
|
14
15
|
import type { WelcomeDismissScheduler } from "../../welcome/auto-dismiss.ts";
|
|
15
16
|
import type { RenderScheduler } from "../../render/timer.ts";
|
|
17
|
+
import type { MotionPolicy, MotionScheduler } from "../../motion/index.ts";
|
|
18
|
+
import type { SignalRuntime } from "../../signal/controller.ts";
|
|
16
19
|
|
|
17
20
|
export type ShortcutBinding = string | null;
|
|
18
21
|
|
|
@@ -66,6 +69,8 @@ export interface RuntimeState {
|
|
|
66
69
|
costAlertNotified: boolean;
|
|
67
70
|
/** Highest daily-budget warning already shown this session (0 / 80 / 100). */
|
|
68
71
|
tokenBudgetNotifiedLevel: 0 | 80 | 100;
|
|
72
|
+
/** Event-driven token-budget snapshot consumed by render paths without disk I/O. */
|
|
73
|
+
tokenBudgetSnapshot: TokenBudgetSnapshot;
|
|
69
74
|
bashModeActive: boolean;
|
|
70
75
|
bashTranscript: BashTranscriptStore;
|
|
71
76
|
bashCompletionEngine: BashCompletionEngine;
|
|
@@ -98,4 +103,9 @@ export interface RuntimeState {
|
|
|
98
103
|
|
|
99
104
|
welcomeDismissScheduler: WelcomeDismissScheduler<any>;
|
|
100
105
|
statusRenderScheduler: RenderScheduler;
|
|
101
|
-
|
|
106
|
+
/** The single shared clock for every Wishcraft animation surface. */
|
|
107
|
+
motionScheduler: MotionScheduler;
|
|
108
|
+
motionPolicy: MotionPolicy;
|
|
109
|
+
/** Live Signal event, motion frame, and activity label. */
|
|
110
|
+
signal: SignalRuntime;
|
|
111
|
+
}
|