saterminal 0.3.2 → 0.5.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.
Files changed (83) hide show
  1. package/README.md +168 -4
  2. package/data/question-bank.json.zst +0 -0
  3. package/package.json +16 -10
  4. package/src/cli/commands/_app.tsx +10 -0
  5. package/src/cli/commands/config/index.tsx +21 -0
  6. package/src/cli/commands/config/reset.tsx +12 -0
  7. package/src/cli/commands/config/set.tsx +34 -0
  8. package/src/cli/commands/focus.tsx +12 -0
  9. package/src/cli/commands/history.tsx +21 -0
  10. package/src/cli/commands/index.tsx +7 -0
  11. package/src/cli/commands/review.tsx +7 -0
  12. package/src/cli/commands/show.tsx +36 -0
  13. package/src/cli/commands/stats.tsx +15 -0
  14. package/src/cli/commands/weak.tsx +13 -0
  15. package/src/cli/components/command-action.tsx +23 -0
  16. package/src/cli/components/report.tsx +16 -0
  17. package/src/cli/index.ts +10 -0
  18. package/src/cli/report-options.ts +19 -0
  19. package/src/cli/reports/focus.ts +20 -0
  20. package/src/cli/reports/history.ts +21 -0
  21. package/src/cli/reports/question.ts +24 -0
  22. package/src/cli/reports/stats.ts +66 -0
  23. package/src/cli/reports/terminal-format.ts +28 -0
  24. package/src/cli/reports/weaknesses.ts +36 -0
  25. package/src/database/focus-repository.ts +26 -0
  26. package/src/database/index.ts +28 -0
  27. package/src/database/migrations.ts +100 -0
  28. package/src/database/progress-repository.ts +90 -0
  29. package/src/local-data/paths.ts +17 -0
  30. package/src/local-data/setup.ts +25 -0
  31. package/src/practice/answer-question.ts +25 -0
  32. package/src/practice/question-queue.ts +58 -0
  33. package/src/preferences/index.ts +131 -0
  34. package/src/preferences/preferences.schema.json +45 -0
  35. package/src/progress/activity.ts +55 -0
  36. package/src/progress/attempt.ts +70 -0
  37. package/src/progress/history.ts +34 -0
  38. package/src/progress/review-queue.ts +44 -0
  39. package/src/progress/statistics.ts +35 -0
  40. package/src/progress/weaknesses.ts +44 -0
  41. package/src/questions/focus.ts +77 -0
  42. package/src/questions/local-bank.ts +133 -0
  43. package/src/questions/practice-sat.ts +14 -0
  44. package/src/questions/question.ts +25 -0
  45. package/src/questions/taxonomy.ts +56 -0
  46. package/src/text/duration.ts +4 -0
  47. package/src/{text.ts → text/html.ts} +3 -119
  48. package/src/text/media.ts +16 -0
  49. package/src/text/rich-text.ts +37 -0
  50. package/src/text/wrap.ts +59 -0
  51. package/src/tui/app.tsx +243 -0
  52. package/src/tui/components/chrome.tsx +39 -0
  53. package/src/tui/components/question-content.tsx +91 -0
  54. package/src/tui/hooks/use-terminal-size.ts +16 -0
  55. package/src/tui/screens/detail.tsx +20 -0
  56. package/src/tui/screens/focus.tsx +244 -0
  57. package/src/tui/screens/history.tsx +33 -0
  58. package/src/tui/screens/practice.tsx +159 -0
  59. package/src/tui/screens/result.tsx +169 -0
  60. package/src/tui/screens/setup.tsx +17 -0
  61. package/src/tui/screens/summary.tsx +16 -0
  62. package/src/api.ts +0 -113
  63. package/src/cli.ts +0 -917
  64. package/src/focus.ts +0 -231
  65. package/src/main.ts +0 -13
  66. package/src/progress.ts +0 -48
  67. package/src/state.ts +0 -346
  68. package/src/tui/app.ts +0 -134
  69. package/src/tui/focus-grid.ts +0 -113
  70. package/src/tui/frame.ts +0 -210
  71. package/src/tui/history.ts +0 -6
  72. package/src/tui/input.ts +0 -442
  73. package/src/tui/kit.ts +0 -9
  74. package/src/tui/layout.ts +0 -25
  75. package/src/tui/pane-content.ts +0 -150
  76. package/src/tui/question.ts +0 -46
  77. package/src/tui/render.ts +0 -627
  78. package/src/tui/timer.ts +0 -43
  79. package/src/tui/types.ts +0 -51
  80. package/src/tui/viewport.ts +0 -60
  81. package/src/tui.ts +0 -1
  82. package/src/types/terminal-kit.d.ts +0 -121
  83. package/src/types.ts +0 -69
package/src/tui/types.ts DELETED
@@ -1,51 +0,0 @@
1
- import type { Attempt, Focus, PracticeQuestion } from "../types.ts";
2
- import type { TextSegment } from "../text.ts";
3
- import type { PaneId } from "./viewport.ts";
4
-
5
- export type View = "setup" | "focus" | "loading" | "practice" | "review" | "history" | "summary" | "detail" | "error";
6
-
7
- export type AppState = {
8
- attempts: Map<string, Attempt>;
9
- skippedIds: Set<string>;
10
- nextQuestion?: Promise<PracticeQuestion | undefined>;
11
- reviewMode?: boolean;
12
- reviewQuestionIds?: string[];
13
- focus: Focus;
14
- focusIndex: number;
15
- focusColumn: number;
16
- focusRow: number;
17
- view: View;
18
- question?: PracticeQuestion;
19
- selected: number;
20
- questionScroll: number;
21
- answerScroll: number;
22
- activePane: PaneId;
23
- elapsedMs: number;
24
- timerStartedAt?: number;
25
- timerPaused: boolean;
26
- timerHidden: boolean;
27
- lastAnswer?: string;
28
- lastCorrect?: boolean;
29
- detailQuestion?: PracticeQuestion;
30
- historyIndex: number;
31
- notice?: string;
32
- error?: string;
33
- };
34
-
35
- export type KeyData = {
36
- code?: string | Buffer | number;
37
- codepoint?: number;
38
- isCharacter?: boolean;
39
- };
40
-
41
- export type DisplayRow = {
42
- segments: TextSegment[];
43
- bold?: boolean;
44
- };
45
-
46
- export type PaneLayout = {
47
- leftX: number;
48
- leftWidth: number;
49
- rightX: number;
50
- rightWidth: number;
51
- };
@@ -1,60 +0,0 @@
1
- export type PaneId = "question" | "answers";
2
-
3
- export type PaneViewport = {
4
- scroll: number;
5
- height: number;
6
- contentRows: number;
7
- };
8
-
9
- export function alternatePane(pane: PaneId): PaneId {
10
- return pane === "question" ? "answers" : "question";
11
- }
12
-
13
- export function maxScroll(viewport: PaneViewport): number {
14
- return Math.max(0, viewport.contentRows - viewport.height);
15
- }
16
-
17
- export function clampScroll(viewport: PaneViewport): number {
18
- return Math.max(0, Math.min(viewport.scroll, maxScroll(viewport)));
19
- }
20
-
21
- export function scrollBy(viewport: PaneViewport, delta: number): number {
22
- return clampScroll({ ...viewport, scroll: viewport.scroll + delta });
23
- }
24
-
25
- export function scrollPage(viewport: PaneViewport, direction: 1 | -1): number {
26
- return scrollBy(viewport, direction * Math.max(1, viewport.height - 1));
27
- }
28
-
29
- export function scrollToEdge(viewport: PaneViewport, edge: "top" | "bottom"): number {
30
- return edge === "top" ? 0 : maxScroll(viewport);
31
- }
32
-
33
- export function ensureRowVisible(viewport: PaneViewport, row: number): number {
34
- const scroll = clampScroll(viewport);
35
- if (row < scroll) {
36
- return clampScroll({ ...viewport, scroll: row });
37
- }
38
-
39
- const lastVisible = scroll + viewport.height - 1;
40
- if (row > lastVisible) {
41
- return clampScroll({ ...viewport, scroll: row - viewport.height + 1 });
42
- }
43
-
44
- return scroll;
45
- }
46
-
47
- export function ensureRangeVisible(viewport: PaneViewport, start: number, end: number): number {
48
- const scroll = clampScroll(viewport);
49
- const lastVisible = scroll + viewport.height - 1;
50
-
51
- if (start < scroll) {
52
- return clampScroll({ ...viewport, scroll: start });
53
- }
54
-
55
- if (end > lastVisible) {
56
- return clampScroll({ ...viewport, scroll: end - viewport.height + 1 });
57
- }
58
-
59
- return scroll;
60
- }
package/src/tui.ts DELETED
@@ -1 +0,0 @@
1
- export { runTui } from "./tui/app.ts";
@@ -1,121 +0,0 @@
1
- declare module "terminal-kit" {
2
- type KeyData = {
3
- code?: string | Buffer | number;
4
- codepoint?: number;
5
- isCharacter?: boolean;
6
- };
7
-
8
- export type Terminal = {
9
- width: number;
10
- height: number;
11
- clear(): Terminal;
12
- moveTo(x: number, y: number): Terminal;
13
- bold: Terminal & Record<string, Terminal>;
14
- gray: Terminal;
15
- cyan: Terminal;
16
- green: Terminal;
17
- red: Terminal;
18
- yellow: Terminal;
19
- underline: Terminal;
20
- inverse: Terminal;
21
- defaultColor: Terminal;
22
- italic: Terminal;
23
- styleReset(): Terminal;
24
- eraseLineAfter(): Terminal;
25
- fullscreen(enabled: boolean): void;
26
- hideCursor(enabled?: boolean): void;
27
- grabInput(enabled?: boolean): void;
28
- processExit(code: number): void;
29
- on(event: "key", listener: (name: string, matches?: string[], data?: KeyData) => void): void;
30
- on(event: "resize", listener: (width: number, height: number) => void): void;
31
- off(event: "resize", listener: (width: number, height: number) => void): void;
32
- (value: string): void;
33
- };
34
-
35
- export type DocumentOptions = {
36
- inlineTerm?: Terminal;
37
- eventSource?: Terminal;
38
- outputDst?: Terminal;
39
- outputX?: number;
40
- outputY?: number;
41
- outputWidth?: number;
42
- outputHeight?: number;
43
- backgroundAttr?: Record<string, unknown>;
44
- noInput?: boolean;
45
- };
46
-
47
- export type MenuItem = {
48
- content: string;
49
- value: string;
50
- disabled?: boolean;
51
- };
52
-
53
- export type ColumnMenuMultiOptions = {
54
- parent?: unknown;
55
- id?: string;
56
- x?: number;
57
- y?: number;
58
- width?: number;
59
- items?: MenuItem[];
60
- value?: Record<string, boolean>;
61
- multiLineItems?: boolean;
62
- master?: MenuItem;
63
- };
64
-
65
- export type WindowOptions = {
66
- parent?: unknown;
67
- title?: string;
68
- x?: number;
69
- y?: number;
70
- width?: number;
71
- height?: number;
72
- };
73
-
74
- export type TextOptions = {
75
- parent?: unknown;
76
- content?: string | string[];
77
- x?: number;
78
- y?: number;
79
- width?: number;
80
- height?: number;
81
- attr?: Record<string, unknown>;
82
- contentHasMarkup?: boolean | "ansi" | "legacyAnsi";
83
- noDraw?: boolean;
84
- };
85
-
86
- export class Document {
87
- constructor(options: DocumentOptions);
88
- clear(): void;
89
- draw(): void;
90
- destroy(): void;
91
- focusNext(): void;
92
- giveFocusTo(element: unknown, type?: string): void;
93
- on(event: "key", listener: (key: string) => void): void;
94
- }
95
-
96
- export class ColumnMenuMulti {
97
- constructor(options: ColumnMenuMultiOptions);
98
- value: Record<string, boolean>;
99
- setValue(value: Record<string, boolean>, noDraw?: boolean): void;
100
- on(event: "itemToggle", listener: (key: string, enabled: boolean) => void): void;
101
- on(event: "submit", listener: (...args: unknown[]) => void): void;
102
- }
103
-
104
- export class Window {
105
- constructor(options: WindowOptions);
106
- }
107
-
108
- export class Text {
109
- constructor(options: TextOptions);
110
- }
111
-
112
- const terminalKit: {
113
- terminal: Terminal;
114
- Document: typeof Document;
115
- ColumnMenuMulti: typeof ColumnMenuMulti;
116
- Window: typeof Window;
117
- Text: typeof Text;
118
- };
119
-
120
- export default terminalKit;
121
- }
package/src/types.ts DELETED
@@ -1,69 +0,0 @@
1
- export type Outcome = "correct" | "incorrect" | "corrected";
2
-
3
- export type Attempt = {
4
- question_id: string;
5
- outcome: Outcome;
6
- updated_at: string;
7
- elapsed_seconds: number;
8
- difficulty?: string;
9
- domain?: string;
10
- domain_desc?: string;
11
- skill?: string;
12
- skill_desc?: string;
13
- };
14
-
15
- export type AttemptEvent = {
16
- question_id: string;
17
- correct: boolean;
18
- answered_at: string;
19
- elapsed_seconds: number;
20
- difficulty: string;
21
- domain: string;
22
- domain_desc?: string;
23
- skill: string;
24
- skill_desc?: string;
25
- };
26
-
27
- export type SummaryRow = {
28
- metric: string;
29
- value: string;
30
- updated_at: string;
31
- };
32
-
33
- export type Difficulty = "E" | "M" | "H";
34
- export type Domain = "INI" | "CAS" | "EOI" | "SEC";
35
- export type Skill = "CID" | "INF" | "COE" | "WIC" | "TSP" | "CTC" | "SYN" | "TRA" | "BOU" | "FSS";
36
-
37
- export type Focus = {
38
- difficulties: Difficulty[];
39
- domains: Domain[];
40
- skills: Skill[];
41
- };
42
-
43
- export type QuestionMeta = {
44
- questionId: string;
45
- uId: string;
46
- external_id: string;
47
- difficulty: string;
48
- primary_class_cd: string;
49
- primary_class_cd_desc?: string;
50
- program?: string;
51
- skill_cd: string;
52
- skill_desc?: string;
53
- score_band_range_cd?: number;
54
- };
55
-
56
- export type QuestionDetail = {
57
- externalid: string;
58
- type: string;
59
- stimulus?: string;
60
- stem: string;
61
- answerOptions: Record<string, string>;
62
- correct_answer: string[];
63
- rationale?: string;
64
- };
65
-
66
- export type PracticeQuestion = {
67
- meta: QuestionMeta;
68
- detail: QuestionDetail;
69
- };