@litfamily/litopencode 1.0.36 → 1.0.38

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README-Ko-KR.md +6 -6
  3. package/README.md +6 -6
  4. package/dist/state.d.ts +1 -0
  5. package/dist/state.js +1 -0
  6. package/dist/tools.d.ts +15 -5
  7. package/dist/tui/mission-band.d.ts +7 -0
  8. package/dist/tui/mission-band.js +4 -0
  9. package/dist/tui/mission-skills.js +3 -1
  10. package/dist/tui/mission-source-v2.d.ts +23 -0
  11. package/dist/tui/mission-source-v2.js +29 -4
  12. package/dist/tui/mission-source.d.ts +1 -0
  13. package/dist/tui/mission-source.js +3 -2
  14. package/dist/tui/mission-text.d.ts +3 -3
  15. package/dist/tui/mission-text.js +5 -5
  16. package/dist/v2/events.d.ts +1 -1
  17. package/dist/v2/events.js +31 -5
  18. package/dist/v2/notices.d.ts +13 -0
  19. package/dist/v2/notices.js +143 -0
  20. package/dist/v2/tui-footer.d.ts +20 -0
  21. package/dist/v2/tui-footer.js +56 -0
  22. package/dist/v2/tui-notices.d.ts +7 -0
  23. package/dist/v2/tui-notices.js +45 -0
  24. package/dist/v2/tui.d.ts +43 -1
  25. package/dist/v2/tui.js +345 -32
  26. package/dist/v2/usage-limits.d.ts +19 -0
  27. package/dist/v2/usage-limits.js +70 -0
  28. package/docs/assets/readme/badge-version.svg +1 -1
  29. package/docs/reference-Ko-KR.md +24 -5
  30. package/docs/reference.md +29 -7
  31. package/package.json +6 -2
  32. package/skills/lit-typographic-motion/engine/cover/render.mjs +1 -1
  33. package/skills/lit-typographic-motion/engine/stage/capture.mjs +3 -2
  34. package/skills/lit-typographic-motion/engine/stage/gate.mjs +1 -0
  35. package/skills/lit-typographic-motion/engine/stage/render.mjs +1 -0
  36. package/skills/lit-typographic-motion/engine/stage/scan.mjs +109 -5
  37. package/skills/lit-typographic-motion/engine/stage/stage-kit.js +39 -1
  38. package/skills/lit-typographic-motion/references/cover.md +2 -1
  39. package/skills/lit-typographic-motion/references/runtime.md +1 -1
  40. package/skills/lit-typographic-motion/references/stage.md +48 -2
  41. package/skills/lit-typographic-motion/requirements-audio.txt +92 -89
  42. package/skills/managed-skill-manifest.json +13 -13
  43. package/skills/readme-studio/templates/hyperframes/package-lock.json +4 -4
  44. package/skills/readme-studio/templates/remotion/package-lock.json +3 -3
  45. package/skills/readme-studio/templates/remotion/package.json +1 -1
@@ -0,0 +1,20 @@
1
+ import type { MissionView } from "../tui/mission-model.ts";
2
+ import type { MotionFrame } from "../tui/mission-motion.ts";
3
+ import { type Line, type MissionPalette } from "../tui/mission-text.ts";
4
+ /** The session sidebar, which a wide terminal is taken to have open (the setting is not readable by a plugin). */
5
+ export declare const sidebarCells = 42;
6
+ export declare function footerBudget(input: {
7
+ readonly columns: number;
8
+ readonly sidebar: boolean;
9
+ readonly busy: boolean;
10
+ }): number;
11
+ export type FooterInput = {
12
+ /** The discipline the latest lit prompt started, as the server wrote it into the message. */
13
+ readonly name: string;
14
+ readonly view: MissionView | undefined;
15
+ readonly frame: MotionFrame;
16
+ readonly palette: MissionPalette;
17
+ readonly budget: number;
18
+ };
19
+ /** The footer line for `budget` cells, as segments; empty when not even the flame fits. */
20
+ export declare function footerStatus(input: FooterInput): Line;
@@ -0,0 +1,56 @@
1
+ // What OpenCode 2's prompt footer row holds besides our line, and how our line steps down to the room left.
2
+ // The row is the host's spinner and `esc interrupt` hint on the left and its token, goal and `ctrl+p commands`
3
+ // figures on the right; our line is squeezed between them, and the host clips it mid-word when it is too long.
4
+ // So the line is chosen by width: the ignition mark with the whole stage chip, the chip at a smaller size,
5
+ // the chip as `🔥 1/3`, the bare flame, then nothing. The numbers were measured on opencode2 2.2.5.
6
+ import { activationDiscipline } from "../activation-probe.js";
7
+ import { cellWidth, chipLine, lineWidth } from "../tui/mission-text.js";
8
+ /** The session sidebar, which a wide terminal is taken to have open (the setting is not readable by a plugin). */
9
+ export const sidebarCells = 42;
10
+ // Right of our line: with a turn running `↓ 1 shell · ◎ goal ctrl+p commands`, idle `◎ goal paused · 42.3K (8%) · $0.07 ctrl+p commands`.
11
+ const hostRightBusy = 38;
12
+ const hostRightIdle = 54;
13
+ // Left of it, the least the host keeps: the spinner and a shortened `esc …rrupt` while running, a shortened path when idle.
14
+ const hostLeftBusy = 24;
15
+ const hostLeftIdle = 6;
16
+ const gap = 2;
17
+ export function footerBudget(input) {
18
+ const main = input.columns - (input.sidebar ? sidebarCells : 0);
19
+ const host = input.busy ? hostRightBusy + hostLeftBusy : hostRightIdle + hostLeftIdle;
20
+ return Math.max(0, main - host);
21
+ }
22
+ const flameWidth = 2;
23
+ /** The footer line for `budget` cells, as segments; empty when not even the flame fits. */
24
+ export function footerStatus(input) {
25
+ const { palette, budget } = input;
26
+ const discipline = activationDiscipline(input.name);
27
+ const mark = (text) => [{ text, fg: palette.primary, bold: true }];
28
+ const full = `🔥 LIT IGNITED · ${discipline}`;
29
+ const active = input.view !== undefined && input.view.active;
30
+ const chipFor = (room, largest) => {
31
+ if (!active || input.view === undefined || room < flameWidth)
32
+ return [];
33
+ const chip = chipLine(input.view, input.frame, palette, room, largest);
34
+ return lineWidth(chip) <= room ? chip : [];
35
+ };
36
+ if (!active) {
37
+ if (cellWidth(full) <= budget)
38
+ return mark(full);
39
+ }
40
+ else {
41
+ const beside = chipFor(budget - cellWidth(full) - gap, "full");
42
+ if (beside.length > 0)
43
+ return [...mark(full), { text: " ".repeat(gap), fg: palette.muted }, ...beside];
44
+ // The chip is worth more than the mark's words, so it stays alone when both do not fit. Alone it never
45
+ // grows past the middle size, so the line only gets smaller as the room does.
46
+ const alone = chipFor(budget, "medium");
47
+ if (alone.length > 0)
48
+ return alone;
49
+ }
50
+ const short = `🔥 ${discipline}`;
51
+ if (cellWidth(short) <= budget)
52
+ return mark(short);
53
+ if (budget >= flameWidth)
54
+ return mark("🔥");
55
+ return [];
56
+ }
@@ -0,0 +1,7 @@
1
+ import { type MissionNotice, type MissionView } from "../tui/mission-model.ts";
2
+ import type { ThreadRow } from "../tui/mission-threads.ts";
3
+ /**
4
+ * Stage, discipline and lane changes between two views. A first view never toasts its history. A lane
5
+ * counts as started when its key is new and working, and as finished when a working lane is gone or done.
6
+ */
7
+ export declare function v2StageNotices(prev: MissionView | undefined, next: MissionView, before: readonly ThreadRow[], after: readonly ThreadRow[]): readonly MissionNotice[];
@@ -0,0 +1,45 @@
1
+ // The toasts OpenCode 2 raises beyond the shared gate events (plan saved, goal set, criterion passed,
2
+ // blockers, complete): the workflow stage moving, a discipline switching, a lane starting or finishing.
3
+ // They are pure: the TUI hands in the previous and next view and thread rows and gets notices back,
4
+ // which leadingNotice folds into one toast with a `+N more` tail.
5
+ import { stepName } from "../tui/mission-model.js";
6
+ const maxNamed = 1;
7
+ function runningStage(view) {
8
+ const step = view.steps.find((candidate) => candidate.state === "now");
9
+ if (step === undefined)
10
+ return undefined;
11
+ const count = view.progress !== undefined && view.progress.total > 0 ? ` ${view.progress.done}/${view.progress.total}` : "";
12
+ return { id: `${view.family}:${step.id}`, label: `${stepName(step.id, view)}${count}` };
13
+ }
14
+ function laneNotice(rows, verb) {
15
+ if (rows.length === 0)
16
+ return undefined;
17
+ const message = rows.length > maxNamed ? `${rows.length} lanes ${verb}` : `lane ${verb} · ${rows[0].name}`;
18
+ return { variant: "info", title: "🔥 Lane", message };
19
+ }
20
+ /**
21
+ * Stage, discipline and lane changes between two views. A first view never toasts its history. A lane
22
+ * counts as started when its key is new and working, and as finished when a working lane is gone or done.
23
+ */
24
+ export function v2StageNotices(prev, next, before, after) {
25
+ if (prev === undefined || !next.active)
26
+ return [];
27
+ const notices = [];
28
+ if (prev.active && prev.discipline !== next.discipline && next.discipline !== "") {
29
+ notices.push({ variant: "info", title: `🔥 ${prev.discipline} → ${next.discipline}`, message: "Discipline switched." });
30
+ }
31
+ else if (prev.active && !next.complete) {
32
+ const was = runningStage(prev);
33
+ const now = runningStage(next);
34
+ if (was !== undefined && now !== undefined && was.id !== now.id)
35
+ notices.push({ variant: "info", title: "🔥 Stage", message: now.label });
36
+ }
37
+ const priorKeys = new Set(before.map((row) => row.key));
38
+ const nextByKey = new Map(after.map((row) => [row.key, row]));
39
+ const started = after.filter((row) => row.status === "working" && !priorKeys.has(row.key));
40
+ const finished = before.filter((row) => row.status === "working" && (nextByKey.get(row.key) === undefined || nextByKey.get(row.key)?.status === "done"));
41
+ for (const notice of [laneNotice(started, "started"), laneNotice(finished, "finished")])
42
+ if (notice !== undefined)
43
+ notices.push(notice);
44
+ return notices;
45
+ }
package/dist/v2/tui.d.ts CHANGED
@@ -5,6 +5,11 @@ export type TuiRuntime = {
5
5
  readonly createSignal: <T>(value: T) => readonly [() => T, (value: T) => T];
6
6
  readonly createEffect: (fn: () => void) => void;
7
7
  readonly createRoot: <T>(fn: (dispose: () => void) => T) => T;
8
+ /** The host's terminal size, reactive; a stand-in runtime may leave it out. */
9
+ readonly useTerminalDimensions?: () => () => {
10
+ readonly width: number;
11
+ readonly height: number;
12
+ };
8
13
  };
9
14
  type PromptFooterInput = {
10
15
  readonly sessionID?: string;
@@ -19,15 +24,44 @@ export type SlotClaimLike = {
19
24
  } | {
20
25
  readonly append: "prompt.footer.status";
21
26
  readonly render: (input: PromptFooterInput) => unknown;
27
+ } | {
28
+ readonly append: "app";
29
+ readonly render: (input: Record<string, never>) => unknown;
30
+ } | {
31
+ readonly append: "home.footer";
32
+ readonly render: (input: Record<string, never>) => unknown;
22
33
  };
23
34
  export type TuiContextLike = {
35
+ readonly options?: unknown;
24
36
  readonly location: {
25
37
  readonly directory: string;
26
38
  } | undefined;
27
39
  readonly theme: unknown;
28
40
  readonly themeMode: "dark" | "light";
41
+ /** The host's API client; only `usage.limits` is read, and a host without it simply shows no plan figures. */
42
+ readonly client?: {
43
+ readonly usage?: {
44
+ readonly limits?: () => Promise<unknown>;
45
+ };
46
+ };
47
+ readonly attention?: {
48
+ readonly notify: (options: {
49
+ readonly title?: string;
50
+ readonly message: string;
51
+ readonly notification?: boolean;
52
+ readonly sound?: boolean | {
53
+ readonly name?: "done";
54
+ };
55
+ }) => Promise<unknown>;
56
+ };
29
57
  readonly ui: {
30
58
  readonly slot: (claim: SlotClaimLike) => () => void;
59
+ readonly router?: {
60
+ current(): {
61
+ readonly type: string;
62
+ readonly sessionID?: string;
63
+ };
64
+ };
31
65
  readonly toast: {
32
66
  readonly show: (options: {
33
67
  readonly title?: string;
@@ -49,11 +83,19 @@ export type TuiContextLike = {
49
83
  readonly type: string;
50
84
  };
51
85
  }) => void) => () => void;
52
- readonly location: {
86
+ readonly location: MissionDataV2["location"] & {
53
87
  default(): {
54
88
  readonly directory: string;
55
89
  };
56
90
  };
91
+ readonly session: MissionDataV2["session"] & {
92
+ get?(sessionID: string): {
93
+ readonly parentID?: string;
94
+ readonly time?: {
95
+ readonly created?: number;
96
+ };
97
+ } | undefined;
98
+ };
57
99
  };
58
100
  };
59
101
  /** OpenCode 2 theme tokens under the names the mission palette reads. */