soja-cli 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.
Files changed (189) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +117 -0
  3. package/dist/application/chat.js +1 -0
  4. package/dist/application/filters.js +27 -0
  5. package/dist/application/import.js +1 -0
  6. package/dist/application/ports.js +1 -0
  7. package/dist/application/repository-root.js +18 -0
  8. package/dist/application/services/backup-service.js +93 -0
  9. package/dist/application/services/folder-service.js +116 -0
  10. package/dist/application/services/git-workflow-service.js +593 -0
  11. package/dist/application/services/index.js +24 -0
  12. package/dist/application/services/project-service.js +129 -0
  13. package/dist/application/services/session-service.js +52 -0
  14. package/dist/application/services/task-service.js +350 -0
  15. package/dist/application/services/update-service.js +60 -0
  16. package/dist/application/services/workspace-service.js +81 -0
  17. package/dist/application/timeline.js +83 -0
  18. package/dist/application/types.js +1 -0
  19. package/dist/application/validation.js +30 -0
  20. package/dist/bootstrap.js +91 -0
  21. package/dist/cli/commands/access.js +60 -0
  22. package/dist/cli/commands/account.js +203 -0
  23. package/dist/cli/commands/args.js +27 -0
  24. package/dist/cli/commands/backup.js +70 -0
  25. package/dist/cli/commands/chat.js +133 -0
  26. package/dist/cli/commands/dev.js +59 -0
  27. package/dist/cli/commands/folders.js +59 -0
  28. package/dist/cli/commands/git-ops.js +200 -0
  29. package/dist/cli/commands/import.js +48 -0
  30. package/dist/cli/commands/info.js +82 -0
  31. package/dist/cli/commands/project.js +108 -0
  32. package/dist/cli/commands/start.js +34 -0
  33. package/dist/cli/commands/sync.js +43 -0
  34. package/dist/cli/commands/task.js +309 -0
  35. package/dist/cli/commands/tui.js +43 -0
  36. package/dist/cli/commands/update.js +20 -0
  37. package/dist/cli/commands/workspace.js +55 -0
  38. package/dist/cli/index.js +103 -0
  39. package/dist/cli/output.js +56 -0
  40. package/dist/cli/prompt.js +28 -0
  41. package/dist/cli/runtime.js +43 -0
  42. package/dist/config/config.js +103 -0
  43. package/dist/config/credentials.js +68 -0
  44. package/dist/config/paths.js +18 -0
  45. package/dist/config/server.js +21 -0
  46. package/dist/config/version.js +7 -0
  47. package/dist/data/local/activity.js +33 -0
  48. package/dist/data/local/clock.js +1 -0
  49. package/dist/data/local/comments.js +27 -0
  50. package/dist/data/local/index.js +48 -0
  51. package/dist/data/local/projects.js +53 -0
  52. package/dist/data/local/tasks.js +104 -0
  53. package/dist/data/local/users.js +38 -0
  54. package/dist/data/local/workspaces.js +55 -0
  55. package/dist/data/remote/api-client.js +103 -0
  56. package/dist/data/remote/live.js +93 -0
  57. package/dist/data/repositories.js +1 -0
  58. package/dist/data/sync/chat.js +242 -0
  59. package/dist/data/sync/engine.js +459 -0
  60. package/dist/data/sync/importer.js +156 -0
  61. package/dist/data/sync/index.js +109 -0
  62. package/dist/data/sync/services.js +263 -0
  63. package/dist/data/sync/store.js +200 -0
  64. package/dist/database/client.js +76 -0
  65. package/dist/database/migrate.js +27 -0
  66. package/dist/database/migrations/0000_init.sql +100 -0
  67. package/dist/database/migrations/0001_git-operations.sql +19 -0
  68. package/dist/database/migrations/0002_merge-detection.sql +19 -0
  69. package/dist/database/migrations/0003_sync-replica.sql +40 -0
  70. package/dist/database/migrations/0004_chat-replica.sql +52 -0
  71. package/dist/database/migrations/0005_pr-events.sql +18 -0
  72. package/dist/database/migrations/0006_archive.sql +20 -0
  73. package/dist/database/migrations/meta/0000_snapshot.json +710 -0
  74. package/dist/database/migrations/meta/0001_snapshot.json +717 -0
  75. package/dist/database/migrations/meta/0002_snapshot.json +724 -0
  76. package/dist/database/migrations/meta/0003_snapshot.json +972 -0
  77. package/dist/database/migrations/meta/0004_snapshot.json +1168 -0
  78. package/dist/database/migrations/meta/0005_snapshot.json +1168 -0
  79. package/dist/database/migrations/meta/0006_snapshot.json +1183 -0
  80. package/dist/database/migrations/meta/_journal.json +55 -0
  81. package/dist/database/schema.js +170 -0
  82. package/dist/dev/seed.js +84 -0
  83. package/dist/domain/activity.js +22 -0
  84. package/dist/domain/chat.js +21 -0
  85. package/dist/domain/entities.js +1 -0
  86. package/dist/domain/errors.js +23 -0
  87. package/dist/domain/naming.js +33 -0
  88. package/dist/domain/task.js +140 -0
  89. package/dist/domain/workflow.js +23 -0
  90. package/dist/git/cli-git.js +363 -0
  91. package/dist/git/console.js +37 -0
  92. package/dist/git/diagnose.js +145 -0
  93. package/dist/git/merge-evidence.js +23 -0
  94. package/dist/git/releases.js +95 -0
  95. package/dist/git/types.js +16 -0
  96. package/dist/ui/App.js +71 -0
  97. package/dist/ui/Shell.js +211 -0
  98. package/dist/ui/app-state.js +213 -0
  99. package/dist/ui/branding/CompactLogo.js +8 -0
  100. package/dist/ui/branding/Logo.js +22 -0
  101. package/dist/ui/branding/Splash.js +21 -0
  102. package/dist/ui/branding/brand.js +23 -0
  103. package/dist/ui/chrome/Sidebar.js +50 -0
  104. package/dist/ui/chrome/StatusBar.js +26 -0
  105. package/dist/ui/chrome/Toast.js +11 -0
  106. package/dist/ui/chrome/TopBar.js +10 -0
  107. package/dist/ui/chrome/context.js +33 -0
  108. package/dist/ui/components/ConsoleLines.js +16 -0
  109. package/dist/ui/components/EmptyState.js +8 -0
  110. package/dist/ui/components/Labels.js +25 -0
  111. package/dist/ui/components/PullRequestLabel.js +27 -0
  112. package/dist/ui/components/TaskTable.js +41 -0
  113. package/dist/ui/components/TextField.js +11 -0
  114. package/dist/ui/components/TextInput.js +29 -0
  115. package/dist/ui/components/task-columns.js +27 -0
  116. package/dist/ui/copy.js +23 -0
  117. package/dist/ui/hooks/use-commands.js +58 -0
  118. package/dist/ui/hooks/use-flows.js +254 -0
  119. package/dist/ui/hooks/use-layout.js +36 -0
  120. package/dist/ui/hooks/use-list.js +28 -0
  121. package/dist/ui/hooks/use-measure.js +22 -0
  122. package/dist/ui/hooks/use-query.js +29 -0
  123. package/dist/ui/hooks/use-task-actions.js +450 -0
  124. package/dist/ui/hooks/use-terminal-size.js +19 -0
  125. package/dist/ui/input/KeyProvider.js +101 -0
  126. package/dist/ui/input/dispatcher.js +26 -0
  127. package/dist/ui/input/list-navigation.js +38 -0
  128. package/dist/ui/input/mouse.js +78 -0
  129. package/dist/ui/input/text-editing.js +62 -0
  130. package/dist/ui/kit/Badge.js +8 -0
  131. package/dist/ui/kit/Button.js +13 -0
  132. package/dist/ui/kit/Clickable.js +14 -0
  133. package/dist/ui/kit/Gauge.js +9 -0
  134. package/dist/ui/kit/Keycap.js +7 -0
  135. package/dist/ui/kit/Panel.js +30 -0
  136. package/dist/ui/kit/ScrollBar.js +14 -0
  137. package/dist/ui/kit/Spinner.js +9 -0
  138. package/dist/ui/kit/Tabs.js +12 -0
  139. package/dist/ui/mascot/AgentScene.js +30 -0
  140. package/dist/ui/mascot/Mascot.js +26 -0
  141. package/dist/ui/mascot/ansi.js +25 -0
  142. package/dist/ui/mascot/engine.js +146 -0
  143. package/dist/ui/mascot/index.js +6 -0
  144. package/dist/ui/mascot/palette.js +18 -0
  145. package/dist/ui/mascot/scenes/bugHunt.js +115 -0
  146. package/dist/ui/mascot/scenes/celebrate.js +76 -0
  147. package/dist/ui/mascot/scenes/cleaning.js +156 -0
  148. package/dist/ui/mascot/scenes/clockIn.js +105 -0
  149. package/dist/ui/mascot/scenes/deadline.js +125 -0
  150. package/dist/ui/mascot/scenes/empty.js +149 -0
  151. package/dist/ui/mascot/scenes/fire.js +138 -0
  152. package/dist/ui/mascot/scenes/index.js +25 -0
  153. package/dist/ui/mascot/scenes/planning.js +73 -0
  154. package/dist/ui/mascot/scenes/resting.js +90 -0
  155. package/dist/ui/mascot/scenes/syncing.js +116 -0
  156. package/dist/ui/mascot/scenes/working.js +193 -0
  157. package/dist/ui/mascot/selection.js +32 -0
  158. package/dist/ui/mascot/states.js +25 -0
  159. package/dist/ui/navigation/routes.js +17 -0
  160. package/dist/ui/overlays/CommitOverlay.js +93 -0
  161. package/dist/ui/overlays/ConfirmOverlay.js +42 -0
  162. package/dist/ui/overlays/GitLogOverlay.js +22 -0
  163. package/dist/ui/overlays/GitRunOverlay.js +94 -0
  164. package/dist/ui/overlays/NewTaskOverlay.js +117 -0
  165. package/dist/ui/overlays/OverlayFrame.js +35 -0
  166. package/dist/ui/overlays/PickerOverlay.js +72 -0
  167. package/dist/ui/overlays/PromptOverlay.js +51 -0
  168. package/dist/ui/overlays/SearchOverlay.js +49 -0
  169. package/dist/ui/overlays/options.js +29 -0
  170. package/dist/ui/overlays/types.js +1 -0
  171. package/dist/ui/screens/AccessScreen.js +91 -0
  172. package/dist/ui/screens/ChatScreen.js +450 -0
  173. package/dist/ui/screens/HelpScreen.js +99 -0
  174. package/dist/ui/screens/ProjectsScreen.js +66 -0
  175. package/dist/ui/screens/ScreenFrame.js +14 -0
  176. package/dist/ui/screens/SetupScreen.js +79 -0
  177. package/dist/ui/screens/TaskListScreen.js +152 -0
  178. package/dist/ui/screens/TaskScreen.js +193 -0
  179. package/dist/ui/screens/WelcomeScreen.js +254 -0
  180. package/dist/ui/screens/WorkspacesScreen.js +64 -0
  181. package/dist/ui/theme/detect.js +59 -0
  182. package/dist/ui/theme/theme.js +135 -0
  183. package/dist/utils/editor.js +37 -0
  184. package/dist/utils/errors.js +23 -0
  185. package/dist/utils/text.js +60 -0
  186. package/dist/utils/time.js +25 -0
  187. package/docs/NPM_PUBLISH.md +35 -0
  188. package/docs/PRIVACY.md +38 -0
  189. package/package.json +74 -0
@@ -0,0 +1,125 @@
1
+ import { blink, drawGround, mirror, rng, soilLine, withFace } from '../engine.js';
2
+ const W = 78;
3
+ const H = 13;
4
+ const G = 11;
5
+ const RUN_A = [' .-. ', '(o.o)=', '( ) ', " / \\ "];
6
+ const RUN_B = [' .-. ', '(o.o)=', '( ) ', " |\\ "];
7
+ const TYPE_A = [' .-. ', '(o.o) ', '( )/'];
8
+ const TYPE_B = [' .-. ', '(o.o) ', '( )\\'];
9
+ export const deadline = {
10
+ id: 'deadline',
11
+ title: 'Contra reloj',
12
+ useFor: 'Tareas vencidas o por vencer',
13
+ width: W,
14
+ height: H,
15
+ create(seed = 10) {
16
+ const r = rng(seed);
17
+ const soil = [soilLine(W, r)];
18
+ const runners = [
19
+ { x: 24, v: 0.9, n: 1 },
20
+ { x: 50, v: -1.1, n: 2 },
21
+ { x: 66, v: -0.8, n: 3 },
22
+ ];
23
+ let t = 0;
24
+ let secs = 59;
25
+ let delivered = 0;
26
+ let doneT = 0;
27
+ let papers = [];
28
+ let sweat = [];
29
+ let taps = 0;
30
+ return {
31
+ step() {
32
+ t++;
33
+ if (doneT) {
34
+ doneT--;
35
+ if (!doneT)
36
+ secs = 59;
37
+ }
38
+ else {
39
+ if (t % 5 === 0)
40
+ secs--;
41
+ if (secs <= 0) {
42
+ secs = 0;
43
+ doneT = 30;
44
+ delivered++;
45
+ }
46
+ }
47
+ const speedUp = !doneT && secs < 15 ? 1.4 : 1;
48
+ for (const a of runners) {
49
+ if (doneT)
50
+ continue;
51
+ a.x += a.v * speedUp;
52
+ if (a.x < 22 || a.x > W - 7) {
53
+ a.v = -a.v;
54
+ a.x = Math.max(22, Math.min(W - 7, a.x));
55
+ if (r() < 0.6)
56
+ papers.push({ x: a.x + 3, y: G - 3, vx: (r() - 0.5) * 1.2, vy: -0.6, ch: '▭', tone: 'paper' });
57
+ }
58
+ if (t % 6 === a.n)
59
+ sweat.push({ x: a.x + (a.v > 0 ? 0 : 5), y: G - 4, vx: -Math.sign(a.v) * 0.4, vy: -0.3, ch: "'", tone: 'water' });
60
+ }
61
+ if (!doneT)
62
+ taps++;
63
+ for (const p of papers) {
64
+ p.x += p.vx;
65
+ p.y += p.vy;
66
+ p.vy += 0.06;
67
+ p.vx *= 0.97;
68
+ }
69
+ papers = papers.filter((p) => p.y < G);
70
+ for (const s of sweat) {
71
+ s.x += s.vx;
72
+ s.y += s.vy;
73
+ s.vy += 0.1;
74
+ }
75
+ sweat = sweat.filter((s) => s.y < G);
76
+ },
77
+ draw(c) {
78
+ drawGround(c, G, soil);
79
+ const urgent = !doneT && secs < 15;
80
+ const clockTone = doneT ? 'good' : urgent && t % 6 < 3 ? 'bad' : 'text';
81
+ c.put(29, 0, ' .--------------. ', 'rock');
82
+ c.put(29, 1, ' | | ', 'rock');
83
+ c.put(29, 2, " '--------------' ", 'rock');
84
+ c.put(doneT ? 33 : 34, 1, doneT ? 'entregado!' : `23:59:${String(secs).padStart(2, '0')}`, clockTone);
85
+ if (urgent) {
86
+ c.put(26, 1, '!!', 'bad');
87
+ c.put(49, 1, '!!', 'bad');
88
+ }
89
+ c.put(1, G - 3, '▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄', 'wood');
90
+ c.put(2, G - 2, '||', 'wood');
91
+ c.put(2, G - 1, '||', 'wood');
92
+ c.put(13, G - 2, '||', 'wood');
93
+ c.put(13, G - 1, '||', 'wood');
94
+ c.put(9, G - 6, '.----.', 'rock');
95
+ c.put(9, G - 5, '|' + (doneT ? ' ok ' : '#'.repeat(Math.floor(t / 2) % 5).padEnd(4, '_')) + '|', doneT ? 'good' : 'accent');
96
+ c.put(9, G - 4, "'----'", 'rock');
97
+ c.put(9, G - 5, '|', 'rock');
98
+ c.put(14, G - 5, '|', 'rock');
99
+ c.sprite(3, G - 6, withFace(taps % 2 ? TYPE_A : TYPE_B, doneT ? '^.^' : urgent ? '>.<' : 'O.O'), 'agent');
100
+ if (!doneT && t % 4 < 2)
101
+ c.put(7, G - 7, 'tap', 'cloud');
102
+ c.put(16, G - 4, '▭▭', 'paper');
103
+ c.put(16, G - 5, '▭', 'paper');
104
+ runners.forEach((a, i) => {
105
+ const face = doneT ? '^.^' : urgent ? '>.<' : blink(t, i, 'O.O');
106
+ let sp = doneT ? [' .-. ', '(o.o)', '( )', " ' ' "] : Math.floor(t / 2) % 2 ? RUN_A : RUN_B;
107
+ if (a.v < 0 && !doneT)
108
+ sp = mirror(sp);
109
+ c.sprite(a.x, G - 4, withFace(sp, face), 'agent');
110
+ if (!doneT)
111
+ c.put(a.v > 0 ? a.x + 6 : a.x - 1, G - 3, '▭', 'paper');
112
+ });
113
+ if (doneT && t % 8 < 5)
114
+ c.put(40, G - 6, '(lo logramos!)', 'good');
115
+ for (const p of papers)
116
+ c.put(p.x, p.y, p.ch, p.tone);
117
+ for (const s of sweat)
118
+ c.put(s.x, s.y, s.ch, s.tone);
119
+ },
120
+ status() {
121
+ return doneT ? `entregado a tiempo · ${delivered} entregas` : `vence en ${secs}s · ${delivered} entregas`;
122
+ },
123
+ };
124
+ },
125
+ };
@@ -0,0 +1,149 @@
1
+ /* eslint-disable prefer-const -- the bird list is mutated in place by the scene engine. */
2
+ import { blink, drawCloud, rng, soilLine, withFace } from '../engine.js';
3
+ const W = 78;
4
+ const H = 12;
5
+ const WATER_Y = 8;
6
+ const SHORE = 30;
7
+ const DOCK_L = 28;
8
+ const DOCK_R = 50;
9
+ const FISHER_X = 43;
10
+ const TREE = [' .--. ', ' ( ) ', '( ~ )', " '-..-' "];
11
+ const SIT_ROD = [' .-. ', '(o.o)/', '(___) '];
12
+ const SIT_PULL = [' .-. |', '(o.o)|', '(___) '];
13
+ export const empty = {
14
+ id: 'empty',
15
+ title: 'Pescando',
16
+ useFor: 'Lista vacía / sin tareas pendientes',
17
+ width: W,
18
+ height: H,
19
+ create(seed = 9) {
20
+ const r = rng(seed);
21
+ const soil = [soilLine(SHORE, r), soilLine(SHORE, r), soilLine(SHORE, r)];
22
+ let t = 0;
23
+ let fish = 0;
24
+ let boots = 0;
25
+ let phase = 'wait';
26
+ let k = 0;
27
+ let waitFor = 50;
28
+ let catchKind = 'fish';
29
+ let flying = null;
30
+ let happy = 0;
31
+ let zs = [];
32
+ let weed = -10;
33
+ let birds = [{ x: 70, y: 1 }];
34
+ return {
35
+ step() {
36
+ t++;
37
+ k++;
38
+ if (phase === 'wait' && k > waitFor) {
39
+ phase = 'bite';
40
+ k = 0;
41
+ }
42
+ else if (phase === 'bite' && k > 10) {
43
+ phase = 'pull';
44
+ k = 0;
45
+ catchKind = r() < 0.7 ? 'fish' : 'boot';
46
+ flying = { x: FISHER_X + 9, y: WATER_Y, vx: -0.9, vy: -0.9, ch: catchKind === 'fish' ? '><>' : '_|', tone: catchKind === 'fish' ? 'water' : 'wood' };
47
+ }
48
+ else if (phase === 'pull' && k > 14) {
49
+ phase = 'wait';
50
+ k = 0;
51
+ waitFor = 40 + Math.floor(r() * 50);
52
+ if (catchKind === 'fish')
53
+ fish++;
54
+ else
55
+ boots++;
56
+ happy = 16;
57
+ flying = null;
58
+ }
59
+ if (flying) {
60
+ flying.x += flying.vx;
61
+ flying.y += flying.vy;
62
+ flying.vy += 0.14;
63
+ if (flying.y > WATER_Y - 2)
64
+ flying.y = WATER_Y - 2;
65
+ }
66
+ if (happy)
67
+ happy--;
68
+ if (t % 16 === 0)
69
+ zs.push({ x: 8, y: WATER_Y - 3, l: 0 });
70
+ for (const z of zs) {
71
+ z.l++;
72
+ z.y -= 0.15;
73
+ z.x += 0.1;
74
+ }
75
+ zs = zs.filter((z) => z.l < 20);
76
+ weed += 0.4;
77
+ if (weed > SHORE + 6)
78
+ weed = -30 - r() * 40;
79
+ for (const b of birds) {
80
+ b.x -= 0.25;
81
+ if (b.x < -4) {
82
+ b.x = W + r() * 20;
83
+ b.y = 1 + Math.floor(r() * 3);
84
+ }
85
+ }
86
+ },
87
+ draw(c) {
88
+ drawCloud(c, t, 0.04, 30, 0);
89
+ for (let x = 0; x < SHORE; x++)
90
+ c.set(x, WATER_Y, '▀', 'soil');
91
+ soil.forEach((l, i) => c.put(0, WATER_Y + 1 + i, l, 'soil'));
92
+ for (let y = WATER_Y; y < H; y++) {
93
+ for (let x = SHORE; x < W; x++) {
94
+ const v = (x + y * 3 + Math.floor(t / 3)) % 7;
95
+ c.put(x, y, y === WATER_Y ? (v < 3 ? '~' : '-') : v === 0 ? '~' : ' ', 'water');
96
+ }
97
+ }
98
+ c.sprite(1, WATER_Y - 7, TREE, 'leaf');
99
+ c.put(4, WATER_Y - 3, '||', 'wood');
100
+ c.put(4, WATER_Y - 2, '||', 'wood');
101
+ c.put(4, WATER_Y - 1, '||', 'wood');
102
+ c.put(7, WATER_Y - 2, ' .-.____ ', 'agent');
103
+ c.put(7, WATER_Y - 1, '(-.-_____)', 'agent');
104
+ for (const z of zs)
105
+ c.put(z.x, z.y, z.l < 8 ? 'z' : 'Z', 'cloud');
106
+ if (weed > -3)
107
+ c.put(weed, WATER_Y - 1, '@', 'dirt');
108
+ for (let x = DOCK_L; x <= DOCK_R; x++)
109
+ c.put(x, WATER_Y - 1, '=', 'wood');
110
+ for (const px of [DOCK_L + 3, DOCK_R - 2])
111
+ for (let y = WATER_Y; y < H - 1; y++)
112
+ c.put(px, y, '|', 'wood');
113
+ c.put(FISHER_X - 7, WATER_Y - 2, '\\_/', 'rock');
114
+ if (fish)
115
+ c.put(FISHER_X - 6, WATER_Y - 3, '>', 'water');
116
+ const face = happy ? (catchKind === 'fish' ? '^.^' : '-_-') : phase === 'bite' ? 'O.O' : blink(t, 1);
117
+ const pulling = phase === 'pull';
118
+ c.sprite(FISHER_X, WATER_Y - 4, withFace(pulling ? SIT_PULL : SIT_ROD, face), 'agent');
119
+ if (pulling) {
120
+ c.put(FISHER_X + 5, WATER_Y - 6, '|', 'wood');
121
+ c.put(FISHER_X + 5, WATER_Y - 7, '.', 'wood');
122
+ }
123
+ else {
124
+ c.put(FISHER_X + 6, WATER_Y - 5, '/', 'wood');
125
+ c.put(FISHER_X + 7, WATER_Y - 6, '/', 'wood');
126
+ c.put(FISHER_X + 8, WATER_Y - 7, '.', 'wood');
127
+ for (let y = WATER_Y - 6; y < WATER_Y; y++)
128
+ c.put(FISHER_X + 9, y, ':', 'cloud');
129
+ const bob = phase === 'bite' ? (t % 4 < 2 ? 1 : 0) : Math.floor(t / 8) % 2 ? 0 : 0;
130
+ c.put(FISHER_X + 9, WATER_Y + bob, 'o', 'fire');
131
+ if (phase === 'bite') {
132
+ c.put(FISHER_X + 8, WATER_Y, '(', 'water');
133
+ c.put(FISHER_X + 10, WATER_Y, ')', 'water');
134
+ c.put(FISHER_X + 1, WATER_Y - 6, '!', 'spark');
135
+ }
136
+ }
137
+ if (flying)
138
+ c.put(flying.x, flying.y, flying.ch, flying.tone);
139
+ if (happy && t % 6 < 4)
140
+ c.put(FISHER_X - 2, WATER_Y - 6, catchKind === 'fish' ? '(uno más!)' : '(una bota?)', 'cloud');
141
+ for (const b of birds)
142
+ c.put(b.x, b.y, Math.floor(t / 4) % 2 ? 'v' : '-v-', 'cloud');
143
+ },
144
+ status() {
145
+ return `sin tareas pendientes · peces ${fish} · botas ${boots}`;
146
+ },
147
+ };
148
+ },
149
+ };
@@ -0,0 +1,138 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion, prefer-const -- scene arrays are indexed within bounds; particle arrays are mutated in place. */
2
+ import { blink, drawCloud, drawGround, rng, soilLine, withFace } from '../engine.js';
3
+ const W = 78;
4
+ const H = 13;
5
+ const G = 11;
6
+ const HOUSE_X = 60;
7
+ const PASS = [8, 15, 22, 29, 36, 43];
8
+ const THROWER = 50;
9
+ const REACH_L = [' .-. ', ' (o.o)', '_( )', " ' ' "];
10
+ const REACH_R = [' .-. ', '(o.o) ', '( )_', " ' ' "];
11
+ const THROW = [' .-. /', '(o.o)/ ', '( ) ', " ' ' "];
12
+ const WELL = [' ___ ', ' /___\\ ', ' | | ', ' [ ] ', ' [___] '];
13
+ const HOUSE = [' ____ ', ' / \\ ', ' /______\\ ', ' |[] []| ', ' | __ | ', ' |_| |_| '];
14
+ export const fire = {
15
+ id: 'fire',
16
+ title: 'Apagando incendio',
17
+ useFor: 'Tareas urgentes / incidente crítico',
18
+ width: W,
19
+ height: H,
20
+ create(seed = 5) {
21
+ const r = rng(seed);
22
+ const soil = [soilLine(W, r)];
23
+ let t = 0;
24
+ let I = 10;
25
+ let outT = 0;
26
+ let throwT = 0;
27
+ let thrown = 0;
28
+ let buckets = [];
29
+ let water = [];
30
+ let smoke = [];
31
+ let flames = [];
32
+ return {
33
+ step() {
34
+ t++;
35
+ if (t % 16 === 0)
36
+ buckets.push({ x: 6 });
37
+ for (const b of buckets)
38
+ b.x += 0.5;
39
+ if (buckets.length && buckets[0].x >= THROWER - 1) {
40
+ buckets.shift();
41
+ if (I > 0) {
42
+ throwT = 8;
43
+ thrown++;
44
+ for (let i = 0; i < 6; i++) {
45
+ water.push({ x: THROWER + 6, y: G - 4, vx: 0.75 + r() * 0.35, vy: -0.55 - r() * 0.25, ch: "'.:"[i % 3], tone: 'water' });
46
+ }
47
+ }
48
+ }
49
+ if (throwT)
50
+ throwT--;
51
+ for (const p of water) {
52
+ p.x += p.vx;
53
+ p.y += p.vy;
54
+ p.vy += 0.1;
55
+ }
56
+ water = water.filter((p) => {
57
+ if (p.x >= HOUSE_X + 2 && p.x <= HOUSE_X + 12 && I > 0) {
58
+ I = Math.max(0, I - 0.25);
59
+ smoke.push({ x: p.x, y: p.y, l: 0, steam: true });
60
+ return false;
61
+ }
62
+ return p.y < G && p.x < W;
63
+ });
64
+ if (I > 0) {
65
+ I = Math.min(10, I + 0.03);
66
+ outT = 0;
67
+ if (t % 3 === 0)
68
+ smoke.push({ x: HOUSE_X + 2 + r() * 8, y: G - 2 - I * 0.6, l: 0 });
69
+ }
70
+ else {
71
+ outT++;
72
+ if (outT < 40 && t % 4 === 0)
73
+ smoke.push({ x: HOUSE_X + 2 + r() * 8, y: G - 2, l: 0 });
74
+ if (outT > 70)
75
+ I = 2;
76
+ }
77
+ for (const s of smoke) {
78
+ s.l++;
79
+ s.y -= 0.2;
80
+ s.x += 0.1 + Math.sin((s.l + s.x) * 0.4) * 0.1;
81
+ }
82
+ smoke = smoke.filter((s) => s.l < (s.steam ? 8 : 26) && s.y > -1);
83
+ flames = [];
84
+ for (let col = 0; col < 10; col++) {
85
+ flames.push(Math.max(0, Math.round(I * 0.7 * (0.55 + 0.45 * Math.sin(t * 0.7 + col * 1.3)) + (r() - 0.5) * 1.4)));
86
+ }
87
+ },
88
+ draw(c) {
89
+ drawCloud(c, t, 0.05, 0, 0);
90
+ drawGround(c, G, soil);
91
+ c.sprite(0, G - 5, WELL, 'rock');
92
+ c.put(2, G - 2, '~~~', 'water');
93
+ c.sprite(HOUSE_X, G - 6, HOUSE, 'wood');
94
+ if (I > 0) {
95
+ flames.forEach((h, col) => {
96
+ const x = HOUSE_X + 2 + col;
97
+ for (let k = 0; k < h; k++) {
98
+ const top = k === h - 1;
99
+ const ch = top ? "^'^"[(t + x) % 3] : k < 2 ? 'wWw'[(t + x + k) % 3] : ')(('[(t + x + k) % 3];
100
+ c.put(x, G - 1 - k, ch, top || k > h * 0.6 ? 'flame' : 'fire');
101
+ }
102
+ });
103
+ }
104
+ const hot = I > 6;
105
+ const out = I <= 0;
106
+ PASS.forEach((x, i) => {
107
+ const cx = x + 2.5;
108
+ const b = buckets.find((b) => b.x + 1.5 > cx - 6 && b.x + 1.5 < cx + 4);
109
+ const pose = b && b.x + 1.5 < cx ? REACH_L : REACH_R;
110
+ c.sprite(x, G - 4, withFace(pose, out ? '^.^' : hot ? blink(t, i, '>.<') : blink(t, i)), 'agent');
111
+ });
112
+ for (const b of buckets) {
113
+ c.put(b.x, G - 2, '\\_/', 'rock');
114
+ c.put(b.x + 1, G - 3, '~', 'water');
115
+ }
116
+ c.sprite(THROWER, G - 4, withFace(throwT > 3 ? THROW : REACH_R, out ? '^.^' : hot ? '>.<' : blink(t, 9)), 'agent');
117
+ if (throwT > 3)
118
+ c.put(THROWER + 6, G - 5, '\\~/', 'water');
119
+ if (hot && Math.floor(t / 20) % 2)
120
+ c.put(7, G - 5, '(agua!)', 'cloud');
121
+ if (out) {
122
+ c.put(14, G - 5, '(uf!)', 'cloud');
123
+ c.put(35, G - 5, '(listo)', 'cloud');
124
+ if (t % 10 < 6)
125
+ c.put(HOUSE_X + 5, G - 8, 'ok', 'good');
126
+ }
127
+ for (const p of water)
128
+ c.put(p.x, p.y, p.ch, p.tone);
129
+ for (const s of smoke)
130
+ c.put(s.x, s.y, s.steam ? '~' : s.l < 8 ? '.' : s.l < 16 ? 'o' : 'O', 'cloud');
131
+ },
132
+ status() {
133
+ const lv = Math.ceil(I / 2);
134
+ return `fuego ${'▮'.repeat(lv)}${'▯'.repeat(5 - lv)} · baldes ${thrown}${I <= 0 ? ' · apagado' : ''}`;
135
+ },
136
+ };
137
+ },
138
+ };
@@ -0,0 +1,25 @@
1
+ import { working } from './working.js';
2
+ import { resting } from './resting.js';
3
+ import { clockIn } from './clockIn.js';
4
+ import { planning } from './planning.js';
5
+ import { fire } from './fire.js';
6
+ import { celebrate } from './celebrate.js';
7
+ import { syncing } from './syncing.js';
8
+ import { bugHunt } from './bugHunt.js';
9
+ import { empty } from './empty.js';
10
+ import { deadline } from './deadline.js';
11
+ import { cleaning } from './cleaning.js';
12
+ export const SCENES = {
13
+ working,
14
+ resting,
15
+ clockIn,
16
+ planning,
17
+ fire,
18
+ celebrate,
19
+ syncing,
20
+ bugHunt,
21
+ empty,
22
+ deadline,
23
+ cleaning,
24
+ };
25
+ export const SCENE_IDS = Object.keys(SCENES);
@@ -0,0 +1,73 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion -- scene arrays are indexed within their declared bounds. */
2
+ import { blink, drawGround, rng, soilLine, withFace } from '../engine.js';
3
+ const W = 78;
4
+ const H = 12;
5
+ const G = 10;
6
+ const BX = 46;
7
+ const VALS = [3, 3, 3, 2, 3, 2, 2, 2, 1, 2, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0];
8
+ const IDEAS = ['( ? )', '( ! )', '(...)', '( % )', '(ok!)'];
9
+ const SEATED = [' .-. ', '(o.o)', '( )'];
10
+ const POINT_UP = [' .-. ', '(o.o) /', '( )/ ', " ' ' "];
11
+ const POINT_SIDE = [' .-. ', '(o.o) ', '( )--', " ' ' "];
12
+ export const planning = {
13
+ id: 'planning',
14
+ title: 'Analizando planes',
15
+ useFor: 'Planificación / revisión de sprint',
16
+ width: W,
17
+ height: H,
18
+ create(seed = 4) {
19
+ const r = rng(seed);
20
+ const soil = [soilLine(W, r)];
21
+ let t = 0;
22
+ const cycle = () => Math.floor(t / 3) % (VALS.length + 20);
23
+ return {
24
+ step() {
25
+ t++;
26
+ },
27
+ draw(c) {
28
+ drawGround(c, G, soil);
29
+ c.put(BX, 0, ' ' + '_'.repeat(30), 'rock');
30
+ for (let y = 1; y < 7; y++)
31
+ c.put(BX, y, '|' + ' '.repeat(30) + '|', 'rock');
32
+ c.put(BX, 7, '|' + '_'.repeat(30) + '|', 'rock');
33
+ c.put(BX + 4, 8, '/', 'rock');
34
+ c.put(BX + 3, 9, '/', 'rock');
35
+ c.put(BX + 27, 8, '\\', 'rock');
36
+ c.put(BX + 28, 9, '\\', 'rock');
37
+ c.put(BX + 2, 1, 'plan v2', 'text');
38
+ for (let y = 2; y < 6; y++)
39
+ c.put(BX + 3, y, '|', 'cloud');
40
+ c.put(BX + 3, 6, '+' + '-'.repeat(26), 'cloud');
41
+ const n = cycle();
42
+ const done = n >= VALS.length;
43
+ const shown = Math.min(n, VALS.length);
44
+ for (let i = 0; i < shown; i++)
45
+ c.put(BX + 5 + i, 2 + VALS[i], i === shown - 1 ? '*' : '.', 'accent');
46
+ if (done && t % 10 < 6)
47
+ c.put(BX + 30, 1, '!', 'good');
48
+ [11, 20, 29].forEach((x, i) => {
49
+ const face = done ? '^.^' : i === 1 ? blink(t, 7, '-.o') : blink(t, 8 + i);
50
+ c.sprite(x, G - 6, withFace(SEATED, face), 'agent');
51
+ if (Math.floor((t + i * 17) / 22) % 3 < 2) {
52
+ c.put(x - 1, G - 8, IDEAS[(Math.floor(t / 66) + i) % 5], 'cloud');
53
+ c.put(x + 3, G - 7, 'o', 'cloud');
54
+ }
55
+ });
56
+ c.put(16, G - 4, 'c[]', 'paper');
57
+ c.put(17 + ((t >> 3) % 2), G - 5, '~', 'cloud');
58
+ c.put(25, G - 4, '[=]', 'accent');
59
+ c.put(8, G - 3, '▄'.repeat(31), 'wood');
60
+ for (const lx of [9, 36]) {
61
+ c.put(lx, G - 2, '||', 'wood');
62
+ c.put(lx, G - 1, '||', 'wood');
63
+ }
64
+ const pose = Math.floor(t / 20) % 2 ? POINT_UP : POINT_SIDE;
65
+ c.sprite(39, G - 4, withFace(pose, done ? '^.^' : blink(t, 11)), 'agent');
66
+ },
67
+ status() {
68
+ const n = cycle();
69
+ return n >= VALS.length ? 'plan aprobado' : `analizando · ${Math.round((n / VALS.length) * 100)}%`;
70
+ },
71
+ };
72
+ },
73
+ };
@@ -0,0 +1,90 @@
1
+ import { AGENT, blink, drawCloud, drawGround, mirror, rng, soilLine, withFace } from '../engine.js';
2
+ const W = 78;
3
+ const H = 12;
4
+ const G = 10;
5
+ const TREE = [' .--~~--. ', ' .( ~ ~ ). ', '( ~ ~ ~ )', " '-.______.-' "];
6
+ const STRETCH = ['\\ .-. /', ' (o.O) ', ' ( ) ', " ' ' "];
7
+ const COFFEE = [' .-. ', '(o.o)c[]', '(___) '];
8
+ export const resting = {
9
+ id: 'resting',
10
+ title: 'Descansando',
11
+ useFor: 'Sin actividad / en pausa',
12
+ width: W,
13
+ height: H,
14
+ create(seed = 2) {
15
+ const r = rng(seed);
16
+ const soil = [soilLine(W, r)];
17
+ let t = 0;
18
+ let zs = [];
19
+ let leaves = [];
20
+ return {
21
+ step() {
22
+ t++;
23
+ const sw = Math.floor(t / 10) % 2;
24
+ if (t % 14 === 0)
25
+ zs.push({ x: 11, y: G - 3, l: 0 });
26
+ if (t % 18 === 5)
27
+ zs.push({ x: 39 + sw, y: G - 6, l: 0 });
28
+ if (t % 25 === 0)
29
+ leaves.push({ x: 1 + r() * 11, y: 5 });
30
+ for (const z of zs) {
31
+ z.l++;
32
+ z.y -= 0.15;
33
+ z.x += 0.12;
34
+ }
35
+ zs = zs.filter((z) => z.l < 22);
36
+ for (const l of leaves) {
37
+ l.y += 0.12;
38
+ l.x += Math.sin(l.y * 2) * 0.3;
39
+ }
40
+ leaves = leaves.filter((l) => l.y < G - 0.5);
41
+ },
42
+ draw(c) {
43
+ drawCloud(c, t, 0.05, 10, 0);
44
+ drawGround(c, G, soil);
45
+ c.put(73, 0, '\\ | /', 'spark');
46
+ c.put(73, 1, '- O -', 'spark');
47
+ c.put(73, 2, '/ | \\', 'spark');
48
+ c.sprite(0, 2, TREE, 'leaf');
49
+ for (let y = 6; y < G; y++)
50
+ c.put(6, y, '||', 'wood');
51
+ c.put(10, G - 2, ' .-.____ ', 'agent');
52
+ c.put(10, G - 1, '(-.-_____)', 'agent');
53
+ const sip = t % 50 < 8;
54
+ c.sprite(21, G - 3, withFace(COFFEE, sip ? '^.^' : blink(t, 1)), 'agent');
55
+ c.put(26, G - 2, 'c[]', 'paper');
56
+ c.put(27 + ((t >> 3) % 2), G - 3, '~', 'cloud');
57
+ const sw = Math.floor(t / 10) % 2;
58
+ for (let y = G - 5; y < G; y++) {
59
+ c.put(33, y, '|', 'wood');
60
+ c.put(49, y, '|', 'wood');
61
+ }
62
+ c.put(34, G - 4, '\\', 'wood');
63
+ c.put(48, G - 4, '/', 'wood');
64
+ c.put(35, G - 3, '\\___________/', 'wood');
65
+ c.put(38 + sw, G - 5, ' .-.___', 'agent');
66
+ c.put(38 + sw, G - 4, '(-.-___)', 'agent');
67
+ if (Math.floor(t / 24) % 3 === 0)
68
+ c.sprite(53, G - 4, STRETCH, 'agent');
69
+ else
70
+ c.sprite(54, G - 4, withFace(AGENT.stand, blink(t, 2)), 'agent');
71
+ const ph = Math.floor(t / 15) % 4;
72
+ c.sprite(62, G - 3, withFace(AGENT.sit, blink(t, 3)), 'agent');
73
+ c.sprite(68, G - 3, withFace(mirror(AGENT.sit), ph === 1 ? '^.^' : blink(t, 4)), 'agent');
74
+ if (ph === 0)
75
+ c.put(61, G - 4, '(bla)', 'cloud');
76
+ if (ph === 1)
77
+ c.put(67, G - 4, '(jaja)', 'cloud');
78
+ if (ph === 2)
79
+ c.put(61, G - 4, '(...)', 'cloud');
80
+ for (const z of zs)
81
+ c.put(z.x, z.y, z.l < 8 ? 'z' : 'Z', 'cloud');
82
+ for (const l of leaves)
83
+ c.put(l.x, l.y, ',', 'leaf');
84
+ },
85
+ status() {
86
+ return 'en pausa · recargando energía';
87
+ },
88
+ };
89
+ },
90
+ };