@otto-code/brain 0.7.5
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/bin/otto-brain +2 -0
- package/dist/bench/context-corpus.d.ts +58 -0
- package/dist/bench/context-corpus.js +210 -0
- package/dist/bench/corpus.d.ts +31 -0
- package/dist/bench/corpus.js +379 -0
- package/dist/bench/curated-repos.d.ts +35 -0
- package/dist/bench/curated-repos.js +41 -0
- package/dist/bench/health.d.ts +50 -0
- package/dist/bench/health.js +112 -0
- package/dist/bench/index.d.ts +103 -0
- package/dist/bench/index.js +209 -0
- package/dist/bench/mine.d.ts +32 -0
- package/dist/bench/mine.js +101 -0
- package/dist/bench/repo-task.d.ts +93 -0
- package/dist/bench/repo-task.js +380 -0
- package/dist/bench/repo.d.ts +125 -0
- package/dist/bench/repo.js +195 -0
- package/dist/bench/rescore.d.ts +41 -0
- package/dist/bench/rescore.js +127 -0
- package/dist/bench/tasks.d.ts +124 -0
- package/dist/bench/tasks.js +1249 -0
- package/dist/bench/verify.d.ts +142 -0
- package/dist/bench/verify.js +350 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +72 -0
- package/dist/commands/bench.d.ts +20 -0
- package/dist/commands/bench.js +222 -0
- package/dist/commands/calibrate.d.ts +19 -0
- package/dist/commands/calibrate.js +75 -0
- package/dist/commands/catalog.d.ts +32 -0
- package/dist/commands/catalog.js +48 -0
- package/dist/commands/config.d.ts +13 -0
- package/dist/commands/config.js +90 -0
- package/dist/commands/lifecycle.d.ts +29 -0
- package/dist/commands/lifecycle.js +194 -0
- package/dist/commands/pull.d.ts +22 -0
- package/dist/commands/pull.js +135 -0
- package/dist/commands/report.d.ts +10 -0
- package/dist/commands/report.js +34 -0
- package/dist/commands/rescore.d.ts +11 -0
- package/dist/commands/rescore.js +48 -0
- package/dist/commands/runtime.d.ts +21 -0
- package/dist/commands/runtime.js +62 -0
- package/dist/commands/scan.d.ts +24 -0
- package/dist/commands/scan.js +55 -0
- package/dist/commands/search.d.ts +31 -0
- package/dist/commands/search.js +135 -0
- package/dist/commands/share.d.ts +26 -0
- package/dist/commands/share.js +148 -0
- package/dist/commands/sweep.d.ts +21 -0
- package/dist/commands/sweep.js +69 -0
- package/dist/commands/ui.d.ts +9 -0
- package/dist/commands/ui.js +28 -0
- package/dist/config/env.d.ts +10 -0
- package/dist/config/env.js +48 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.js +9 -0
- package/dist/config/otto-home.d.ts +2 -0
- package/dist/config/otto-home.js +24 -0
- package/dist/config/paths.d.ts +20 -0
- package/dist/config/paths.js +33 -0
- package/dist/config/private-files.d.ts +3 -0
- package/dist/config/private-files.js +32 -0
- package/dist/config/profiles.d.ts +34 -0
- package/dist/config/profiles.js +116 -0
- package/dist/config/schema.d.ts +1035 -0
- package/dist/config/schema.js +191 -0
- package/dist/config/store.d.ts +11 -0
- package/dist/config/store.js +73 -0
- package/dist/gguf.d.ts +61 -0
- package/dist/gguf.js +231 -0
- package/dist/gpu.d.ts +12 -0
- package/dist/gpu.js +49 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +13 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +5 -0
- package/dist/models/dirs.d.ts +9 -0
- package/dist/models/dirs.js +21 -0
- package/dist/models/download.d.ts +31 -0
- package/dist/models/download.js +105 -0
- package/dist/models/enrich.d.ts +36 -0
- package/dist/models/enrich.js +68 -0
- package/dist/models/hf.d.ts +62 -0
- package/dist/models/hf.js +114 -0
- package/dist/models/index.d.ts +15 -0
- package/dist/models/index.js +49 -0
- package/dist/models/manage.d.ts +27 -0
- package/dist/models/manage.js +112 -0
- package/dist/models/pick.d.ts +3 -0
- package/dist/models/pick.js +36 -0
- package/dist/models/scan.d.ts +13 -0
- package/dist/models/scan.js +185 -0
- package/dist/ops/archive.d.ts +34 -0
- package/dist/ops/archive.js +105 -0
- package/dist/ops/calibrate.d.ts +49 -0
- package/dist/ops/calibrate.js +74 -0
- package/dist/ops/report.d.ts +26 -0
- package/dist/ops/report.js +532 -0
- package/dist/ops/results.d.ts +207 -0
- package/dist/ops/results.js +250 -0
- package/dist/ops/sweep.d.ts +77 -0
- package/dist/ops/sweep.js +126 -0
- package/dist/output/index.d.ts +5 -0
- package/dist/output/index.js +5 -0
- package/dist/output/render.d.ts +4 -0
- package/dist/output/render.js +96 -0
- package/dist/output/types.d.ts +52 -0
- package/dist/output/types.js +9 -0
- package/dist/output/with-output.d.ts +3 -0
- package/dist/output/with-output.js +42 -0
- package/dist/run.d.ts +5 -0
- package/dist/run.js +19 -0
- package/dist/runtime/args.d.ts +21 -0
- package/dist/runtime/args.js +71 -0
- package/dist/runtime/index.d.ts +13 -0
- package/dist/runtime/index.js +41 -0
- package/dist/runtime/lmstudio.d.ts +10 -0
- package/dist/runtime/lmstudio.js +88 -0
- package/dist/runtime/managed.d.ts +26 -0
- package/dist/runtime/managed.js +148 -0
- package/dist/service/model-selector.d.ts +36 -0
- package/dist/service/model-selector.js +123 -0
- package/dist/service/pid-lock.d.ts +18 -0
- package/dist/service/pid-lock.js +50 -0
- package/dist/service/router.d.ts +144 -0
- package/dist/service/router.js +746 -0
- package/dist/service/scheduler.d.ts +74 -0
- package/dist/service/scheduler.js +110 -0
- package/dist/service/serve.d.ts +41 -0
- package/dist/service/serve.js +278 -0
- package/dist/service/supervisor.d.ts +67 -0
- package/dist/service/supervisor.js +222 -0
- package/dist/service/tailscale.d.ts +19 -0
- package/dist/service/tailscale.js +62 -0
- package/dist/service/tls.d.ts +77 -0
- package/dist/service/tls.js +192 -0
- package/dist/sysmon.d.ts +50 -0
- package/dist/sysmon.js +103 -0
- package/dist/tui/app.d.ts +208 -0
- package/dist/tui/app.js +1801 -0
- package/dist/tui/screen.d.ts +72 -0
- package/dist/tui/screen.js +176 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.js +7 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +8 -0
- package/dist/vram.d.ts +67 -0
- package/dist/vram.js +132 -0
- package/package.json +58 -0
package/dist/sysmon.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import { query } from "./gpu.js";
|
|
4
|
+
/** CPU busy fraction, sampled between successive calls. */
|
|
5
|
+
export function createCpuSampler() {
|
|
6
|
+
let previous = null;
|
|
7
|
+
function snapshot() {
|
|
8
|
+
let idle = 0;
|
|
9
|
+
let total = 0;
|
|
10
|
+
for (const cpu of os.cpus()) {
|
|
11
|
+
for (const [kind, ms] of Object.entries(cpu.times)) {
|
|
12
|
+
total += ms;
|
|
13
|
+
if (kind === "idle")
|
|
14
|
+
idle += ms;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return { idle, total };
|
|
18
|
+
}
|
|
19
|
+
return function sample() {
|
|
20
|
+
const now = snapshot();
|
|
21
|
+
if (!previous) {
|
|
22
|
+
previous = now;
|
|
23
|
+
return null; // first call establishes the baseline
|
|
24
|
+
}
|
|
25
|
+
const idleDelta = now.idle - previous.idle;
|
|
26
|
+
const totalDelta = now.total - previous.total;
|
|
27
|
+
previous = now;
|
|
28
|
+
if (totalDelta <= 0)
|
|
29
|
+
return null;
|
|
30
|
+
return Math.max(0, Math.min(1, 1 - idleDelta / totalDelta));
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function fetchJson({ host, port, path: urlPath, timeout = 2500, }) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const req = http.get({ host, port, path: urlPath, timeout }, (res) => {
|
|
36
|
+
let body = "";
|
|
37
|
+
res.on("data", (c) => (body += c));
|
|
38
|
+
res.on("end", () => {
|
|
39
|
+
try {
|
|
40
|
+
resolve(JSON.parse(body));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
resolve(null);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
req.on("timeout", () => {
|
|
48
|
+
req.destroy();
|
|
49
|
+
resolve(null);
|
|
50
|
+
});
|
|
51
|
+
req.on("error", () => resolve(null));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Slot occupancy from the running server.
|
|
56
|
+
* @returns {{total:number, busy:number, idle:number, contexts:number[]}|null}
|
|
57
|
+
*/
|
|
58
|
+
async function slots({ host, port }) {
|
|
59
|
+
const data = await fetchJson({ host, port, path: "/slots" });
|
|
60
|
+
if (!Array.isArray(data))
|
|
61
|
+
return null;
|
|
62
|
+
const rows = data;
|
|
63
|
+
// Field naming has varied across llama.cpp versions; accept either.
|
|
64
|
+
const busy = rows.filter((s) => {
|
|
65
|
+
const rec = s;
|
|
66
|
+
if (typeof rec.is_processing === "boolean")
|
|
67
|
+
return rec.is_processing;
|
|
68
|
+
if (typeof rec.state === "number")
|
|
69
|
+
return rec.state !== 0;
|
|
70
|
+
return false;
|
|
71
|
+
}).length;
|
|
72
|
+
return {
|
|
73
|
+
total: rows.length,
|
|
74
|
+
busy,
|
|
75
|
+
idle: rows.length - busy,
|
|
76
|
+
contexts: rows.map((s) => {
|
|
77
|
+
const rec = s;
|
|
78
|
+
const nCtx = typeof rec.n_ctx === "number" ? rec.n_ctx : undefined;
|
|
79
|
+
const nPast = typeof rec.n_past === "number" ? rec.n_past : undefined;
|
|
80
|
+
return nCtx ?? nPast ?? 0;
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export { slots };
|
|
85
|
+
/** One combined reading for the status panel. */
|
|
86
|
+
export async function sample(sampler, { host, port } = {}) {
|
|
87
|
+
const totalMem = os.totalmem();
|
|
88
|
+
const freeMem = os.freemem();
|
|
89
|
+
const [gpuInfo, slotInfo] = await Promise.all([
|
|
90
|
+
query(),
|
|
91
|
+
host && port ? slots({ host, port }) : Promise.resolve(null),
|
|
92
|
+
]);
|
|
93
|
+
return {
|
|
94
|
+
cpu: sampler(),
|
|
95
|
+
cpuCount: os.cpus().length,
|
|
96
|
+
loadAverage: os.loadavg()[0] || null, // 0 on Windows; shown only when real
|
|
97
|
+
ramUsedBytes: totalMem - freeMem,
|
|
98
|
+
ramTotalBytes: totalMem,
|
|
99
|
+
gpu: gpuInfo,
|
|
100
|
+
slots: slotInfo,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=sysmon.js.map
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Screen } from "./screen.js";
|
|
2
|
+
import type { DiskUsage, QuantOption, RepoQuants, ModelSearchResult } from "../models/index.js";
|
|
3
|
+
import { Supervisor } from "../service/supervisor.js";
|
|
4
|
+
import { Telemetry } from "../service/router.js";
|
|
5
|
+
import http from "node:http";
|
|
6
|
+
import type { GpuInfo, Model, Runtime } from "../types.js";
|
|
7
|
+
import type { Budget } from "../vram.js";
|
|
8
|
+
import type { Calibration, Profile, ProfilesStore } from "../config/schema.js";
|
|
9
|
+
import type { RankedModel, RunRecord } from "../ops/results.js";
|
|
10
|
+
import type { SweepReport } from "../ops/sweep.js";
|
|
11
|
+
import type { CpuSampler, SystemSample } from "../sysmon.js";
|
|
12
|
+
type Tone = "info" | "good" | "warn" | "bad";
|
|
13
|
+
type Focus = "models" | "config";
|
|
14
|
+
type ViewMode = "standard" | "logs" | "help" | "bench";
|
|
15
|
+
/** The model a field's callbacks are rendered against. */
|
|
16
|
+
interface FieldContext {
|
|
17
|
+
model: Model | null;
|
|
18
|
+
}
|
|
19
|
+
/** A pending destructive action awaiting y/n. */
|
|
20
|
+
interface ConfirmState {
|
|
21
|
+
kind: "delete";
|
|
22
|
+
model: Model;
|
|
23
|
+
}
|
|
24
|
+
/** One downloadable quant in the picker, with whether it is already on disk. */
|
|
25
|
+
interface PickerQuant extends QuantOption {
|
|
26
|
+
installed: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** The quant-download picker: a modal list of a repo's available quants. */
|
|
29
|
+
interface PickerState {
|
|
30
|
+
model: Model | null;
|
|
31
|
+
repo: string;
|
|
32
|
+
loading: boolean;
|
|
33
|
+
options: PickerQuant[];
|
|
34
|
+
mmproj: RepoQuants["mmproj"];
|
|
35
|
+
index: number;
|
|
36
|
+
}
|
|
37
|
+
/** The Hugging Face search modal: type a query, then browse GGUF repos. */
|
|
38
|
+
interface SearchState {
|
|
39
|
+
query: string;
|
|
40
|
+
input: boolean;
|
|
41
|
+
loading: boolean;
|
|
42
|
+
results: ModelSearchResult[];
|
|
43
|
+
index: number;
|
|
44
|
+
}
|
|
45
|
+
/** One editable configuration field. */
|
|
46
|
+
interface Field {
|
|
47
|
+
key: keyof Profile;
|
|
48
|
+
label: string;
|
|
49
|
+
kind: "number" | "cycle" | "toggle";
|
|
50
|
+
format: (profile: Profile, ctx: FieldContext) => string;
|
|
51
|
+
step?: number;
|
|
52
|
+
min?: number;
|
|
53
|
+
max?: number | ((ctx: FieldContext) => number);
|
|
54
|
+
values?: Array<number | string>;
|
|
55
|
+
note?: (profile: Profile) => string | null;
|
|
56
|
+
enabled?: (ctx: FieldContext) => boolean;
|
|
57
|
+
}
|
|
58
|
+
/** The number field currently being typed into. */
|
|
59
|
+
interface EditingState {
|
|
60
|
+
field: Field;
|
|
61
|
+
buffer: string;
|
|
62
|
+
}
|
|
63
|
+
/** The current status line and its tone. */
|
|
64
|
+
interface StatusState {
|
|
65
|
+
text: string;
|
|
66
|
+
tone: Tone;
|
|
67
|
+
}
|
|
68
|
+
/** Constructor options for the interactive app. */
|
|
69
|
+
interface AppOptions {
|
|
70
|
+
runtime: Runtime;
|
|
71
|
+
listenPort: number;
|
|
72
|
+
listenHost: string;
|
|
73
|
+
}
|
|
74
|
+
/** Editable configuration fields, in display order. */
|
|
75
|
+
export declare const FIELDS: Field[];
|
|
76
|
+
export declare class App {
|
|
77
|
+
runtime: Runtime;
|
|
78
|
+
listenPort: number;
|
|
79
|
+
listenHost: string;
|
|
80
|
+
screen: Screen;
|
|
81
|
+
store: ProfilesStore;
|
|
82
|
+
catalog: Model[];
|
|
83
|
+
filter: string;
|
|
84
|
+
selected: number;
|
|
85
|
+
scrollTop: number;
|
|
86
|
+
focus: Focus;
|
|
87
|
+
fieldIndex: number;
|
|
88
|
+
editing: EditingState | null;
|
|
89
|
+
busy: boolean;
|
|
90
|
+
status: StatusState;
|
|
91
|
+
gpuInfo: GpuInfo | null;
|
|
92
|
+
profile: Profile | null;
|
|
93
|
+
sweepResult: SweepReport | null;
|
|
94
|
+
cpuSampler: CpuSampler;
|
|
95
|
+
sys: SystemSample | null;
|
|
96
|
+
viewMode: ViewMode;
|
|
97
|
+
benchRunning: boolean;
|
|
98
|
+
benchProgress: string[];
|
|
99
|
+
benchResults: RunRecord[];
|
|
100
|
+
benchModelId: string | null;
|
|
101
|
+
rankings: Map<string, RankedModel>;
|
|
102
|
+
rankedModels: RankedModel[];
|
|
103
|
+
telemetry: Telemetry;
|
|
104
|
+
supervisor: Supervisor;
|
|
105
|
+
routerServer: http.Server | null;
|
|
106
|
+
filterMode: boolean;
|
|
107
|
+
confirming: ConfirmState | null;
|
|
108
|
+
picker: PickerState | null;
|
|
109
|
+
search: SearchState | null;
|
|
110
|
+
disk: DiskUsage | null;
|
|
111
|
+
detach?: () => void;
|
|
112
|
+
ticker?: NodeJS.Timeout;
|
|
113
|
+
done?: () => void;
|
|
114
|
+
constructor({ runtime, listenPort, listenHost }: AppOptions);
|
|
115
|
+
run(): Promise<void>;
|
|
116
|
+
shutdown(): Promise<void>;
|
|
117
|
+
/** Fit a model to the live VRAM budget and (re)start the server on it. */
|
|
118
|
+
loadModelFitted(target: Model): Promise<void>;
|
|
119
|
+
startRouter(): Promise<void>;
|
|
120
|
+
reload(): void;
|
|
121
|
+
/** Mean-of-runs rank + score per model, for ordering and badging the list. */
|
|
122
|
+
loadRankings(): void;
|
|
123
|
+
rankOf(model: Model | null): RankedModel | null;
|
|
124
|
+
/** Small, bounded ordering nudge for more-capable models (vision, thinking). */
|
|
125
|
+
capabilityBonus(model: Model): number;
|
|
126
|
+
get visible(): Model[];
|
|
127
|
+
get model(): Model | null;
|
|
128
|
+
syncProfile(): void;
|
|
129
|
+
get calibration(): Calibration | null;
|
|
130
|
+
get budget(): Budget | null;
|
|
131
|
+
persist(): void;
|
|
132
|
+
setStatus(text: string, tone?: Tone): void;
|
|
133
|
+
onKey(key: string): void;
|
|
134
|
+
onFilterKey(key: string): void;
|
|
135
|
+
onEditKey(key: string): void;
|
|
136
|
+
move(delta: number): void;
|
|
137
|
+
usableFields(): number[];
|
|
138
|
+
/** Read a profile field by key, without narrowing to a single value type. */
|
|
139
|
+
readField(key: keyof Profile): unknown;
|
|
140
|
+
/** Write a profile field by key; a no-op when no model is selected. */
|
|
141
|
+
writeField(key: keyof Profile, value: number | string | boolean): void;
|
|
142
|
+
adjust(direction: number): void;
|
|
143
|
+
activateField(): void;
|
|
144
|
+
applyMaxContext(): void;
|
|
145
|
+
/** The Hugging Face repo for a model: catalog match, else the id's first two
|
|
146
|
+
* path segments (`<publisher>/<repo>/<file>`). */
|
|
147
|
+
repoOf(model: Model): string | null;
|
|
148
|
+
refreshDisk(): Promise<void>;
|
|
149
|
+
beginDelete(): void;
|
|
150
|
+
onConfirmKey(key: string): void;
|
|
151
|
+
beginDownload(): Promise<void>;
|
|
152
|
+
/** Open the quant picker for a repo (an installed model, or one from search). */
|
|
153
|
+
openPicker(repo: string, model: Model | null): Promise<void>;
|
|
154
|
+
/** A direct owner/repo the query names, so a known repo can be opened without
|
|
155
|
+
* a round trip. Null unless the query looks like a repo path. */
|
|
156
|
+
directRepo(query: string): string | null;
|
|
157
|
+
beginSearch(): void;
|
|
158
|
+
onSearchKey(key: string): void;
|
|
159
|
+
runSearch(): Promise<void>;
|
|
160
|
+
drawSearch(cols: number): void;
|
|
161
|
+
onPickerKey(key: string): void;
|
|
162
|
+
downloadQuant(repo: string, choice: PickerQuant, mmproj: RepoQuants["mmproj"]): Promise<void>;
|
|
163
|
+
drawPicker(cols: number): void;
|
|
164
|
+
guard(label: string, fn: () => Promise<void>): Promise<void>;
|
|
165
|
+
startModel(): Promise<void> | void;
|
|
166
|
+
stopModel(): Promise<void>;
|
|
167
|
+
runCalibration(): Promise<void> | void;
|
|
168
|
+
runSweep(): Promise<void> | void;
|
|
169
|
+
enterBench(): void;
|
|
170
|
+
loadBenchResults(): void;
|
|
171
|
+
onBenchKey(key: string): void;
|
|
172
|
+
/** Load the selected model if needed, run the suite, and store the result. */
|
|
173
|
+
runBenchmarkOnSelected(): Promise<void> | void;
|
|
174
|
+
scoreColour(score: number): string;
|
|
175
|
+
/**
|
|
176
|
+
* Render, but never let the footer scroll off. The renderer only paints
|
|
177
|
+
* rows-1 lines; if the layout is taller than the terminal, drop rows from
|
|
178
|
+
* just above the footer so the keybindings hint is always on screen.
|
|
179
|
+
*/
|
|
180
|
+
renderFitted(lines: string[]): void;
|
|
181
|
+
draw(): void;
|
|
182
|
+
/**
|
|
183
|
+
* Benchmark workspace: the model list on the left, the selected model's
|
|
184
|
+
* scorecard where Configuration sits in serve mode, and the ranked leaderboard
|
|
185
|
+
* (or live run progress) where the Status panel sits.
|
|
186
|
+
*/
|
|
187
|
+
drawBench(cols: number): void;
|
|
188
|
+
/** The selected model's latest scorecard, or a prompt to run one. */
|
|
189
|
+
benchSidebar(innerWidth: number, rows: number): string[];
|
|
190
|
+
/** Live run progress, otherwise the ranked leaderboard. */
|
|
191
|
+
benchBottom(innerWidth: number): string[];
|
|
192
|
+
drawLogs(cols: number): void;
|
|
193
|
+
header(cols: number): string;
|
|
194
|
+
modelPanel(innerWidth: number, rows: number): string[];
|
|
195
|
+
configPanel(innerWidth: number, rows: number): string[];
|
|
196
|
+
budgetPanel(innerWidth: number): string[];
|
|
197
|
+
statusPanel(innerWidth: number): string[];
|
|
198
|
+
/** Full-screen reference so no option ever has to be guessed. */
|
|
199
|
+
drawHelp(cols: number): void;
|
|
200
|
+
/**
|
|
201
|
+
* The key hints for the current mode, as an array of lines. Groups are
|
|
202
|
+
* deliberately broken onto separate lines — navigation first, then the
|
|
203
|
+
* actions — and each group wraps further only if the terminal is too narrow.
|
|
204
|
+
*/
|
|
205
|
+
keybindings(cols: number): string[];
|
|
206
|
+
}
|
|
207
|
+
export {};
|
|
208
|
+
//# sourceMappingURL=app.d.ts.map
|