@noodleseed/one 0.109.0 → 0.110.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/deploy-ops.d.ts +0 -1
- package/dist/commands/deploy-ops.d.ts.map +1 -1
- package/dist/commands/deploy-ops.js +6 -42
- package/dist/commands/deploy-ops.js.map +1 -1
- package/dist/commands/project-setup.d.ts.map +1 -1
- package/dist/commands/project-setup.js +0 -4
- package/dist/commands/project-setup.js.map +1 -1
- package/dist/first-run.d.ts.map +1 -1
- package/dist/first-run.js +0 -3
- package/dist/first-run.js.map +1 -1
- package/node_modules/@noodle-borg/control-plane/dist/contracts.d.ts +210 -0
- package/node_modules/@noodle-borg/control-plane/dist/contracts.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/contracts.js +2 -0
- package/node_modules/@noodle-borg/control-plane/dist/contracts.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/index.d.ts +6 -0
- package/node_modules/@noodle-borg/control-plane/dist/index.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/index.js +4 -0
- package/node_modules/@noodle-borg/control-plane/dist/index.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-contracts.d.ts +11 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-contracts.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-contracts.js +2 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-contracts.js.map +1 -0
- package/node_modules/@noodle-borg/{service/dist/store/postgres-control-plane.d.ts → control-plane/dist/postgres-organization-store.d.ts} +4 -3
- package/node_modules/@noodle-borg/control-plane/dist/postgres-organization-store.d.ts.map +1 -0
- package/node_modules/@noodle-borg/{service/dist/store/postgres-control-plane.js → control-plane/dist/postgres-organization-store.js} +4 -5
- package/node_modules/@noodle-borg/control-plane/dist/postgres-organization-store.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.d.ts +4 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.js +88 -0
- package/node_modules/@noodle-borg/control-plane/dist/postgres-schema.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/validation.d.ts +16 -0
- package/node_modules/@noodle-borg/control-plane/dist/validation.d.ts.map +1 -0
- package/node_modules/@noodle-borg/control-plane/dist/validation.js +87 -0
- package/node_modules/@noodle-borg/control-plane/dist/validation.js.map +1 -0
- package/node_modules/@noodle-borg/control-plane/package.json +30 -0
- package/node_modules/@noodle-borg/service/dist/platform-auth-operator.d.ts +10 -10
- package/node_modules/@noodle-borg/service/dist/store/postgres-deploy-records.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-deploy-records.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-schema.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js +2 -84
- package/node_modules/@noodle-borg/service/dist/store/postgres-schema.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-signup.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres.js +3 -2
- package/node_modules/@noodle-borg/service/dist/store/postgres.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.d.ts +2 -20
- package/node_modules/@noodle-borg/service/dist/store/validate.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store/validate.js +7 -85
- package/node_modules/@noodle-borg/service/dist/store/validate.js.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.d.ts +3 -208
- package/node_modules/@noodle-borg/service/dist/store.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/store.js.map +1 -1
- package/node_modules/@noodle-borg/service/package.json +1 -0
- package/package.json +2 -1
- package/dist/banner.d.ts +0 -11
- package/dist/banner.d.ts.map +0 -1
- package/dist/banner.js +0 -183
- package/dist/banner.js.map +0 -1
- package/dist/commands/deploy-fire-progress.d.ts +0 -28
- package/dist/commands/deploy-fire-progress.d.ts.map +0 -1
- package/dist/commands/deploy-fire-progress.js +0 -64
- package/dist/commands/deploy-fire-progress.js.map +0 -1
- package/dist/fire.d.ts +0 -108
- package/dist/fire.d.ts.map +0 -1
- package/dist/fire.js +0 -511
- package/dist/fire.js.map +0 -1
- package/dist/flavor.d.ts +0 -19
- package/dist/flavor.d.ts.map +0 -1
- package/dist/flavor.js +0 -105
- package/dist/flavor.js.map +0 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.d.ts.map +0 -1
- package/node_modules/@noodle-borg/service/dist/store/postgres-control-plane.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deploy-fire-progress.js","sourceRoot":"","sources":["../../src/commands/deploy-fire-progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,UAAU,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,kGAAkG;AAElG;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAKnC;IACC,OAAO,CACL,CAAC,IAAI,CAAC,IAAI;QACV,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS;QACzB,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS;QAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;QAC1B,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,MAAM;QACvC,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI;QACzB,IAAI,CAAC,GAAG,CAAC,cAAc,KAAK,SAAS,CACtC,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAkC;IACpD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,GAAG;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IAClD,OAAQ,KAAiB,CAAC,GAAG,CAAC;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAkB,EAAE,IAA0B;IAChF,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,cAAc,GAAW,UAAU,CAAC,MAAM,CAAC;IAC/C,MAAM,OAAO,GAAG,KAAK,EACnB,KAAkC,EAClC,IAAkC,EACR,EAAE;QAC5B,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;QACtD,MAAM,QAAQ,GACZ,CAAC,YAAY,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;QACnF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,YAAY,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,WAAW,EAAE,CAAC;YAChB,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC;YACnC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACnC,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,cAAc,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC;YAC7D,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,OAAuB,CAAC;AACjC,CAAC"}
|
package/dist/fire.d.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { type ColorMode, type GlyphMode, type RGB } from './gradient.js';
|
|
2
|
-
export type FireMode = 'warm' | 'green' | 'rose';
|
|
3
|
-
/** Heat (0..1) through the mode's gradient stops, evenly spaced and linearly interpolated. */
|
|
4
|
-
export declare function fireColor(h: number, mode: FireMode): RGB;
|
|
5
|
-
/** Heat (0..1) quantized to one of 5 density glyphs (Unicode blocks, or an ASCII fallback). */
|
|
6
|
-
export declare function glyphFor(h: number, glyph: GlyphMode): string;
|
|
7
|
-
export type HeatGrid = readonly (readonly number[])[];
|
|
8
|
-
export declare function createGrid(rows: number, cols: number): HeatGrid;
|
|
9
|
-
/**
|
|
10
|
-
* Advance the grid one tick: heat flows up by exactly one row per call (row `y`'s new value comes
|
|
11
|
-
* from the *previous* frame's row `y+1`, or `sources` for the bottom-most row), with a jittered
|
|
12
|
-
* lateral drift and a jittered decay — both index/tick-hashed, so `advanceHeat` is a pure function
|
|
13
|
-
* of its inputs (same grid + sources + tick always produces the same next grid).
|
|
14
|
-
*/
|
|
15
|
-
export declare function advanceHeat(grid: HeatGrid, sources: readonly number[], tick: number): HeatGrid;
|
|
16
|
-
export type Stage = 'compile' | 'assets' | 'upload' | 'activate' | 'live';
|
|
17
|
-
/** x-fraction (0..1) along the band each pipeline stage's milestone tick sits at. */
|
|
18
|
-
export declare const MILESTONES: Readonly<Record<Stage, number>>;
|
|
19
|
-
export declare const MILESTONE_ORDER: readonly Stage[];
|
|
20
|
-
/**
|
|
21
|
-
* The stage currently in flight (used to pick the flavor line): the window between two milestones
|
|
22
|
-
* belongs to the *later* one — e.g. `[0.16, 0.30)` is "checking assets", not "still compiling" —
|
|
23
|
-
* so each threshold below is the *previous* milestone, not the stage's own.
|
|
24
|
-
*/
|
|
25
|
-
export declare function stageForProgress(progress: number): Stage;
|
|
26
|
-
/** The column a milestone x-fraction lands on for a given band width. */
|
|
27
|
-
export declare function milestoneCol(position: number, cols: number): number;
|
|
28
|
-
/** A milestone-crossing flare: a short-lived additive heat boost centered on `col`, aging each tick. */
|
|
29
|
-
export interface FlareState {
|
|
30
|
-
readonly col: number;
|
|
31
|
-
readonly ageTicks: number;
|
|
32
|
-
}
|
|
33
|
-
/** ~1.1s of decay at `FRAME_MS` — exported so tests and the renderer share one duration. */
|
|
34
|
-
export declare const FLARE_DURATION_TICKS: number;
|
|
35
|
-
export type FirePhase = 'progress' | 'success' | 'failure';
|
|
36
|
-
export interface FireZoneState {
|
|
37
|
-
readonly cols: number;
|
|
38
|
-
readonly tick: number;
|
|
39
|
-
/**
|
|
40
|
-
* Ticks since the current end phase (`success`/`failure`) began — NOT the global tick. The failure
|
|
41
|
-
* spread is computed from this, so a deploy that dies late still bleeds rose outward gradually
|
|
42
|
-
* instead of instantly owning the band. Defaults to 0 when omitted (spread not yet started).
|
|
43
|
-
*/
|
|
44
|
-
readonly phaseTick?: number;
|
|
45
|
-
readonly frontCol: number;
|
|
46
|
-
readonly phase: FirePhase;
|
|
47
|
-
/** Column the deploy died at; only meaningful (and required) once `phase === 'failure'`. */
|
|
48
|
-
readonly deathCol?: number;
|
|
49
|
-
readonly flare?: FlareState;
|
|
50
|
-
}
|
|
51
|
-
/** Heat sources injected on the virtual row below the band, one per column, for this tick's zone state. */
|
|
52
|
-
export declare function sourcesFor(state: FireZoneState): number[];
|
|
53
|
-
export interface FireFrameInput {
|
|
54
|
-
readonly grid: HeatGrid;
|
|
55
|
-
readonly cols: number;
|
|
56
|
-
readonly progress: number;
|
|
57
|
-
readonly mode: FireMode;
|
|
58
|
-
readonly color: ColorMode;
|
|
59
|
-
readonly glyph: GlyphMode;
|
|
60
|
-
/** Pre-rendered ✔-checklist lines drawn above the band (the approved layout), or omit. */
|
|
61
|
-
readonly headerLines?: readonly string[];
|
|
62
|
-
/** Pre-rendered flavor line, or `undefined` to omit it entirely. */
|
|
63
|
-
readonly flavorLine?: string;
|
|
64
|
-
/** Pre-rendered "press enter to close" hint, or `undefined` while not yet holding. */
|
|
65
|
-
readonly dismissHint?: string;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* The labeled stage track from the approved frames: `compile —— assets —— upload ——— activate —— live`,
|
|
69
|
-
* label starts anchored to their milestone columns, dashes filling the gaps. Passed stages read amber,
|
|
70
|
-
* the road ahead dim.
|
|
71
|
-
*/
|
|
72
|
-
export declare function renderStageLabelRow(progress: number, cols: number, color: ColorMode, glyph: GlyphMode): string;
|
|
73
|
-
/** Build one frame's lines: checklist header, grid rows, milestone ticks + labels, flavor/dismiss. */
|
|
74
|
-
export declare function renderFireFrame(input: FireFrameInput): readonly string[];
|
|
75
|
-
export interface DeployFireOptions {
|
|
76
|
-
readonly stream: NodeJS.WriteStream;
|
|
77
|
-
/** Enables Enter/Ctrl-C dismissal on success; failure and non-TTY runs settle immediately. */
|
|
78
|
-
readonly stdin?: (NodeJS.ReadStream & {
|
|
79
|
-
isRaw?: boolean;
|
|
80
|
-
}) | undefined;
|
|
81
|
-
readonly frameMs?: number;
|
|
82
|
-
readonly rows?: number;
|
|
83
|
-
readonly cols?: number;
|
|
84
|
-
/** Entrypoint shown on the checklist's compile line (e.g. `server.ts`). */
|
|
85
|
-
readonly entrypointLabel?: string;
|
|
86
|
-
}
|
|
87
|
-
export interface DeployFireController {
|
|
88
|
-
/** Advance progress along the pipeline (0..1); crossing a milestone pushes a decaying flare. */
|
|
89
|
-
setProgress(progress: number): void;
|
|
90
|
-
/** Green end-state + simmer + hold; `lines` join the ✔ checklist (e.g. Activated / Live: url). */
|
|
91
|
-
succeed(opts?: {
|
|
92
|
-
readonly lines?: readonly string[];
|
|
93
|
-
}): Promise<void>;
|
|
94
|
-
/** Final rose frame; `line` becomes the ✗ checklist entry before recovery output prints. */
|
|
95
|
-
fail(opts?: {
|
|
96
|
-
readonly line?: string;
|
|
97
|
-
}): Promise<void>;
|
|
98
|
-
/** Stop immediately with no end-state and no hold (e.g. pausing for an interactive secret prompt). */
|
|
99
|
-
stop(): void;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Drive the fire band on `stream`. Assumes the caller has already decided this run is eligible
|
|
103
|
-
* (interactive, colored, not `--json`, not `NOODLE_NO_FIRE`) — this function independently derives
|
|
104
|
-
* color from `stream` too, and renders nothing at all when that resolves to `'none'`, so it is safe
|
|
105
|
-
* to call directly in tests without re-deriving the outer gate.
|
|
106
|
-
*/
|
|
107
|
-
export declare function runDeployFire(opts: DeployFireOptions): DeployFireController;
|
|
108
|
-
//# sourceMappingURL=fire.d.ts.map
|
package/dist/fire.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fire.d.ts","sourceRoot":"","sources":["../src/fire.ts"],"names":[],"mappings":"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"}
|
package/dist/fire.js
DELETED
|
@@ -1,511 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `noodle deploy` fire animation: a cell-grid heat band (classic demoscene fire propagation)
|
|
3
|
-
* whose x-axis maps deploy progress. Split in two halves, both in this one file per the approved
|
|
4
|
-
* design: a pure engine (heat propagation, zone sourcing, palette, glyph quantization — fully
|
|
5
|
-
* unit-testable without a TTY) and a renderer (`runDeployFire`) that repaints it in place on a
|
|
6
|
-
* real stream, reusing the HIDE_CURSOR/cursorUp/CLEAR_EOL conventions `watch.ts`/`status.ts`
|
|
7
|
-
* already established.
|
|
8
|
-
*
|
|
9
|
-
* Semantics: position = pipeline. `MILESTONES` places compile/assets/upload/activate/live at fixed
|
|
10
|
-
* x-fractions, drawn as tick marks on a track row under the band (bright once passed, dim ahead).
|
|
11
|
-
* Settled territory burns as a calm ember bed; the 7-column working front is a blazing crest;
|
|
12
|
-
* territory ahead stays dark except for faint sparks within 2 columns of the front. Crossing a
|
|
13
|
-
* milestone pushes a short decaying flare. An indeterminate wait (e.g. service-side activation)
|
|
14
|
-
* holds the front in place and burns there — it never fake-advances.
|
|
15
|
-
*
|
|
16
|
-
* Success converts the whole bed to a simmering green fire and, on a full interactive TTY
|
|
17
|
-
* (`stdin.isTTY` as well as the color stream), holds until the user dismisses it (Enter or Ctrl-C).
|
|
18
|
-
* Failure paints a final rose frame and returns immediately so the caller's recovery diagnostics are
|
|
19
|
-
* never gated behind animation dismissal. Headless/non-TTY runs always settle immediately.
|
|
20
|
-
*
|
|
21
|
-
* Determinism: every stochastic-looking element (flicker, drift, decay, sparks) is derived from a
|
|
22
|
-
* cheap integer hash of `(x, y, tick)` — never `Math.random` — so the same tick always paints the
|
|
23
|
-
* same grid and the whole suite can run under fake timers with no real waits.
|
|
24
|
-
*/
|
|
25
|
-
import { emitKeypressEvents } from 'node:readline';
|
|
26
|
-
import { dimText } from './commands/resource-shared.js';
|
|
27
|
-
import { createFlavorSeed, renderFlavorLine } from './flavor.js';
|
|
28
|
-
import { AMBER, CLEAR_EOL, cursorUp, detectColorMode, detectGlyphMode, HIDE_CURSOR, mix, ORANGE, paint, ROSE, SHOW_CURSOR, } from './gradient.js';
|
|
29
|
-
const CR = String.fromCharCode(13);
|
|
30
|
-
const NL = String.fromCharCode(10);
|
|
31
|
-
/** Repaint cadence — matches `status.ts`'s spinner `FRAME_MS` so the two animations feel like one system. */
|
|
32
|
-
const FRAME_MS = 80;
|
|
33
|
-
const DEFAULT_ROWS = 7;
|
|
34
|
-
const DEFAULT_COLS = 80;
|
|
35
|
-
const MIN_COLS = 20;
|
|
36
|
-
const GREEN = [34, 197, 94];
|
|
37
|
-
const WARM_STOPS = [[26, 10, 10], ROSE, ORANGE, AMBER, [255, 244, 210]];
|
|
38
|
-
const GREEN_STOPS = [[6, 24, 14], GREEN, [214, 255, 224]];
|
|
39
|
-
const ROSE_STOPS = [[30, 8, 14], ROSE, [255, 214, 224]];
|
|
40
|
-
function stopsFor(mode) {
|
|
41
|
-
if (mode === 'green')
|
|
42
|
-
return GREEN_STOPS;
|
|
43
|
-
if (mode === 'rose')
|
|
44
|
-
return ROSE_STOPS;
|
|
45
|
-
return WARM_STOPS;
|
|
46
|
-
}
|
|
47
|
-
/** Heat (0..1) through the mode's gradient stops, evenly spaced and linearly interpolated. */
|
|
48
|
-
export function fireColor(h, mode) {
|
|
49
|
-
const stops = stopsFor(mode);
|
|
50
|
-
const clamped = clamp01(h);
|
|
51
|
-
const segment = 1 / (stops.length - 1);
|
|
52
|
-
const index = Math.min(stops.length - 2, Math.floor(clamped / segment));
|
|
53
|
-
const t = (clamped - index * segment) / segment;
|
|
54
|
-
return mix(stops[index], stops[index + 1], t);
|
|
55
|
-
}
|
|
56
|
-
const GLYPHS_UNICODE = [' ', '░', '▒', '▓', '█'];
|
|
57
|
-
const GLYPHS_ASCII = [' ', '.', ':', '*', '#'];
|
|
58
|
-
/** Heat (0..1) quantized to one of 5 density glyphs (Unicode blocks, or an ASCII fallback). */
|
|
59
|
-
export function glyphFor(h, glyph) {
|
|
60
|
-
const idx = Math.min(4, Math.floor(clamp01(h) * 5));
|
|
61
|
-
return (glyph === 'ascii' ? GLYPHS_ASCII : GLYPHS_UNICODE)[idx];
|
|
62
|
-
}
|
|
63
|
-
function clamp01(v) {
|
|
64
|
-
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
65
|
-
}
|
|
66
|
-
function clampInt(v, lo, hi) {
|
|
67
|
-
return v < lo ? lo : v > hi ? hi : v;
|
|
68
|
-
}
|
|
69
|
-
// --- deterministic noise -------------------------------------------------------------------------
|
|
70
|
-
/** Cheap deterministic 2D+time hash to [0,1) — never `Math.random`, so a tick always repaints identically. */
|
|
71
|
-
function hash01(x, y, tick) {
|
|
72
|
-
let h = (x * 374761393 + y * 668265263 + tick * 974634) | 0;
|
|
73
|
-
h = Math.imul(h ^ (h >>> 13), 1274126177);
|
|
74
|
-
h ^= h >>> 16;
|
|
75
|
-
return (h >>> 0) / 4294967295;
|
|
76
|
-
}
|
|
77
|
-
export function createGrid(rows, cols) {
|
|
78
|
-
return Array.from({ length: rows }, () => new Array(cols).fill(0));
|
|
79
|
-
}
|
|
80
|
-
const MIN_DECAY = 0.08;
|
|
81
|
-
const DECAY_JITTER = 0.07;
|
|
82
|
-
/**
|
|
83
|
-
* Advance the grid one tick: heat flows up by exactly one row per call (row `y`'s new value comes
|
|
84
|
-
* from the *previous* frame's row `y+1`, or `sources` for the bottom-most row), with a jittered
|
|
85
|
-
* lateral drift and a jittered decay — both index/tick-hashed, so `advanceHeat` is a pure function
|
|
86
|
-
* of its inputs (same grid + sources + tick always produces the same next grid).
|
|
87
|
-
*/
|
|
88
|
-
export function advanceHeat(grid, sources, tick) {
|
|
89
|
-
const rows = grid.length;
|
|
90
|
-
const cols = sources.length;
|
|
91
|
-
const next = new Array(rows);
|
|
92
|
-
for (let y = 0; y < rows; y++) {
|
|
93
|
-
const below = y === rows - 1 ? sources : grid[y + 1];
|
|
94
|
-
const row = new Array(cols);
|
|
95
|
-
for (let x = 0; x < cols; x++) {
|
|
96
|
-
const drift = Math.floor(hash01(x, y, tick) * 3) - 1; // -1, 0, or 1
|
|
97
|
-
const sx = clampInt(x + drift, 0, cols - 1);
|
|
98
|
-
const decay = MIN_DECAY + hash01(x, y + 101, tick) * DECAY_JITTER;
|
|
99
|
-
row[x] = clamp01(below[sx] - decay);
|
|
100
|
-
}
|
|
101
|
-
next[y] = row;
|
|
102
|
-
}
|
|
103
|
-
return next;
|
|
104
|
-
}
|
|
105
|
-
/** x-fraction (0..1) along the band each pipeline stage's milestone tick sits at. */
|
|
106
|
-
export const MILESTONES = {
|
|
107
|
-
compile: 0.16,
|
|
108
|
-
assets: 0.3,
|
|
109
|
-
upload: 0.68,
|
|
110
|
-
activate: 0.88,
|
|
111
|
-
live: 1,
|
|
112
|
-
};
|
|
113
|
-
export const MILESTONE_ORDER = [
|
|
114
|
-
'compile',
|
|
115
|
-
'assets',
|
|
116
|
-
'upload',
|
|
117
|
-
'activate',
|
|
118
|
-
'live',
|
|
119
|
-
];
|
|
120
|
-
/**
|
|
121
|
-
* The stage currently in flight (used to pick the flavor line): the window between two milestones
|
|
122
|
-
* belongs to the *later* one — e.g. `[0.16, 0.30)` is "checking assets", not "still compiling" —
|
|
123
|
-
* so each threshold below is the *previous* milestone, not the stage's own.
|
|
124
|
-
*/
|
|
125
|
-
export function stageForProgress(progress) {
|
|
126
|
-
if (progress >= MILESTONES.live)
|
|
127
|
-
return 'live';
|
|
128
|
-
if (progress >= MILESTONES.upload)
|
|
129
|
-
return 'activate'; // [0.68, 1.0): sending + awaiting activation
|
|
130
|
-
if (progress >= MILESTONES.assets)
|
|
131
|
-
return 'upload';
|
|
132
|
-
if (progress >= MILESTONES.compile)
|
|
133
|
-
return 'assets';
|
|
134
|
-
return 'compile';
|
|
135
|
-
}
|
|
136
|
-
/** The column a milestone x-fraction lands on for a given band width. */
|
|
137
|
-
export function milestoneCol(position, cols) {
|
|
138
|
-
return Math.round(clamp01(position) * Math.max(1, cols - 1));
|
|
139
|
-
}
|
|
140
|
-
/** ~1.1s of decay at `FRAME_MS` — exported so tests and the renderer share one duration. */
|
|
141
|
-
export const FLARE_DURATION_TICKS = Math.round(1100 / FRAME_MS);
|
|
142
|
-
const FLARE_RADIUS_COLS = 4;
|
|
143
|
-
const FLARE_PEAK = 0.35;
|
|
144
|
-
function flareBoost(x, flare) {
|
|
145
|
-
if (flare === undefined || flare.ageTicks > FLARE_DURATION_TICKS)
|
|
146
|
-
return 0;
|
|
147
|
-
const distance = Math.abs(x - flare.col);
|
|
148
|
-
if (distance > FLARE_RADIUS_COLS)
|
|
149
|
-
return 0;
|
|
150
|
-
const spatialFalloff = 1 - distance / FLARE_RADIUS_COLS;
|
|
151
|
-
const timeFalloff = 1 - flare.ageTicks / FLARE_DURATION_TICKS;
|
|
152
|
-
return FLARE_PEAK * spatialFalloff * timeFalloff;
|
|
153
|
-
}
|
|
154
|
-
const CREST_WIDTH = 7; // the working front: the 7 most-recently-covered columns
|
|
155
|
-
const SPARK_AHEAD_COLS = 2;
|
|
156
|
-
const EMBER_BASE = 0.3;
|
|
157
|
-
const EMBER_AMPLITUDE = 0.06;
|
|
158
|
-
const CREST_BASE = 0.78;
|
|
159
|
-
const CREST_FLICKER = 0.22;
|
|
160
|
-
const SIMMER_BASE = 0.42; // success simmer
|
|
161
|
-
const FAILURE_SIMMER_BASE = 0.4;
|
|
162
|
-
const SIMMER_AMPLITUDE = 0.06;
|
|
163
|
-
// Slowly-evolving taller "structures" over the low bed — the approved frames show block clusters
|
|
164
|
-
// rising from a 1-2 row ember baseline, not a uniform wall. Cluster identity comes from a coarse
|
|
165
|
-
// column bucket and a slow tick bucket, so shapes hold for ~5s then drift.
|
|
166
|
-
const CLUSTER_SPAN_COLS = 6;
|
|
167
|
-
const CLUSTER_TICKS = 64;
|
|
168
|
-
const CLUSTER_BOOST = 0.34;
|
|
169
|
-
function clusterBoost(x, tick, salt) {
|
|
170
|
-
const shape = hash01(Math.floor(x / CLUSTER_SPAN_COLS), salt, Math.floor(tick / CLUSTER_TICKS));
|
|
171
|
-
return shape > 0.55 ? CLUSTER_BOOST * ((shape - 0.55) / 0.45) : 0;
|
|
172
|
-
}
|
|
173
|
-
const FAILURE_CREST_BASE = 0.8;
|
|
174
|
-
const FAILURE_CREST_FLICKER = 0.15;
|
|
175
|
-
const FAILURE_DIM = 0.25;
|
|
176
|
-
const FAILURE_SPREAD_COLS_PER_TICK = 1.5;
|
|
177
|
-
/** Heat sources injected on the virtual row below the band, one per column, for this tick's zone state. */
|
|
178
|
-
export function sourcesFor(state) {
|
|
179
|
-
const { cols, tick, frontCol, phase } = state;
|
|
180
|
-
const out = new Array(cols);
|
|
181
|
-
if (phase === 'success') {
|
|
182
|
-
for (let x = 0; x < cols; x++) {
|
|
183
|
-
out[x] = clamp01(SIMMER_BASE +
|
|
184
|
-
SIMMER_AMPLITUDE * Math.sin(tick * 0.04 + x * 0.2) +
|
|
185
|
-
clusterBoost(x, tick, 13));
|
|
186
|
-
}
|
|
187
|
-
return out;
|
|
188
|
-
}
|
|
189
|
-
if (phase === 'failure') {
|
|
190
|
-
const deathCol = state.deathCol ?? frontCol;
|
|
191
|
-
const spreadRadius = (state.phaseTick ?? 0) * FAILURE_SPREAD_COLS_PER_TICK;
|
|
192
|
-
const fullyOwned = spreadRadius >= cols;
|
|
193
|
-
for (let x = 0; x < cols; x++) {
|
|
194
|
-
if (fullyOwned) {
|
|
195
|
-
out[x] = clamp01(FAILURE_SIMMER_BASE +
|
|
196
|
-
SIMMER_AMPLITUDE * Math.sin(tick * 0.04 + x * 0.2) +
|
|
197
|
-
clusterBoost(x, tick, 17));
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
const distance = Math.abs(x - deathCol);
|
|
201
|
-
out[x] =
|
|
202
|
-
distance <= spreadRadius
|
|
203
|
-
? clamp01(FAILURE_CREST_BASE + FAILURE_CREST_FLICKER * hash01(x, 5, tick))
|
|
204
|
-
: FAILURE_DIM;
|
|
205
|
-
}
|
|
206
|
-
return out;
|
|
207
|
-
}
|
|
208
|
-
for (let x = 0; x < cols; x++) {
|
|
209
|
-
let base;
|
|
210
|
-
if (x <= frontCol && frontCol - x < CREST_WIDTH) {
|
|
211
|
-
base = CREST_BASE + CREST_FLICKER * hash01(x, 1, tick);
|
|
212
|
-
}
|
|
213
|
-
else if (x < frontCol) {
|
|
214
|
-
base =
|
|
215
|
-
EMBER_BASE + EMBER_AMPLITUDE * Math.sin(tick * 0.05 + x * 0.3) + clusterBoost(x, tick, 11);
|
|
216
|
-
}
|
|
217
|
-
else if (x - frontCol <= SPARK_AHEAD_COLS) {
|
|
218
|
-
base = hash01(x, 2, tick) > 0.82 ? 0.3 * hash01(x, 3, tick) : 0;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
base = 0;
|
|
222
|
-
}
|
|
223
|
-
out[x] = clamp01(base + flareBoost(x, state.flare));
|
|
224
|
-
}
|
|
225
|
-
return out;
|
|
226
|
-
}
|
|
227
|
-
function renderGridLine(row, mode, color, glyph) {
|
|
228
|
-
let out = '';
|
|
229
|
-
for (const heat of row) {
|
|
230
|
-
const ch = glyphFor(heat, glyph);
|
|
231
|
-
out += color === 'none' ? ch : paint(fireColor(heat, mode), ch, color);
|
|
232
|
-
}
|
|
233
|
-
return out;
|
|
234
|
-
}
|
|
235
|
-
const DIM_GRAY = [115, 115, 115];
|
|
236
|
-
function renderMilestoneRow(progress, cols, color, glyph) {
|
|
237
|
-
const tick = glyph === 'ascii' ? '+' : '┴';
|
|
238
|
-
const cells = new Array(cols).fill(' ');
|
|
239
|
-
for (const stage of MILESTONE_ORDER) {
|
|
240
|
-
const position = MILESTONES[stage];
|
|
241
|
-
const col = milestoneCol(position, cols);
|
|
242
|
-
const passed = progress >= position;
|
|
243
|
-
cells[col] = color === 'none' ? tick : paint(passed ? AMBER : DIM_GRAY, tick, color);
|
|
244
|
-
}
|
|
245
|
-
return cells.join('');
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* The labeled stage track from the approved frames: `compile —— assets —— upload ——— activate —— live`,
|
|
249
|
-
* label starts anchored to their milestone columns, dashes filling the gaps. Passed stages read amber,
|
|
250
|
-
* the road ahead dim.
|
|
251
|
-
*/
|
|
252
|
-
export function renderStageLabelRow(progress, cols, color, glyph) {
|
|
253
|
-
const dash = glyph === 'ascii' ? '-' : '─';
|
|
254
|
-
const cells = Array.from({ length: cols }, () => ({
|
|
255
|
-
ch: dash,
|
|
256
|
-
passed: undefined,
|
|
257
|
-
}));
|
|
258
|
-
for (const stage of MILESTONE_ORDER) {
|
|
259
|
-
const position = MILESTONES[stage];
|
|
260
|
-
// Anchor each label so it ENDS near its milestone column (the final 'live' label must fit).
|
|
261
|
-
const col = milestoneCol(position, cols);
|
|
262
|
-
const start = clampInt(stage === 'live' ? col - stage.length + 1 : Math.max(0, col - Math.floor(stage.length / 2)), 0, Math.max(0, cols - stage.length));
|
|
263
|
-
const passed = progress >= position;
|
|
264
|
-
// One space of breathing room around each label.
|
|
265
|
-
if (start > 0)
|
|
266
|
-
cells[start - 1] = { ch: ' ', passed: undefined };
|
|
267
|
-
for (let i = 0; i < stage.length && start + i < cols; i++) {
|
|
268
|
-
cells[start + i] = { ch: stage[i], passed };
|
|
269
|
-
}
|
|
270
|
-
if (start + stage.length < cols)
|
|
271
|
-
cells[start + stage.length] = { ch: ' ', passed: undefined };
|
|
272
|
-
}
|
|
273
|
-
if (color === 'none')
|
|
274
|
-
return cells.map((cell) => cell.ch).join('');
|
|
275
|
-
return cells
|
|
276
|
-
.map((cell) => cell.passed === undefined
|
|
277
|
-
? paint(DIM_GRAY, cell.ch, color)
|
|
278
|
-
: paint(cell.passed ? AMBER : DIM_GRAY, cell.ch, color))
|
|
279
|
-
.join('');
|
|
280
|
-
}
|
|
281
|
-
/** Build one frame's lines: checklist header, grid rows, milestone ticks + labels, flavor/dismiss. */
|
|
282
|
-
export function renderFireFrame(input) {
|
|
283
|
-
const lines = [];
|
|
284
|
-
if (input.headerLines !== undefined)
|
|
285
|
-
lines.push(...input.headerLines, '');
|
|
286
|
-
lines.push(...input.grid.map((row) => renderGridLine(row, input.mode, input.color, input.glyph)));
|
|
287
|
-
lines.push(renderMilestoneRow(input.progress, input.cols, input.color, input.glyph));
|
|
288
|
-
if (input.flavorLine !== undefined)
|
|
289
|
-
lines.push(input.flavorLine);
|
|
290
|
-
lines.push(renderStageLabelRow(input.progress, input.cols, input.color, input.glyph));
|
|
291
|
-
if (input.dismissHint !== undefined)
|
|
292
|
-
lines.push(input.dismissHint);
|
|
293
|
-
return lines;
|
|
294
|
-
}
|
|
295
|
-
function inertController() {
|
|
296
|
-
return {
|
|
297
|
-
setProgress: () => { },
|
|
298
|
-
succeed: async () => { },
|
|
299
|
-
fail: async () => { },
|
|
300
|
-
stop: () => { },
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Drive the fire band on `stream`. Assumes the caller has already decided this run is eligible
|
|
305
|
-
* (interactive, colored, not `--json`, not `NOODLE_NO_FIRE`) — this function independently derives
|
|
306
|
-
* color from `stream` too, and renders nothing at all when that resolves to `'none'`, so it is safe
|
|
307
|
-
* to call directly in tests without re-deriving the outer gate.
|
|
308
|
-
*/
|
|
309
|
-
export function runDeployFire(opts) {
|
|
310
|
-
const stream = opts.stream;
|
|
311
|
-
const color = detectColorMode(stream);
|
|
312
|
-
if (color === 'none')
|
|
313
|
-
return inertController();
|
|
314
|
-
const glyph = detectGlyphMode();
|
|
315
|
-
const frameMs = opts.frameMs ?? FRAME_MS;
|
|
316
|
-
const rows = opts.rows ?? DEFAULT_ROWS;
|
|
317
|
-
const cols = opts.cols ?? (typeof stream.columns === 'number' ? stream.columns : DEFAULT_COLS);
|
|
318
|
-
// A band narrower than MIN_COLS can't hold the milestone track, and rows longer than the real
|
|
319
|
-
// terminal would soft-wrap — breaking repaintBand's move-up-by-line-count math into garbage.
|
|
320
|
-
// Too narrow to draw honestly = don't draw at all.
|
|
321
|
-
if (cols < MIN_COLS)
|
|
322
|
-
return inertController();
|
|
323
|
-
const stdin = opts.stdin;
|
|
324
|
-
const flavorSeed = createFlavorSeed();
|
|
325
|
-
const entrypointLabel = opts.entrypointLabel ?? 'server.ts';
|
|
326
|
-
let grid = createGrid(rows, cols);
|
|
327
|
-
let tick = 0;
|
|
328
|
-
let progress = 0;
|
|
329
|
-
let phase = 'progress';
|
|
330
|
-
let phaseStartTick = 0; // tick at which the current end phase (success/failure) began
|
|
331
|
-
let deathCol;
|
|
332
|
-
let flare;
|
|
333
|
-
let holding = false;
|
|
334
|
-
let previousLineCount = 0;
|
|
335
|
-
let stopped = false;
|
|
336
|
-
let successLines = [];
|
|
337
|
-
let failLine;
|
|
338
|
-
const flaredStages = new Set();
|
|
339
|
-
// The ✔ checklist above the band (approved layout): milestone crossings append lines; the
|
|
340
|
-
// indeterminate activate wait shows as a pending line until the end state replaces it.
|
|
341
|
-
const glyphs = detectGlyphMode() === 'ascii'
|
|
342
|
-
? { prompt: '>', ok: '+', pending: '~', bad: 'x' }
|
|
343
|
-
: { prompt: '❯', ok: '✔', pending: '⠿', bad: '✗' };
|
|
344
|
-
// `color` is already narrowed past the top inert guard — a 'none' stream never reaches here.
|
|
345
|
-
const tint = (rgb, text) => paint(rgb, text, color);
|
|
346
|
-
// Clamp every checklist line to the band width: a long error message or endpoint URL that
|
|
347
|
-
// soft-wraps would break the cursor-up repaint math (CodeRabbit, fire-fix review).
|
|
348
|
-
const clampLine = (text) => [...text].length > cols - 2 ? `${[...text].slice(0, cols - 3).join('')}…` : text;
|
|
349
|
-
const headerLines = () => {
|
|
350
|
-
const lines = [`${tint(ORANGE, glyphs.prompt)} noodle deploy`];
|
|
351
|
-
const done = (text) => lines.push(`${tint(GREEN, glyphs.ok)} ${clampLine(text)}`);
|
|
352
|
-
if (progress >= MILESTONES.compile)
|
|
353
|
-
done(`Compiled ${entrypointLabel}`);
|
|
354
|
-
if (progress >= MILESTONES.assets)
|
|
355
|
-
done('Assets verified');
|
|
356
|
-
if (progress >= MILESTONES.upload)
|
|
357
|
-
done('Uploaded');
|
|
358
|
-
if (phase === 'success') {
|
|
359
|
-
for (const line of successLines.length > 0 ? successLines : ['Activated (atomic)']) {
|
|
360
|
-
done(line);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
else if (phase === 'failure') {
|
|
364
|
-
lines.push(`${tint(ROSE, glyphs.bad)} ${clampLine(failLine ?? 'Deploy failed')}`);
|
|
365
|
-
}
|
|
366
|
-
else if (progress >= MILESTONES.upload) {
|
|
367
|
-
lines.push(tint(DIM_GRAY, `${glyphs.pending} Activating on Noodle Seed Cloud…`));
|
|
368
|
-
}
|
|
369
|
-
return lines;
|
|
370
|
-
};
|
|
371
|
-
const currentFlavorStage = () => phase === 'failure' ? 'failed' : phase === 'success' ? 'live' : stageForProgress(progress);
|
|
372
|
-
const paintFrame = () => {
|
|
373
|
-
tick += 1;
|
|
374
|
-
if (flare !== undefined) {
|
|
375
|
-
const aged = { col: flare.col, ageTicks: flare.ageTicks + 1 };
|
|
376
|
-
flare = aged.ageTicks > FLARE_DURATION_TICKS ? undefined : aged;
|
|
377
|
-
}
|
|
378
|
-
const frontCol = milestoneCol(Math.min(progress, 1), cols);
|
|
379
|
-
const zone = {
|
|
380
|
-
cols,
|
|
381
|
-
tick,
|
|
382
|
-
frontCol,
|
|
383
|
-
phase,
|
|
384
|
-
...(phase !== 'progress' ? { phaseTick: tick - phaseStartTick } : {}),
|
|
385
|
-
...(deathCol !== undefined ? { deathCol } : {}),
|
|
386
|
-
...(flare !== undefined ? { flare } : {}),
|
|
387
|
-
};
|
|
388
|
-
grid = advanceHeat(grid, sourcesFor(zone), tick);
|
|
389
|
-
const mode = phase === 'success' ? 'green' : phase === 'failure' ? 'rose' : 'warm';
|
|
390
|
-
const lines = renderFireFrame({
|
|
391
|
-
grid,
|
|
392
|
-
cols,
|
|
393
|
-
progress,
|
|
394
|
-
mode,
|
|
395
|
-
color,
|
|
396
|
-
glyph,
|
|
397
|
-
headerLines: headerLines(),
|
|
398
|
-
flavorLine: renderFlavorLine(currentFlavorStage(), flavorSeed, color, cols),
|
|
399
|
-
...(holding ? { dismissHint: dimText('press enter to close', stream) } : {}),
|
|
400
|
-
});
|
|
401
|
-
previousLineCount = repaintBand(stream, previousLineCount, lines);
|
|
402
|
-
};
|
|
403
|
-
stream.write(HIDE_CURSOR);
|
|
404
|
-
paintFrame();
|
|
405
|
-
const timer = setInterval(paintFrame, frameMs);
|
|
406
|
-
timer.unref?.();
|
|
407
|
-
const teardownOutput = () => {
|
|
408
|
-
if (stopped)
|
|
409
|
-
return;
|
|
410
|
-
stopped = true;
|
|
411
|
-
clearInterval(timer);
|
|
412
|
-
stream.write(SHOW_CURSOR);
|
|
413
|
-
};
|
|
414
|
-
// Set only while `holdUntilDismiss` is waiting on a keypress: lets `stop()` (or a SIGINT during a
|
|
415
|
-
// hold) run the hold's full cleanup — detach listeners, restore raw mode, resolve the promise —
|
|
416
|
-
// instead of leaving the terminal in raw mode with a forever-pending hold.
|
|
417
|
-
let finishHold;
|
|
418
|
-
const teardown = () => {
|
|
419
|
-
finishHold?.();
|
|
420
|
-
teardownOutput();
|
|
421
|
-
};
|
|
422
|
-
const setProgress = (next) => {
|
|
423
|
-
if (stopped || phase !== 'progress')
|
|
424
|
-
return;
|
|
425
|
-
const clamped = clamp01(next);
|
|
426
|
-
for (const stage of MILESTONE_ORDER) {
|
|
427
|
-
if (clamped >= MILESTONES[stage] && !flaredStages.has(stage)) {
|
|
428
|
-
flaredStages.add(stage);
|
|
429
|
-
flare = { col: milestoneCol(MILESTONES[stage], cols), ageTicks: 0 };
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
progress = clamped;
|
|
433
|
-
};
|
|
434
|
-
const holdUntilDismiss = () => {
|
|
435
|
-
if (stopped)
|
|
436
|
-
return Promise.resolve();
|
|
437
|
-
if (stdin?.isTTY !== true) {
|
|
438
|
-
teardown();
|
|
439
|
-
return Promise.resolve();
|
|
440
|
-
}
|
|
441
|
-
holding = true;
|
|
442
|
-
paintFrame();
|
|
443
|
-
const input = stdin;
|
|
444
|
-
return new Promise((resolve) => {
|
|
445
|
-
const wasRaw = input.isRaw === true;
|
|
446
|
-
emitKeypressEvents(input);
|
|
447
|
-
input.setRawMode?.(true);
|
|
448
|
-
let settled = false;
|
|
449
|
-
const onKey = (_s, key = {}) => {
|
|
450
|
-
if (key.name === 'return' ||
|
|
451
|
-
key.name === 'enter' ||
|
|
452
|
-
(key.ctrl === true && key.name === 'c')) {
|
|
453
|
-
finish();
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
const onSigint = () => finish();
|
|
457
|
-
function finish() {
|
|
458
|
-
if (settled)
|
|
459
|
-
return;
|
|
460
|
-
settled = true;
|
|
461
|
-
finishHold = undefined;
|
|
462
|
-
input.off('keypress', onKey);
|
|
463
|
-
process.off('SIGINT', onSigint);
|
|
464
|
-
input.setRawMode?.(wasRaw);
|
|
465
|
-
teardownOutput();
|
|
466
|
-
resolve();
|
|
467
|
-
}
|
|
468
|
-
finishHold = finish;
|
|
469
|
-
input.on('keypress', onKey);
|
|
470
|
-
process.once('SIGINT', onSigint);
|
|
471
|
-
});
|
|
472
|
-
};
|
|
473
|
-
return {
|
|
474
|
-
setProgress,
|
|
475
|
-
succeed: async (opts = {}) => {
|
|
476
|
-
if (stopped)
|
|
477
|
-
return;
|
|
478
|
-
if (opts.lines !== undefined)
|
|
479
|
-
successLines = opts.lines;
|
|
480
|
-
phase = 'success';
|
|
481
|
-
phaseStartTick = tick;
|
|
482
|
-
progress = 1;
|
|
483
|
-
await holdUntilDismiss();
|
|
484
|
-
},
|
|
485
|
-
fail: async (opts = {}) => {
|
|
486
|
-
if (stopped)
|
|
487
|
-
return;
|
|
488
|
-
if (opts.line !== undefined)
|
|
489
|
-
failLine = opts.line;
|
|
490
|
-
deathCol = milestoneCol(Math.min(progress, 1), cols);
|
|
491
|
-
phase = 'failure';
|
|
492
|
-
phaseStartTick = tick;
|
|
493
|
-
paintFrame();
|
|
494
|
-
teardownOutput();
|
|
495
|
-
},
|
|
496
|
-
stop: () => teardown(),
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* Repaint in place: move the cursor back up over the previous frame and redraw every line. Unlike
|
|
501
|
-
* `watch.ts`'s `repaint`, this never needs to blank stale trailing lines — a fire frame only ever
|
|
502
|
-
* grows (the dismiss hint appends one line once) and never shrinks.
|
|
503
|
-
*/
|
|
504
|
-
function repaintBand(stream, previousLineCount, lines) {
|
|
505
|
-
let out = previousLineCount > 0 ? cursorUp(previousLineCount) : '';
|
|
506
|
-
for (const line of lines)
|
|
507
|
-
out += `${CR}${line}${CLEAR_EOL}${NL}`;
|
|
508
|
-
stream.write(out);
|
|
509
|
-
return lines.length;
|
|
510
|
-
}
|
|
511
|
-
//# sourceMappingURL=fire.js.map
|