@duetso/agent 0.1.139 → 0.1.140
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/dist/package.json +1 -1
- package/dist/src/cli/help.d.ts.map +1 -1
- package/dist/src/cli/help.js +20 -7
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/memory-reflect.d.ts.map +1 -1
- package/dist/src/cli/memory-reflect.js +3 -2
- package/dist/src/cli/memory-reflect.js.map +1 -1
- package/dist/src/memory/observation-groups.d.ts +11 -1
- package/dist/src/memory/observation-groups.d.ts.map +1 -1
- package/dist/src/memory/observation-groups.js +15 -5
- package/dist/src/memory/observation-groups.js.map +1 -1
- package/dist/src/memory/observational-prompts.d.ts +21 -2
- package/dist/src/memory/observational-prompts.d.ts.map +1 -1
- package/dist/src/memory/observational-prompts.js +89 -12
- package/dist/src/memory/observational-prompts.js.map +1 -1
- package/dist/src/memory/observational.d.ts +36 -6
- package/dist/src/memory/observational.d.ts.map +1 -1
- package/dist/src/memory/observational.js +118 -53
- package/dist/src/memory/observational.js.map +1 -1
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +19 -0
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/dino/index.d.ts +31 -0
- package/dist/src/tui/dino/index.d.ts.map +1 -0
- package/dist/src/tui/dino/index.js +313 -0
- package/dist/src/tui/dino/index.js.map +1 -0
- package/dist/src/tui/dino/input.d.ts +12 -0
- package/dist/src/tui/dino/input.d.ts.map +1 -0
- package/dist/src/tui/dino/input.js +44 -0
- package/dist/src/tui/dino/input.js.map +1 -0
- package/dist/src/tui/dino/persistence.d.ts +3 -0
- package/dist/src/tui/dino/persistence.d.ts.map +1 -0
- package/dist/src/tui/dino/persistence.js +36 -0
- package/dist/src/tui/dino/persistence.js.map +1 -0
- package/dist/src/tui/dino/render.d.ts +19 -0
- package/dist/src/tui/dino/render.d.ts.map +1 -0
- package/dist/src/tui/dino/render.js +164 -0
- package/dist/src/tui/dino/render.js.map +1 -0
- package/dist/src/tui/dino/state.d.ts +141 -0
- package/dist/src/tui/dino/state.d.ts.map +1 -0
- package/dist/src/tui/dino/state.js +156 -0
- package/dist/src/tui/dino/state.js.map +1 -0
- package/dist/src/tui/dino/tick.d.ts +10 -0
- package/dist/src/tui/dino/tick.d.ts.map +1 -0
- package/dist/src/tui/dino/tick.js +117 -0
- package/dist/src/tui/dino/tick.js.map +1 -0
- package/dist/src/tui/dino/visibility.d.ts +2 -0
- package/dist/src/tui/dino/visibility.d.ts.map +1 -0
- package/dist/src/tui/dino/visibility.js +18 -0
- package/dist/src/tui/dino/visibility.js.map +1 -0
- package/dist/src/tui/key-handlers.d.ts +7 -0
- package/dist/src/tui/key-handlers.d.ts.map +1 -1
- package/dist/src/tui/key-handlers.js +25 -1
- package/dist/src/tui/key-handlers.js.map +1 -1
- package/dist/src/tui/layout.d.ts +7 -0
- package/dist/src/tui/layout.d.ts.map +1 -1
- package/dist/src/tui/layout.js +10 -0
- package/dist/src/tui/layout.js.map +1 -1
- package/dist/src/tui/status-controller.d.ts +9 -0
- package/dist/src/tui/status-controller.d.ts.map +1 -1
- package/dist/src/tui/status-controller.js +28 -0
- package/dist/src/tui/status-controller.js.map +1 -1
- package/dist/src/turn-runner/tools.js +17 -21
- package/dist/src/turn-runner/tools.js.map +1 -1
- package/dist/src/turn-runner/turn-runner.d.ts.map +1 -1
- package/dist/src/turn-runner/turn-runner.js +1 -0
- package/dist/src/turn-runner/turn-runner.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/** Default logical width of the playfield in character cells. Used as the
|
|
2
|
+
* initial value of `GameState.fieldWidth`; the panel updates the live
|
|
3
|
+
* field width from the renderer on construction and on every resize so
|
|
4
|
+
* the game fills the available column. */
|
|
5
|
+
export declare const DEFAULT_FIELD_WIDTH = 60;
|
|
6
|
+
/** Minimum field width we will render at. Below this the playfield gets
|
|
7
|
+
* uncomfortably tight for the dino + grace window + spawned obstacles. */
|
|
8
|
+
export declare const MIN_FIELD_WIDTH = 40;
|
|
9
|
+
/** Maximum field width we will render at. Above this the obstacles get so
|
|
10
|
+
* far apart that the game stops feeling like Chrome's dino. The cap is
|
|
11
|
+
* generous so ultra-wide terminals still look full. */
|
|
12
|
+
export declare const MAX_FIELD_WIDTH = 240;
|
|
13
|
+
/** @deprecated Use `state.fieldWidth`. Kept as a re-export of the default
|
|
14
|
+
* so older call sites and tests continue to compile against a single
|
|
15
|
+
* width number. */
|
|
16
|
+
export declare const FIELD_WIDTH = 60;
|
|
17
|
+
/** Row index of the ground line within the rendered panel (0-indexed from
|
|
18
|
+
* the top of the 12-row panel). The dino's `y` is measured upward from
|
|
19
|
+
* here so a positive `y` means "in the air". */
|
|
20
|
+
export declare const GROUND_ROW = 8;
|
|
21
|
+
/** Horizontal cell the dino occupies; obstacles scroll past this column. */
|
|
22
|
+
export declare const DINO_X = 6;
|
|
23
|
+
/** Gravity applied per tick to `dinoVy`, in cells/tick². Tuned with
|
|
24
|
+
* `JUMP_VELOCITY` so a single press clears a small cactus and the dino
|
|
25
|
+
* lands in ~0.45s — matching the snappy feel of Chrome's offline dino
|
|
26
|
+
* rather than a floaty Mario jump. Peak height ≈ v²/(2g) ≈ 4.9 cells. */
|
|
27
|
+
export declare const GRAVITY = 0.75;
|
|
28
|
+
/** Upward velocity applied on a jump press while grounded, in cells/tick.
|
|
29
|
+
* Combined with `GRAVITY` this gives a tight ~7.2-tick airtime so the
|
|
30
|
+
* rhythm matches Chrome's game. */
|
|
31
|
+
export declare const JUMP_VELOCITY = 2.7;
|
|
32
|
+
/** Base horizontal scroll speed in cells/tick. */
|
|
33
|
+
export declare const BASE_SPEED = 0.6;
|
|
34
|
+
/** Cap so the game stays playable on a single jump arc no matter how long
|
|
35
|
+
* the run lasts. */
|
|
36
|
+
export declare const MAX_SPEED = 1.6;
|
|
37
|
+
/** Score gained per advanced tick at base speed. Scaled with current speed
|
|
38
|
+
* so faster runs score faster, matching Chrome's behavior. */
|
|
39
|
+
export declare const SCORE_PER_TICK = 0.1;
|
|
40
|
+
/** Minimum horizontal gap between consecutive obstacles, expressed in
|
|
41
|
+
* cells, before the spawner is allowed to drop another one. */
|
|
42
|
+
export declare const MIN_OBSTACLE_GAP = 14;
|
|
43
|
+
/** Maximum extra gap added on top of the minimum, chosen with a per-spawn
|
|
44
|
+
* random roll so the cadence does not feel metronomic. */
|
|
45
|
+
export declare const MAX_EXTRA_GAP = 18;
|
|
46
|
+
/** Cells of obstacle-free runway granted ahead of the dino on resume after
|
|
47
|
+
* an automatic freeze. Set to ~1.5s worth of cells at base speed. */
|
|
48
|
+
export declare const GRACE_DISTANCE_CELLS = 14;
|
|
49
|
+
/** Maximum distance ahead of the dino at which the FIRST obstacle of a run
|
|
50
|
+
* is allowed to spawn, in cells. Without this cap the first obstacle
|
|
51
|
+
* always spawns at the right edge of the playfield, so on a 200-cell-wide
|
|
52
|
+
* terminal the user waits ~23 seconds before anything reaches them. With
|
|
53
|
+
* the cap, wide screens still see the obstacle enter from the right but
|
|
54
|
+
* no further out than ~4 seconds of runway. Narrow screens (where the
|
|
55
|
+
* edge is already closer than this) are unaffected. */
|
|
56
|
+
export declare const FIRST_OBSTACLE_MAX_DISTANCE = 36;
|
|
57
|
+
export interface Obstacle {
|
|
58
|
+
/** Sub-cell horizontal position. Decreases as the world scrolls left. */
|
|
59
|
+
x: number;
|
|
60
|
+
/** Cactus height in cells. 1 = small, 2 = tall. v1 ships with one size
|
|
61
|
+
* but the field is in place so a future variant can differ. */
|
|
62
|
+
height: number;
|
|
63
|
+
}
|
|
64
|
+
export type Phase = {
|
|
65
|
+
kind: "idle";
|
|
66
|
+
} | {
|
|
67
|
+
kind: "running";
|
|
68
|
+
} | {
|
|
69
|
+
kind: "countdown";
|
|
70
|
+
ticksRemaining: number;
|
|
71
|
+
} | {
|
|
72
|
+
kind: "grace";
|
|
73
|
+
} | {
|
|
74
|
+
kind: "frozen";
|
|
75
|
+
} | {
|
|
76
|
+
kind: "gameover";
|
|
77
|
+
};
|
|
78
|
+
export interface GameState {
|
|
79
|
+
phase: Phase;
|
|
80
|
+
/** Score accumulates only during `running`. Frozen as an integer for the
|
|
81
|
+
* UI but kept as a float here so sub-tick scaling is preserved. */
|
|
82
|
+
score: number;
|
|
83
|
+
/** Best score observed this process. Hydrated from `~/.duet` at panel
|
|
84
|
+
* construction; persisted whenever a run ends with `score > highScore`. */
|
|
85
|
+
highScore: number;
|
|
86
|
+
/** Current scroll speed in cells/tick. Ramps from BASE_SPEED toward
|
|
87
|
+
* MAX_SPEED as score grows. */
|
|
88
|
+
speed: number;
|
|
89
|
+
/** Dino vertical position above the ground in cells. `0` = grounded. */
|
|
90
|
+
dinoY: number;
|
|
91
|
+
/** Dino vertical velocity in cells/tick. Positive = ascending. */
|
|
92
|
+
dinoVy: number;
|
|
93
|
+
/** Obstacles ordered left-to-right by `x`. The spawner appends to the
|
|
94
|
+
* tail; the tick removes from the head once an obstacle scrolls past
|
|
95
|
+
* `x < -2`. */
|
|
96
|
+
obstacles: Obstacle[];
|
|
97
|
+
/** Cells of runway still owed to the dino during the post-countdown
|
|
98
|
+
* grace period. Decremented each tick; transitions back to `running`
|
|
99
|
+
* when it reaches zero. */
|
|
100
|
+
graceCellsLeft: number;
|
|
101
|
+
/** Cells of horizontal distance until the spawner is allowed to emit
|
|
102
|
+
* the next obstacle. Decremented each tick the world advances. */
|
|
103
|
+
cellsUntilNextSpawn: number;
|
|
104
|
+
/** Live width of the playfield in cells. The panel keeps this in sync
|
|
105
|
+
* with the renderer's terminal width on construction and on resize so
|
|
106
|
+
* the game stretches to fill the available column. Obstacles spawn at
|
|
107
|
+
* the right edge of this window. */
|
|
108
|
+
fieldWidth: number;
|
|
109
|
+
}
|
|
110
|
+
export declare function initialState(highScore: number, fieldWidth?: number): GameState;
|
|
111
|
+
/** Resize reducer. Called by the panel when the terminal resizes; clamps
|
|
112
|
+
* to the supported range and trims any obstacles that fell off the new
|
|
113
|
+
* right edge so a shrink doesn't leave hazards floating in space. */
|
|
114
|
+
export declare function setFieldWidth(state: GameState, fieldWidth: number): GameState;
|
|
115
|
+
export declare function clampFieldWidth(width: number): number;
|
|
116
|
+
/** Start a fresh run from `idle` or `gameover`. Preserves `highScore` and
|
|
117
|
+
* the current `fieldWidth` so resizes during gameover persist into the
|
|
118
|
+
* next run. */
|
|
119
|
+
export declare function startRun(state: GameState): GameState;
|
|
120
|
+
/** Snap to the ground and stop the world. Called from the panel's
|
|
121
|
+
* `freeze()` so a long agent turn does not leave the dino hanging
|
|
122
|
+
* mid-jump. */
|
|
123
|
+
export declare function freezeRun(state: GameState): GameState;
|
|
124
|
+
/** Decide what should happen when the user re-expands the dino panel
|
|
125
|
+
* while a run is in progress. Three outcomes:
|
|
126
|
+
* - "countdown": agent-induced freeze → run the 3-2-1 + grace gap.
|
|
127
|
+
* - "run": user-induced collapse → instant resume.
|
|
128
|
+
* - "noop": nothing in flight (idle/gameover/countdown/grace/running).
|
|
129
|
+
* Extracted as a pure helper so the panel's toggle flow is unit-testable
|
|
130
|
+
* without spinning up a CliRenderer. */
|
|
131
|
+
export declare function expandResumeKind(phase: GameState["phase"], frozenByAgent: boolean): "countdown" | "run" | "noop";
|
|
132
|
+
/** Begin the 3-2-1 countdown after an automatic freeze ends. The countdown
|
|
133
|
+
* itself counts down by tick in `tick.ts` so this just seeds the phase. */
|
|
134
|
+
export declare function beginCountdown(state: GameState, ticksPerSecond: number): GameState;
|
|
135
|
+
/** Transition from countdown into the grace gap. The grace gap pushes any
|
|
136
|
+
* obstacle inside `GRACE_DISTANCE_CELLS` of the dino's column out to the
|
|
137
|
+
* far edge of the grace window so the run resumes without an unfair hit. */
|
|
138
|
+
export declare function beginGrace(state: GameState): GameState;
|
|
139
|
+
export declare function endRunOnHit(state: GameState): GameState;
|
|
140
|
+
export declare function isWorldAdvancing(phase: Phase): boolean;
|
|
141
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/tui/dino/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Pure GameState for the dino panel. No timers, no I/O, no OpenTUI imports.
|
|
2
|
+
// All transitions are reducer-style: state in, state out.
|
|
3
|
+
/** Default logical width of the playfield in character cells. Used as the
|
|
4
|
+
* initial value of `GameState.fieldWidth`; the panel updates the live
|
|
5
|
+
* field width from the renderer on construction and on every resize so
|
|
6
|
+
* the game fills the available column. */
|
|
7
|
+
export const DEFAULT_FIELD_WIDTH = 60;
|
|
8
|
+
/** Minimum field width we will render at. Below this the playfield gets
|
|
9
|
+
* uncomfortably tight for the dino + grace window + spawned obstacles. */
|
|
10
|
+
export const MIN_FIELD_WIDTH = 40;
|
|
11
|
+
/** Maximum field width we will render at. Above this the obstacles get so
|
|
12
|
+
* far apart that the game stops feeling like Chrome's dino. The cap is
|
|
13
|
+
* generous so ultra-wide terminals still look full. */
|
|
14
|
+
export const MAX_FIELD_WIDTH = 240;
|
|
15
|
+
/** @deprecated Use `state.fieldWidth`. Kept as a re-export of the default
|
|
16
|
+
* so older call sites and tests continue to compile against a single
|
|
17
|
+
* width number. */
|
|
18
|
+
export const FIELD_WIDTH = DEFAULT_FIELD_WIDTH;
|
|
19
|
+
/** Row index of the ground line within the rendered panel (0-indexed from
|
|
20
|
+
* the top of the 12-row panel). The dino's `y` is measured upward from
|
|
21
|
+
* here so a positive `y` means "in the air". */
|
|
22
|
+
export const GROUND_ROW = 8;
|
|
23
|
+
/** Horizontal cell the dino occupies; obstacles scroll past this column. */
|
|
24
|
+
export const DINO_X = 6;
|
|
25
|
+
/** Gravity applied per tick to `dinoVy`, in cells/tick². Tuned with
|
|
26
|
+
* `JUMP_VELOCITY` so a single press clears a small cactus and the dino
|
|
27
|
+
* lands in ~0.45s — matching the snappy feel of Chrome's offline dino
|
|
28
|
+
* rather than a floaty Mario jump. Peak height ≈ v²/(2g) ≈ 4.9 cells. */
|
|
29
|
+
export const GRAVITY = 0.75;
|
|
30
|
+
/** Upward velocity applied on a jump press while grounded, in cells/tick.
|
|
31
|
+
* Combined with `GRAVITY` this gives a tight ~7.2-tick airtime so the
|
|
32
|
+
* rhythm matches Chrome's game. */
|
|
33
|
+
export const JUMP_VELOCITY = 2.7;
|
|
34
|
+
/** Base horizontal scroll speed in cells/tick. */
|
|
35
|
+
export const BASE_SPEED = 0.6;
|
|
36
|
+
/** Cap so the game stays playable on a single jump arc no matter how long
|
|
37
|
+
* the run lasts. */
|
|
38
|
+
export const MAX_SPEED = 1.6;
|
|
39
|
+
/** Score gained per advanced tick at base speed. Scaled with current speed
|
|
40
|
+
* so faster runs score faster, matching Chrome's behavior. */
|
|
41
|
+
export const SCORE_PER_TICK = 0.1;
|
|
42
|
+
/** Minimum horizontal gap between consecutive obstacles, expressed in
|
|
43
|
+
* cells, before the spawner is allowed to drop another one. */
|
|
44
|
+
export const MIN_OBSTACLE_GAP = 14;
|
|
45
|
+
/** Maximum extra gap added on top of the minimum, chosen with a per-spawn
|
|
46
|
+
* random roll so the cadence does not feel metronomic. */
|
|
47
|
+
export const MAX_EXTRA_GAP = 18;
|
|
48
|
+
/** Cells of obstacle-free runway granted ahead of the dino on resume after
|
|
49
|
+
* an automatic freeze. Set to ~1.5s worth of cells at base speed. */
|
|
50
|
+
export const GRACE_DISTANCE_CELLS = 14;
|
|
51
|
+
/** Maximum distance ahead of the dino at which the FIRST obstacle of a run
|
|
52
|
+
* is allowed to spawn, in cells. Without this cap the first obstacle
|
|
53
|
+
* always spawns at the right edge of the playfield, so on a 200-cell-wide
|
|
54
|
+
* terminal the user waits ~23 seconds before anything reaches them. With
|
|
55
|
+
* the cap, wide screens still see the obstacle enter from the right but
|
|
56
|
+
* no further out than ~4 seconds of runway. Narrow screens (where the
|
|
57
|
+
* edge is already closer than this) are unaffected. */
|
|
58
|
+
export const FIRST_OBSTACLE_MAX_DISTANCE = 36;
|
|
59
|
+
export function initialState(highScore, fieldWidth = DEFAULT_FIELD_WIDTH) {
|
|
60
|
+
return {
|
|
61
|
+
phase: { kind: "idle" },
|
|
62
|
+
score: 0,
|
|
63
|
+
highScore,
|
|
64
|
+
speed: BASE_SPEED,
|
|
65
|
+
dinoY: 0,
|
|
66
|
+
dinoVy: 0,
|
|
67
|
+
obstacles: [],
|
|
68
|
+
graceCellsLeft: 0,
|
|
69
|
+
cellsUntilNextSpawn: MIN_OBSTACLE_GAP,
|
|
70
|
+
fieldWidth: clampFieldWidth(fieldWidth),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Resize reducer. Called by the panel when the terminal resizes; clamps
|
|
74
|
+
* to the supported range and trims any obstacles that fell off the new
|
|
75
|
+
* right edge so a shrink doesn't leave hazards floating in space. */
|
|
76
|
+
export function setFieldWidth(state, fieldWidth) {
|
|
77
|
+
const next = clampFieldWidth(fieldWidth);
|
|
78
|
+
if (next === state.fieldWidth)
|
|
79
|
+
return state;
|
|
80
|
+
// Drop obstacles past the new right edge; the spawner will refill from
|
|
81
|
+
// the new edge on the next tick.
|
|
82
|
+
const obstacles = state.obstacles.filter((o) => o.x < next);
|
|
83
|
+
return { ...state, fieldWidth: next, obstacles };
|
|
84
|
+
}
|
|
85
|
+
export function clampFieldWidth(width) {
|
|
86
|
+
if (!Number.isFinite(width))
|
|
87
|
+
return DEFAULT_FIELD_WIDTH;
|
|
88
|
+
return Math.max(MIN_FIELD_WIDTH, Math.min(MAX_FIELD_WIDTH, Math.floor(width)));
|
|
89
|
+
}
|
|
90
|
+
/** Start a fresh run from `idle` or `gameover`. Preserves `highScore` and
|
|
91
|
+
* the current `fieldWidth` so resizes during gameover persist into the
|
|
92
|
+
* next run. */
|
|
93
|
+
export function startRun(state) {
|
|
94
|
+
return {
|
|
95
|
+
...initialState(state.highScore, state.fieldWidth),
|
|
96
|
+
phase: { kind: "running" },
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** Snap to the ground and stop the world. Called from the panel's
|
|
100
|
+
* `freeze()` so a long agent turn does not leave the dino hanging
|
|
101
|
+
* mid-jump. */
|
|
102
|
+
export function freezeRun(state) {
|
|
103
|
+
if (state.phase.kind === "frozen" || state.phase.kind === "idle")
|
|
104
|
+
return state;
|
|
105
|
+
return {
|
|
106
|
+
...state,
|
|
107
|
+
phase: { kind: "frozen" },
|
|
108
|
+
dinoY: 0,
|
|
109
|
+
dinoVy: 0,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** Decide what should happen when the user re-expands the dino panel
|
|
113
|
+
* while a run is in progress. Three outcomes:
|
|
114
|
+
* - "countdown": agent-induced freeze → run the 3-2-1 + grace gap.
|
|
115
|
+
* - "run": user-induced collapse → instant resume.
|
|
116
|
+
* - "noop": nothing in flight (idle/gameover/countdown/grace/running).
|
|
117
|
+
* Extracted as a pure helper so the panel's toggle flow is unit-testable
|
|
118
|
+
* without spinning up a CliRenderer. */
|
|
119
|
+
export function expandResumeKind(phase, frozenByAgent) {
|
|
120
|
+
if (phase.kind !== "frozen")
|
|
121
|
+
return "noop";
|
|
122
|
+
return frozenByAgent ? "countdown" : "run";
|
|
123
|
+
}
|
|
124
|
+
/** Begin the 3-2-1 countdown after an automatic freeze ends. The countdown
|
|
125
|
+
* itself counts down by tick in `tick.ts` so this just seeds the phase. */
|
|
126
|
+
export function beginCountdown(state, ticksPerSecond) {
|
|
127
|
+
return {
|
|
128
|
+
...state,
|
|
129
|
+
phase: { kind: "countdown", ticksRemaining: ticksPerSecond * 3 },
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/** Transition from countdown into the grace gap. The grace gap pushes any
|
|
133
|
+
* obstacle inside `GRACE_DISTANCE_CELLS` of the dino's column out to the
|
|
134
|
+
* far edge of the grace window so the run resumes without an unfair hit. */
|
|
135
|
+
export function beginGrace(state) {
|
|
136
|
+
const graceEdge = DINO_X + GRACE_DISTANCE_CELLS;
|
|
137
|
+
const shifted = state.obstacles.map((o) => (o.x < graceEdge ? { ...o, x: graceEdge + 2 } : o));
|
|
138
|
+
return {
|
|
139
|
+
...state,
|
|
140
|
+
obstacles: shifted,
|
|
141
|
+
phase: { kind: "grace" },
|
|
142
|
+
graceCellsLeft: GRACE_DISTANCE_CELLS,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export function endRunOnHit(state) {
|
|
146
|
+
const finalScore = Math.floor(state.score);
|
|
147
|
+
return {
|
|
148
|
+
...state,
|
|
149
|
+
phase: { kind: "gameover" },
|
|
150
|
+
highScore: Math.max(state.highScore, finalScore),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export function isWorldAdvancing(phase) {
|
|
154
|
+
return phase.kind === "running" || phase.kind === "grace";
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../../src/tui/dino/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type GameState } from "./state.js";
|
|
2
|
+
export interface TickDeps {
|
|
3
|
+
/** Returns a float in [0, 1). Injected so tests can seed the spawner. */
|
|
4
|
+
random: () => number;
|
|
5
|
+
/** Ticks per second the panel is calling us at; used to step the
|
|
6
|
+
* countdown phase down in wall-clock-aligned increments. */
|
|
7
|
+
ticksPerSecond: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function tick(state: GameState, deps: TickDeps): GameState;
|
|
10
|
+
//# sourceMappingURL=tick.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tick.d.ts","sourceRoot":"","sources":["../../../../src/tui/dino/tick.ts"],"names":[],"mappings":"AAIA,OAAO,EAYL,KAAK,SAAS,EAEf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,QAAQ;IACvB,yEAAyE;IACzE,MAAM,EAAE,MAAM,MAAM,CAAC;IACrB;iEAC6D;IAC7D,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,CA4HhE"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// One physics tick. Pure: takes current state + a random source and the
|
|
2
|
+
// per-tick cadence, returns the next state. The panel owns the timer that
|
|
3
|
+
// calls this; tests call it directly with a seeded RNG.
|
|
4
|
+
import { BASE_SPEED, DINO_X, FIRST_OBSTACLE_MAX_DISTANCE, GRAVITY, MAX_EXTRA_GAP, MAX_SPEED, MIN_OBSTACLE_GAP, SCORE_PER_TICK, beginGrace, endRunOnHit, isWorldAdvancing, } from "./state.js";
|
|
5
|
+
export function tick(state, deps) {
|
|
6
|
+
if (state.phase.kind === "countdown") {
|
|
7
|
+
const ticksRemaining = state.phase.ticksRemaining - 1;
|
|
8
|
+
if (ticksRemaining <= 0) {
|
|
9
|
+
// Countdown finished; enter the grace gap. `beginGrace` shifts any
|
|
10
|
+
// nearby obstacles to the edge of the grace window so the dino does
|
|
11
|
+
// not wake up onto a cactus.
|
|
12
|
+
return beginGrace(state);
|
|
13
|
+
}
|
|
14
|
+
return { ...state, phase: { kind: "countdown", ticksRemaining } };
|
|
15
|
+
}
|
|
16
|
+
if (state.phase.kind === "idle" ||
|
|
17
|
+
state.phase.kind === "gameover" ||
|
|
18
|
+
state.phase.kind === "frozen") {
|
|
19
|
+
return state;
|
|
20
|
+
}
|
|
21
|
+
// Physics for running / grace. The dino integrates regardless so a jump
|
|
22
|
+
// initiated mid-grace still arcs correctly.
|
|
23
|
+
const nextDinoVy = state.dinoVy - GRAVITY;
|
|
24
|
+
let nextDinoY = state.dinoY + state.dinoVy;
|
|
25
|
+
let landedVy = nextDinoVy;
|
|
26
|
+
if (nextDinoY <= 0) {
|
|
27
|
+
nextDinoY = 0;
|
|
28
|
+
landedVy = 0;
|
|
29
|
+
}
|
|
30
|
+
// World scroll. Running ticks accumulate score and ramp speed; grace
|
|
31
|
+
// ticks scroll obstacles by but score stays pinned (preventing pause
|
|
32
|
+
// farming) and the speed ramp is paused too.
|
|
33
|
+
const advancingWorld = isWorldAdvancing(state.phase);
|
|
34
|
+
const nextSpeed = state.phase.kind === "running"
|
|
35
|
+
? Math.min(MAX_SPEED, BASE_SPEED + state.score * 0.0008)
|
|
36
|
+
: state.speed;
|
|
37
|
+
const scroll = advancingWorld ? nextSpeed : 0;
|
|
38
|
+
let nextObstacles = state.obstacles
|
|
39
|
+
.map((o) => ({ ...o, x: o.x - scroll }))
|
|
40
|
+
.filter((o) => o.x > -2);
|
|
41
|
+
// Spawner. Decrements the countdown to the next spawn by the scroll
|
|
42
|
+
// distance, then drops an obstacle at the right edge when it hits zero.
|
|
43
|
+
let cellsUntilNextSpawn = state.cellsUntilNextSpawn - scroll;
|
|
44
|
+
if (advancingWorld && cellsUntilNextSpawn <= 0) {
|
|
45
|
+
// Spawn at the live right edge for every obstacle except the first
|
|
46
|
+
// of a run. For the very first obstacle (no existing obstacles) we
|
|
47
|
+
// clamp the spawn to a sensible distance ahead of the dino so wide
|
|
48
|
+
// terminals don't make the player wait 20+ seconds for anything to
|
|
49
|
+
// appear. Narrow screens fall back to the right edge because the
|
|
50
|
+
// cap is already past it. After the first spawn the obstacle list
|
|
51
|
+
// is never empty during a run (the next spawn fires long before the
|
|
52
|
+
// previous obstacle scrolls off), so this naturally only fires once.
|
|
53
|
+
const isFirstSpawnOfRun = nextObstacles.length === 0;
|
|
54
|
+
const spawnX = isFirstSpawnOfRun
|
|
55
|
+
? Math.min(state.fieldWidth, DINO_X + FIRST_OBSTACLE_MAX_DISTANCE)
|
|
56
|
+
: state.fieldWidth;
|
|
57
|
+
nextObstacles = [...nextObstacles, { x: spawnX, height: 1 }];
|
|
58
|
+
cellsUntilNextSpawn = MIN_OBSTACLE_GAP + deps.random() * MAX_EXTRA_GAP;
|
|
59
|
+
}
|
|
60
|
+
// Collision: only during `running`. The grace phase explicitly ignores
|
|
61
|
+
// collisions for `graceCellsLeft` cells so the resume is fair. The
|
|
62
|
+
// hitbox is narrower than the rendered sprite (which is 4 cells wide
|
|
63
|
+
// with a blank leading column) so collisions feel like Chrome's dino:
|
|
64
|
+
// forgiving on the edges, honest in the middle. dx covers the body
|
|
65
|
+
// columns DINO_X+1..DINO_X+2 where the actual ink lives.
|
|
66
|
+
const collided = state.phase.kind === "running" &&
|
|
67
|
+
nextObstacles.some((o) => {
|
|
68
|
+
const dx = o.x - DINO_X;
|
|
69
|
+
return dx > 0 && dx < 3 && nextDinoY < o.height;
|
|
70
|
+
});
|
|
71
|
+
if (collided) {
|
|
72
|
+
return endRunOnHit({
|
|
73
|
+
...state,
|
|
74
|
+
obstacles: nextObstacles,
|
|
75
|
+
dinoY: nextDinoY,
|
|
76
|
+
dinoVy: landedVy,
|
|
77
|
+
speed: nextSpeed,
|
|
78
|
+
cellsUntilNextSpawn,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Grace transition back to running once enough cells have scrolled.
|
|
82
|
+
if (state.phase.kind === "grace") {
|
|
83
|
+
const graceCellsLeft = state.graceCellsLeft - scroll;
|
|
84
|
+
if (graceCellsLeft <= 0) {
|
|
85
|
+
return {
|
|
86
|
+
...state,
|
|
87
|
+
phase: { kind: "running" },
|
|
88
|
+
obstacles: nextObstacles,
|
|
89
|
+
dinoY: nextDinoY,
|
|
90
|
+
dinoVy: landedVy,
|
|
91
|
+
speed: nextSpeed,
|
|
92
|
+
graceCellsLeft: 0,
|
|
93
|
+
cellsUntilNextSpawn,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
obstacles: nextObstacles,
|
|
99
|
+
dinoY: nextDinoY,
|
|
100
|
+
dinoVy: landedVy,
|
|
101
|
+
speed: nextSpeed,
|
|
102
|
+
graceCellsLeft,
|
|
103
|
+
cellsUntilNextSpawn,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Plain running tick.
|
|
107
|
+
return {
|
|
108
|
+
...state,
|
|
109
|
+
obstacles: nextObstacles,
|
|
110
|
+
dinoY: nextDinoY,
|
|
111
|
+
dinoVy: landedVy,
|
|
112
|
+
speed: nextSpeed,
|
|
113
|
+
score: state.score + SCORE_PER_TICK * (nextSpeed / BASE_SPEED),
|
|
114
|
+
cellsUntilNextSpawn,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=tick.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tick.js","sourceRoot":"","sources":["../../../../src/tui/dino/tick.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../../../src/tui/dino/visibility.ts"],"names":[],"mappings":"AAcA,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAGlF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Pure visibility rule for the dino panel. Lives in its own file so tests
|
|
2
|
+
// can import it without dragging in OpenTUI (which the panel module
|
|
3
|
+
// pulls in at the top of `./index.ts`). Keeping this rule centralized
|
|
4
|
+
// means a regression that quietly makes the panel visible at rest fails
|
|
5
|
+
// a unit test instead of a manual dogfood pass.
|
|
6
|
+
//
|
|
7
|
+
// Contract:
|
|
8
|
+
// - agent idle → 0 rows (panel is invisible, reserves no
|
|
9
|
+
// vertical space).
|
|
10
|
+
// - agent busy + collapsed → COLLAPSED_ROWS rows (the Ctrl-G hint).
|
|
11
|
+
// - agent busy + expanded → EXPANDED_ROWS rows (the full game).
|
|
12
|
+
import { COLLAPSED_ROWS, EXPANDED_ROWS } from "./render.js";
|
|
13
|
+
export function panelVisibleRowCount(expanded, agentBusy) {
|
|
14
|
+
if (!agentBusy)
|
|
15
|
+
return 0;
|
|
16
|
+
return expanded ? EXPANDED_ROWS : COLLAPSED_ROWS;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility.js","sourceRoot":"","sources":["../../../../src/tui/dino/visibility.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,oEAAoE;AACpE,sEAAsE;AACtE,wEAAwE;AACxE,gDAAgD;AAChD,EAAE;AACF,YAAY;AACZ,yEAAyE;AACzE,kDAAkD;AAClD,wEAAwE;AACxE,qEAAqE;AAErE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,UAAU,oBAAoB,CAAC,QAAiB,EAAE,SAAkB;IACxE,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,CAAC;IACzB,OAAO,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC;AACnD,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CliRenderer, ScrollBoxRenderable, TextareaRenderable } from "@opentui/core";
|
|
2
2
|
import type { AutocompleteController } from "./autocomplete-controller.js";
|
|
3
3
|
import type { CopyController } from "./copy-controller.js";
|
|
4
|
+
import type { DinoPanel } from "./dino/index.js";
|
|
4
5
|
import type { PasteController } from "./paste-controller.js";
|
|
5
6
|
import type { QuestionPicker } from "./question-picker.js";
|
|
6
7
|
import type { StarterSection } from "./starter-section.js";
|
|
@@ -31,6 +32,12 @@ export interface KeyHandlerDeps {
|
|
|
31
32
|
onEscape(): void;
|
|
32
33
|
/** Dispatch the composer text with behavior:"steer" (Ctrl+Enter). */
|
|
33
34
|
onSteer(): void;
|
|
35
|
+
/** Dino "while-you-wait" panel. The panel always owns Ctrl-G, which
|
|
36
|
+
* cycles collapsed → expanded+game-focused → expanded+composer-focused
|
|
37
|
+
* → collapsed. The only game keystroke is ArrowUp; the spacebar is
|
|
38
|
+
* always the composer's so a half-typed follow-up can coexist with
|
|
39
|
+
* the running game. Ctrl-G hands the up-arrow back and forth. */
|
|
40
|
+
dinoPanel: DinoPanel;
|
|
34
41
|
}
|
|
35
42
|
/**
|
|
36
43
|
* Wires up the two keyboard event surfaces the TUI listens on:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-handlers.d.ts","sourceRoot":"","sources":["../../../src/tui/key-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAY,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACpG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAMD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,mBAAmB,CAAC;IAChC,YAAY,EAAE,sBAAsB,CAAC;IACrC,cAAc,EAAE,cAAc,CAAC;IAC/B,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,cAAc,GAAG,SAAS,CAAC;IACrC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,EAAE,qBAAqB,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,IAAI,IAAI,CAAC;IACjB,qEAAqE;IACrE,OAAO,IAAI,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"key-handlers.d.ts","sourceRoot":"","sources":["../../../src/tui/key-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAY,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACpG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAMD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,mBAAmB,CAAC;IAChC,YAAY,EAAE,sBAAsB,CAAC;IACrC,cAAc,EAAE,cAAc,CAAC;IAC/B,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,cAAc,GAAG,SAAS,CAAC;IACrC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,EAAE,qBAAqB,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,IAAI,IAAI,CAAC;IACjB,qEAAqE;IACrE,OAAO,IAAI,IAAI,CAAC;IAChB;;;;sEAIkE;IAClE,SAAS,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CA6N7D"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* sketch and key handling can be reasoned about in one place.
|
|
13
13
|
*/
|
|
14
14
|
export function installKeyHandlers(deps) {
|
|
15
|
-
const { renderer, inputField, transcript, autocomplete, questionPicker, pasteController, copyController, starters, transcriptWriter, escapeState, onSubmit, onEscape, onSteer, } = deps;
|
|
15
|
+
const { renderer, inputField, transcript, autocomplete, questionPicker, pasteController, copyController, starters, transcriptWriter, escapeState, onSubmit, onEscape, onSteer, dinoPanel, } = deps;
|
|
16
16
|
const keyHandler = renderer._keyHandler;
|
|
17
17
|
keyHandler.onInternal("keypress", (key) => {
|
|
18
18
|
transcriptWriter.logKey("global", key);
|
|
@@ -61,6 +61,30 @@ export function installKeyHandlers(deps) {
|
|
|
61
61
|
// fires, so we intercept at the Renderable's onKeyDown hook which runs first.
|
|
62
62
|
inputField.onKeyDown = (key) => {
|
|
63
63
|
transcriptWriter.logKey("keydown", key);
|
|
64
|
+
// Ctrl-G: the dino panel always owns this keystroke regardless of
|
|
65
|
+
// focus, the agent's running state, or whether the composer has
|
|
66
|
+
// typed text. Toggling the panel must never be eaten by autocomplete
|
|
67
|
+
// or starter chrome below.
|
|
68
|
+
if (key.ctrl && (key.name === "g" || key.sequence === "\u0007")) {
|
|
69
|
+
key.preventDefault();
|
|
70
|
+
dinoPanel.toggle();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Forward ArrowUp to the dino panel whenever it is expanded AND
|
|
74
|
+
// game-focused. Spacebar is deliberately not a game key: users
|
|
75
|
+
// frequently type a follow-up while the game keeps running, and
|
|
76
|
+
// letting the composer always own space avoids the awkward case of
|
|
77
|
+
// a stray jump while typing. We deliberately do not gate on
|
|
78
|
+
// `statusController.isRunning()` so the game is fully testable at
|
|
79
|
+
// rest.
|
|
80
|
+
if (dinoPanel.isGameFocused()) {
|
|
81
|
+
if (key.name === "up" && !key.ctrl && !key.meta && !key.super && !key.shift) {
|
|
82
|
+
if (dinoPanel.handleKey(key.name)) {
|
|
83
|
+
key.preventDefault();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
64
88
|
if (key.name === "pageup") {
|
|
65
89
|
scrollByPage(-1);
|
|
66
90
|
key.preventDefault();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-handlers.js","sourceRoot":"","sources":["../../../src/tui/key-handlers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"key-handlers.js","sourceRoot":"","sources":["../../../src/tui/key-handlers.ts"],"names":[],"mappings":"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"}
|
package/dist/src/tui/layout.d.ts
CHANGED
|
@@ -31,6 +31,13 @@ export interface LayoutRefs {
|
|
|
31
31
|
status: TextRenderable;
|
|
32
32
|
/** Single-line hint row showing the active keystrokes (Enter / Esc / copy). */
|
|
33
33
|
hint: TextRenderable;
|
|
34
|
+
/** Mount point for the dino "while-you-wait" game panel. Sits between
|
|
35
|
+
* the hint row and the autocomplete pickers so it never overlaps the
|
|
36
|
+
* input box. The dino factory adds its own rows into this container;
|
|
37
|
+
* layout doesn't reserve a height because the panel sizes itself from
|
|
38
|
+
* its children (12 rows when expanded, 1 when collapsed, 0 when
|
|
39
|
+
* never opened). */
|
|
40
|
+
dinoPanel: BoxRenderable;
|
|
34
41
|
/** Slash + skill autocomplete panel; toggled via `visible` from the autocomplete controller. */
|
|
35
42
|
skillAutocompletePanel: BoxRenderable;
|
|
36
43
|
/** Header row for the "commands" section of the slash/skill picker. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/tui/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,WAAW,EAChB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C;;;;GAIG;AACH,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,IAAI,EAAE,aAAa,CAAC;IACpB,6DAA6D;IAC7D,MAAM,EAAE,aAAa,CAAC;IACtB,qEAAqE;IACrE,OAAO,EAAE,aAAa,CAAC;IACvB;6EACyE;IACzE,gBAAgB,EAAE,aAAa,CAAC;IAChC;oCACgC;IAChC,oBAAoB,EAAE,cAAc,CAAC;IACrC,8FAA8F;IAC9F,UAAU,EAAE,mBAAmB,CAAC;IAChC,0FAA0F;IAC1F,MAAM,EAAE,cAAc,CAAC;IACvB,+EAA+E;IAC/E,IAAI,EAAE,cAAc,CAAC;IACrB,gGAAgG;IAChG,sBAAsB,EAAE,aAAa,CAAC;IACtC,uEAAuE;IACvE,aAAa,EAAE,cAAc,CAAC;IAC9B,iEAAiE;IACjE,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,qEAAqE;IACrE,WAAW,EAAE,cAAc,CAAC;IAC5B,wDAAwD;IACxD,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,kEAAkE;IAClE,qBAAqB,EAAE,aAAa,CAAC;IACrC,oDAAoD;IACpD,qBAAqB,EAAE,cAAc,CAAC;IACtC,uDAAuD;IACvD,oBAAoB,EAAE,cAAc,EAAE,CAAC;IACvC,qFAAqF;IACrF,aAAa,EAAE,aAAa,CAAC;IAC7B,2EAA2E;IAC3E,aAAa,EAAE,cAAc,CAAC;IAC9B,mEAAmE;IACnE,cAAc,EAAE,cAAc,CAAC;IAC/B,uEAAuE;IACvE,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B;;;iEAG6D;IAC7D,aAAa,EAAE,aAAa,CAAC;IAC7B,yEAAyE;IACzE,iBAAiB,EAAE,cAAc,CAAC;IAClC,uEAAuE;IACvE,QAAQ,EAAE,aAAa,CAAC;IACxB,kFAAkF;IAClF,MAAM,EAAE,cAAc,CAAC;IACvB,6EAA6E;IAC7E,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/tui/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,WAAW,EAChB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C;;;;GAIG;AACH,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,IAAI,EAAE,aAAa,CAAC;IACpB,6DAA6D;IAC7D,MAAM,EAAE,aAAa,CAAC;IACtB,qEAAqE;IACrE,OAAO,EAAE,aAAa,CAAC;IACvB;6EACyE;IACzE,gBAAgB,EAAE,aAAa,CAAC;IAChC;oCACgC;IAChC,oBAAoB,EAAE,cAAc,CAAC;IACrC,8FAA8F;IAC9F,UAAU,EAAE,mBAAmB,CAAC;IAChC,0FAA0F;IAC1F,MAAM,EAAE,cAAc,CAAC;IACvB,+EAA+E;IAC/E,IAAI,EAAE,cAAc,CAAC;IACrB;;;;;yBAKqB;IACrB,SAAS,EAAE,aAAa,CAAC;IACzB,gGAAgG;IAChG,sBAAsB,EAAE,aAAa,CAAC;IACtC,uEAAuE;IACvE,aAAa,EAAE,cAAc,CAAC;IAC9B,iEAAiE;IACjE,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,qEAAqE;IACrE,WAAW,EAAE,cAAc,CAAC;IAC5B,wDAAwD;IACxD,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,kEAAkE;IAClE,qBAAqB,EAAE,aAAa,CAAC;IACrC,oDAAoD;IACpD,qBAAqB,EAAE,cAAc,CAAC;IACtC,uDAAuD;IACvD,oBAAoB,EAAE,cAAc,EAAE,CAAC;IACvC,qFAAqF;IACrF,aAAa,EAAE,aAAa,CAAC;IAC7B,2EAA2E;IAC3E,aAAa,EAAE,cAAc,CAAC;IAC9B,mEAAmE;IACnE,cAAc,EAAE,cAAc,CAAC;IAC/B,uEAAuE;IACvE,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B;;;iEAG6D;IAC7D,aAAa,EAAE,aAAa,CAAC;IAC7B,yEAAyE;IACzE,iBAAiB,EAAE,cAAc,CAAC;IAClC,uEAAuE;IACvE,QAAQ,EAAE,aAAa,CAAC;IACxB,kFAAkF;IAClF,MAAM,EAAE,cAAc,CAAC;IACvB,6EAA6E;IAC7E,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,GAAG,UAAU,CAwV7D"}
|
package/dist/src/tui/layout.js
CHANGED
|
@@ -107,6 +107,14 @@ export function buildLayout(renderer) {
|
|
|
107
107
|
flexShrink: 0,
|
|
108
108
|
selectable: false,
|
|
109
109
|
});
|
|
110
|
+
// Container for the dino game panel. The dino factory mounts its own
|
|
111
|
+
// row pool into this container; we keep it as a bare BoxRenderable so
|
|
112
|
+
// the dino module can own its sizing without layout having to know
|
|
113
|
+
// anything about the game.
|
|
114
|
+
const dinoPanel = new BoxRenderable(renderer, {
|
|
115
|
+
flexDirection: "column",
|
|
116
|
+
flexShrink: 0,
|
|
117
|
+
});
|
|
110
118
|
const skillAutocompletePanel = new BoxRenderable(renderer, {
|
|
111
119
|
flexDirection: "column",
|
|
112
120
|
border: true,
|
|
@@ -295,6 +303,7 @@ export function buildLayout(renderer) {
|
|
|
295
303
|
layout.add(transcriptFrame);
|
|
296
304
|
layout.add(status);
|
|
297
305
|
layout.add(hint);
|
|
306
|
+
layout.add(dinoPanel);
|
|
298
307
|
layout.add(skillAutocompletePanel);
|
|
299
308
|
layout.add(fileAutocompletePanel);
|
|
300
309
|
layout.add(questionPanel);
|
|
@@ -313,6 +322,7 @@ export function buildLayout(renderer) {
|
|
|
313
322
|
transcript,
|
|
314
323
|
status,
|
|
315
324
|
hint,
|
|
325
|
+
dinoPanel,
|
|
316
326
|
skillAutocompletePanel,
|
|
317
327
|
commandHeader,
|
|
318
328
|
commandRows,
|