@groeponline/pi-wishcraft 1.3.0 → 1.4.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 +8 -0
- package/ROADMAP.md +22 -127
- package/docs/design/vnext-release-plan.md +3 -1
- package/package.json +1 -1
- package/src/config/parse.ts +12 -6
- package/src/config/settings-registry.ts +118 -0
- package/src/config/structural-presets.ts +6 -1
- package/src/core/frontmatter.ts +5 -2
- package/src/extension/contrib/appearance.ts +91 -0
- package/src/extension/contrib/registry.ts +42 -0
- package/src/extension/contrib/types.ts +20 -0
- package/src/extension/core/state.ts +5 -4
- package/src/extension/hooks/hooks-config.ts +6 -1
- package/src/extension/hooks/index.ts +11 -5
- package/src/extension/session/read-hints.ts +6 -2
- package/src/extension/settings/wishcraft-config-items.ts +14 -110
- package/src/extension/settings/wishcraft-config.ts +19 -17
- package/src/extension/skills/inline-invocation.ts +35 -11
- package/src/extension/skills/skill-registry.ts +41 -2
- package/src/extension/ui/deck/component.ts +27 -7
- package/src/extension/ui/deck/render.ts +4 -4
- package/src/extension/ui/deck/routes.ts +17 -2
- package/src/extension/ui/deck/types.ts +2 -0
- package/src/motion/catalog.ts +14 -11
- package/src/motion/policy.ts +3 -2
- package/src/signal/render.ts +49 -6
package/src/motion/catalog.ts
CHANGED
|
@@ -20,7 +20,8 @@ const CORE_MOTIONS: readonly MotionDef[] = [
|
|
|
20
20
|
colorRole: "motionHot",
|
|
21
21
|
fallbackGlyph: "*",
|
|
22
22
|
loop: "while-active",
|
|
23
|
-
|
|
23
|
+
// ponytail: vivid — longer trail + faster pulse, travels the full Signal rail
|
|
24
|
+
generator: { geometry: "ember", trail: 6, direction: "forward", intervalMs: 62, ease: "pulse" },
|
|
24
25
|
description: "Lanternwake signature. A warm ember travels the connected segments, only while work happens.",
|
|
25
26
|
},
|
|
26
27
|
{
|
|
@@ -29,10 +30,11 @@ const CORE_MOTIONS: readonly MotionDef[] = [
|
|
|
29
30
|
category: "wishcraft",
|
|
30
31
|
kind: "frames",
|
|
31
32
|
channels: ["workingGlyph", "ambient"],
|
|
32
|
-
colorRole: "
|
|
33
|
+
colorRole: "motionHot",
|
|
33
34
|
fallbackGlyph: "o",
|
|
34
35
|
loop: "ambient",
|
|
35
|
-
|
|
36
|
+
// ponytail: vivid ambient — higher contrast, tighter loop so idle actually breathes
|
|
37
|
+
frames: ["◌", "◎", "◈", "⬡", "◈", "◎"],
|
|
36
38
|
description: "Soft phase drift for minimal presets.",
|
|
37
39
|
},
|
|
38
40
|
{
|
|
@@ -56,7 +58,7 @@ const CORE_MOTIONS: readonly MotionDef[] = [
|
|
|
56
58
|
colorRole: "motionHot",
|
|
57
59
|
fallbackGlyph: "#",
|
|
58
60
|
loop: "while-active",
|
|
59
|
-
generator: { geometry: "heat", trail:
|
|
61
|
+
generator: { geometry: "heat", trail: 7, direction: "forward", intervalMs: 55, ease: "linear" },
|
|
60
62
|
description: "Heat propagates block by block toward the active tool.",
|
|
61
63
|
},
|
|
62
64
|
{
|
|
@@ -125,10 +127,10 @@ const CORE_MOTIONS: readonly MotionDef[] = [
|
|
|
125
127
|
category: "matrix",
|
|
126
128
|
kind: "generator",
|
|
127
129
|
channels: ["workingGlyph", "signal", "ambient"],
|
|
128
|
-
colorRole: "
|
|
130
|
+
colorRole: "motionHot",
|
|
129
131
|
fallbackGlyph: "O",
|
|
130
132
|
loop: "ambient",
|
|
131
|
-
generator: { geometry: "orbit", radius:
|
|
133
|
+
generator: { geometry: "orbit", radius: 3, trail: 5, intervalMs: 150, ease: "breathe" },
|
|
132
134
|
description: "Orbit and phase motion, slow enough for night work.",
|
|
133
135
|
},
|
|
134
136
|
{
|
|
@@ -276,13 +278,14 @@ export const CHANNEL_MATRIX: Record<MotionEvent, readonly MotionChannel[]> = {
|
|
|
276
278
|
};
|
|
277
279
|
|
|
278
280
|
/** Documented cadence bands per channel. */
|
|
281
|
+
// ponytail: tightened for vivid motion — signal/glyph sweep at ~60-80ms, ambient breathes at ~180ms
|
|
279
282
|
export const CADENCE_MS: Record<MotionChannel, { min: number; max: number }> = {
|
|
280
|
-
workingGlyph: { min:
|
|
281
|
-
signal: { min:
|
|
283
|
+
workingGlyph: { min: 55, max: 85 },
|
|
284
|
+
signal: { min: 55, max: 85 },
|
|
282
285
|
deckTransient: { min: 50, max: 100 },
|
|
283
|
-
panelIndicator: { min:
|
|
284
|
-
borderEmphasis: { min:
|
|
285
|
-
ambient: { min:
|
|
286
|
+
panelIndicator: { min: 100, max: 200 },
|
|
287
|
+
borderEmphasis: { min: 180, max: 350 },
|
|
288
|
+
ambient: { min: 180, max: 400 },
|
|
286
289
|
};
|
|
287
290
|
|
|
288
291
|
/** Gallery previews are allowed to run hotter than production channels. */
|
package/src/motion/policy.ts
CHANGED
|
@@ -80,9 +80,10 @@ export function targetFps(
|
|
|
80
80
|
? allowed.filter((channel) => consumers.includes(channel))
|
|
81
81
|
: allowed;
|
|
82
82
|
if (live.length === 0) return 0;
|
|
83
|
-
|
|
83
|
+
// ponytail: vivid idle breathes visibly; active sweeps at 16 FPS
|
|
84
|
+
if (live.length === 1 && live[0] === "ambient") return 8;
|
|
84
85
|
if (effectiveLevel(policy) === "reduced") return 3;
|
|
85
|
-
return
|
|
86
|
+
return 16;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
/** Color transitions are suppressed without color; glyph motion may stay. */
|
package/src/signal/render.ts
CHANGED
|
@@ -18,8 +18,9 @@ import { mergeSegmentsWithCustomItems } from "../config/powerline-config.ts";
|
|
|
18
18
|
import { renderSegment } from "../segments/index.ts";
|
|
19
19
|
import { ansi, colorEnabled, getFgAnsiCode } from "../theme/colors.ts";
|
|
20
20
|
import { getSeparator } from "../theme/separators.ts";
|
|
21
|
-
import { frameAt, getMotion } from "../motion/index.ts";
|
|
21
|
+
import { frameAt, getMotion, sweepPosition, trailGlyph } from "../motion/index.ts";
|
|
22
22
|
import type { SignalRuntime } from "./controller.ts";
|
|
23
|
+
import { getContributedSignalSources } from "../extension/contrib/registry.ts";
|
|
23
24
|
|
|
24
25
|
export interface SignalRenderOptions {
|
|
25
26
|
separatorStyle: StatusLineSeparatorStyle;
|
|
@@ -50,7 +51,10 @@ export function renderSignal(
|
|
|
50
51
|
},
|
|
51
52
|
);
|
|
52
53
|
const left = renderModules(merged.leftSegments, ctx);
|
|
53
|
-
const right =
|
|
54
|
+
const right = [
|
|
55
|
+
...renderModules(merged.rightSegments, ctx),
|
|
56
|
+
...renderContributedSources(ctx),
|
|
57
|
+
];
|
|
54
58
|
const secondary = renderModules(merged.secondarySegments, ctx);
|
|
55
59
|
const separator = getSeparator(options.separatorStyle).left;
|
|
56
60
|
|
|
@@ -91,11 +95,27 @@ export function renderActivity(
|
|
|
91
95
|
const open = spec.caps.leftOpen ?? "";
|
|
92
96
|
const close = spec.caps.leftClose ?? "";
|
|
93
97
|
const dim = getFgAnsiCode("sep");
|
|
98
|
+
const hot = getFgAnsiCode("accent");
|
|
94
99
|
const reset = colorEnabled() ? ansi.reset : "";
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
// ponytail: vivid sweep — 12-char rail with travelling head + 6-char trail, not a single glyph
|
|
101
|
+
const RAIL_WIDTH = 12;
|
|
102
|
+
let railInner: string;
|
|
103
|
+
if (!runtime.active) {
|
|
104
|
+
railInner = "━".repeat(RAIL_WIDTH);
|
|
105
|
+
} else {
|
|
106
|
+
const pos = sweepPosition(runtime.tick, RAIL_WIDTH, true);
|
|
107
|
+
let built = "";
|
|
108
|
+
for (let i = 0; i < RAIL_WIDTH; i++) {
|
|
109
|
+
const dist = Math.abs(i - pos);
|
|
110
|
+
if (dist === 0) built += glyph;
|
|
111
|
+
else if (dist <= 6) built += trailGlyph(dist, ascii);
|
|
112
|
+
else built += "━";
|
|
113
|
+
}
|
|
114
|
+
railInner = built;
|
|
115
|
+
}
|
|
116
|
+
const railColor = runtime.active ? hot : dim;
|
|
117
|
+
const rail = `${spec.separators.left}${railInner}${spec.separators.right}`;
|
|
118
|
+
return `${railColor}${open}${rail}${close}${reset} ${label}`;
|
|
99
119
|
}
|
|
100
120
|
|
|
101
121
|
function fitLanes(
|
|
@@ -164,6 +184,29 @@ function joinModules(modules: Module[], separator: string, width: number): strin
|
|
|
164
184
|
return fitted.length ? ` ${fitted.map((module) => module.content).join(sep)} ` : "";
|
|
165
185
|
}
|
|
166
186
|
|
|
187
|
+
const ANSI_CONTROL_RE = /\x1B(?:\][^\x07]*(?:\x07|\x1B\\)|\[[0-?]*[ -/]*[@-~]|[@-_])|\x9B[0-?]*[ -/]*[@-~]|\x9D[^\x07]*(?:\x07|\x1B\\)/g;
|
|
188
|
+
|
|
189
|
+
function stripAnsiControls(text: string): string {
|
|
190
|
+
return text.replace(ANSI_CONTROL_RE, "");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function renderContributedSources(ctx: SegmentContext): Module[] {
|
|
194
|
+
const out: Module[] = [];
|
|
195
|
+
for (const src of getContributedSignalSources()) {
|
|
196
|
+
try {
|
|
197
|
+
const raw = src.render?.(ctx);
|
|
198
|
+
if (!raw || typeof raw !== "string") continue;
|
|
199
|
+
const content = raw.trim();
|
|
200
|
+
if (!stripAnsiControls(content).trim()) continue;
|
|
201
|
+
// ponytail: fault-isolated — a throwing or empty source never takes down Signal
|
|
202
|
+
out.push({ content, width: visibleWidth(content) });
|
|
203
|
+
} catch {
|
|
204
|
+
// skip failing contribution
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
|
|
167
210
|
function styledSeparator(separator: string): string {
|
|
168
211
|
const color = getFgAnsiCode("sep");
|
|
169
212
|
const reset = colorEnabled() ? ansi.reset : "";
|