@stephenyang/stephen 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stephen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,377 @@
1
+ # stephen
2
+
3
+ `stephen` is a personal TypeScript CLI built for agent-friendly workflows first and interactive terminal use second.
4
+
5
+ The current flagship command is `ak`, a local API key manager. The CLI also includes a conservative Windows disk cleanup command for low-risk cache cleanup.
6
+
7
+ Roadmap work is underway for a new `video` command group focused on browser-assisted media detection, media downloads, and local video compression.
8
+
9
+ `ak` provides:
10
+
11
+ - SQLite-backed local storage
12
+ - encrypted key persistence
13
+ - `sha1(key)` record IDs for compatibility with existing backend lookup behavior
14
+ - JSON-first output for scripts and agents
15
+ - table output for human inspection
16
+ - deterministic command contracts and exit codes
17
+
18
+ ## Design Philosophy
19
+
20
+ `stephen` follows a few strong rules:
21
+
22
+ - Machine-readable by default: commands return JSON unless table mode is explicitly requested.
23
+ - Local-first: commands should work offline and avoid unnecessary remote coupling.
24
+ - Secrets stay protected: sensitive values are encrypted at rest and masked in normal output.
25
+ - Small, composable layers: parsing, domain logic, storage, and rendering should stay separate.
26
+ - Test before behavior: production behavior is expected to be developed with TDD.
27
+
28
+ ## Project Layout
29
+
30
+ ```text
31
+ src/ source code
32
+ docs/ local design notes and references
33
+ tests/ automated tests
34
+ ```
35
+
36
+ Key modules for `ak`:
37
+
38
+ - `src/ak/schema.ts`: validation, field parsing, and masking helpers
39
+ - `src/ak/crypto.ts`: SHA-1 IDs, prefix indexing, and encryption helpers
40
+ - `src/ak/runtime.ts`: local config loading and storage path resolution
41
+ - `src/ak/repository.ts`: SQLite persistence
42
+ - `src/ak/service.ts`: orchestration and domain behavior
43
+ - `src/ak/output.ts`: JSON and table rendering
44
+ - `src/ak/command.ts`: Commander-based CLI wiring
45
+
46
+ Key modules for `disk cleanup`:
47
+
48
+ - `src/disk/types.ts`: shared report shapes
49
+ - `src/disk/runtime.ts`: filesystem and process integration
50
+ - `src/disk/service.ts`: conservative cleanup orchestration
51
+ - `src/disk/output.ts`: JSON and table rendering
52
+ - `src/disk/command.ts`: Commander-based CLI wiring
53
+
54
+ ## Getting Started
55
+
56
+ Requirements:
57
+
58
+ - Node.js 22+
59
+ - npm
60
+
61
+ Install dependencies:
62
+
63
+ ```bash
64
+ npm install
65
+ ```
66
+
67
+ Run tests:
68
+
69
+ ```bash
70
+ npm test
71
+ ```
72
+
73
+ Run coverage:
74
+
75
+ ```bash
76
+ npm run coverage
77
+ ```
78
+
79
+ Build the CLI:
80
+
81
+ ```bash
82
+ npm run build
83
+ ```
84
+
85
+ ## Roadmap
86
+
87
+ Planned next major capability: `video`
88
+
89
+ - `video sniff`: inspect a page or media URL and return candidate downloadable video resources in JSON by default
90
+ - `video download`: download supported media inputs including page URLs, `m3u8` streams, and direct `mp4` links
91
+ - `video compress`: compress local video with `ffmpeg`
92
+
93
+ Current direction for `video`:
94
+
95
+ - browser-first detection for sites that only reveal media requests during real page execution
96
+ - HTTP-based fallback detection for simpler pages and direct media links
97
+ - a unified candidate model so `sniff` and `download` can handle `m3u8` and `mp4` consistently
98
+ - `ffmpeg`-backed compression with default `mp4` output, `h265` video, `aac` audio, and `64k` default audio bitrate
99
+ - explicit parameter support for resolution, video bitrate, audio bitrate, concurrency, request headers, and output selection
100
+
101
+ Planned defaults:
102
+
103
+ - JSON output first, with optional table mode when it improves readability
104
+ - `video sniff` mode default: `auto`, preferring browser-based detection before HTTP fallback
105
+ - `video compress` output default: `mp4`
106
+ - `video compress` video codec default: `h265`
107
+ - `video compress` audio codec default: `aac`
108
+ - `video compress` audio bitrate default: `64k`
109
+ - resolution unchanged unless the user passes an explicit resize option
110
+
111
+ Supporting documents:
112
+
113
+ - [2026-04-27-video-command-solution-report.md](/D:/Development/Stephen/PersonalCli/docs/2026-04-27-video-command-solution-report.md)
114
+ - [2026-04-27-video-command-implementation-plan.md](/D:/Development/Stephen/PersonalCli/docs/2026-04-27-video-command-implementation-plan.md)
115
+
116
+ ## `ak` Command
117
+
118
+ The `ak` command manages API key records with these fields:
119
+
120
+ - `env`
121
+ - `userId`
122
+ - `userName`
123
+ - `email`
124
+ - `phone`
125
+ - `key`
126
+
127
+ Recommended environments:
128
+
129
+ - `bzy-pre`
130
+ - `bzy-prod`
131
+ - `op-pre`
132
+ - `op-prod`
133
+ - `gitee`
134
+ - `github`
135
+ - `gitlab`
136
+
137
+ `env` now accepts custom machine-friendly values. The built-in values above remain the recommended defaults and are shown in CLI help and validation messages.
138
+
139
+ ### Examples
140
+
141
+ Add a record:
142
+
143
+ ```bash
144
+ stephen ak add -e bzy-pre -k op_sk_abcdef123456 -n Stephen
145
+ stephen ak add -e team-a-prod -k op_sk_abcdef123456 -n Stephen
146
+ ```
147
+
148
+ Get a record:
149
+
150
+ ```bash
151
+ stephen ak get -e bzy-pre -k op_sk_abcdef123456
152
+ stephen ak get --id fdb441954fd4573a72fb5a52ce359e0d77c3fa0e
153
+ ```
154
+
155
+ List records:
156
+
157
+ ```bash
158
+ stephen ak list -e bzy-pre
159
+ stephen ak list -q ste -f userName,email
160
+ stephen ak list -q op_sk_ab -f key -t
161
+ ```
162
+
163
+ Update metadata:
164
+
165
+ ```bash
166
+ stephen ak update -e bzy-pre -k op_sk_abcdef123456 -m new@example.com
167
+ ```
168
+
169
+ Delete a record:
170
+
171
+ ```bash
172
+ stephen ak delete --id fdb441954fd4573a72fb5a52ce359e0d77c3fa0e --yes
173
+ ```
174
+
175
+ ### Output Rules
176
+
177
+ - Default output is JSON.
178
+ - `-t` or `--format table` switches to table rendering.
179
+ - `--raw-key` shows the full key.
180
+ - Without `--raw-key`, the key is masked.
181
+
182
+ ### Query Rules
183
+
184
+ - `-q` / `--query` enables fuzzy search
185
+ - `-f` / `--field` selects searchable fields
186
+ - fuzzy search is supported for `userId`, `userName`, `email`, and `phone`
187
+ - `key` search is prefix-based only through a low-sensitivity prefix index
188
+
189
+ ### Short Flags
190
+
191
+ - `-e` => `--env`
192
+ - `-u` => `--user-id`
193
+ - `-n` => `--user-name`
194
+ - `-m` => `--email`
195
+ - `-p` => `--phone`
196
+ - `-k` => `--key`
197
+ - `-q` => `--query`
198
+ - `-f` => `--field`
199
+ - `-t` => table output
200
+
201
+ ## Storage Model
202
+
203
+ Runtime storage uses local SQLite. The full key is encrypted before persistence, while a small prefix index supports limited prefix search for `key`.
204
+
205
+ The database path resolves in this order:
206
+
207
+ 1. local config file `<config dir>/config.json` with `ak.dbPath`
208
+ 2. `STEPHEN_AK_DB_PATH`
209
+ 3. legacy `STEPHEN_CLI_AK_DB_PATH`
210
+ 4. default `env-paths` data directory
211
+
212
+ This keeps `ak` local-first while letting each machine point to a different synced directory such as iDrive.
213
+
214
+ ### iDrive Setup
215
+
216
+ For a synced setup, keep the config local and point the database file into the local iDrive folder on each machine.
217
+
218
+ PowerShell example:
219
+
220
+ ```powershell
221
+ $env:STEPHEN_AK_DB_PATH = 'D:\iDrive\stephen\ak.db'
222
+ ```
223
+
224
+ Local config file example:
225
+
226
+ ```json
227
+ {
228
+ "ak": {
229
+ "dbPath": "D:\\iDrive\\stephen\\ak.db"
230
+ }
231
+ }
232
+ ```
233
+
234
+ If both are present, the local config file wins. `config get` and `config list` will still show the environment variable in `envValue`, but the effective `source` becomes `"config"`. `STEPHEN_CLI_AK_DB_PATH` is still accepted as a legacy fallback for existing machines.
235
+
236
+ ## `config` Command
237
+
238
+ The `config` command manages local CLI configuration values.
239
+
240
+ Current supported keys:
241
+
242
+ - `ak.dbPath`
243
+
244
+ ### Examples
245
+
246
+ List all config values and their effective sources:
247
+
248
+ ```bash
249
+ stephen config list
250
+ ```
251
+
252
+ Get one config value:
253
+
254
+ ```bash
255
+ stephen config get ak.dbPath
256
+ ```
257
+
258
+ Set one config value in the local config file:
259
+
260
+ ```bash
261
+ stephen config set ak.dbPath D:\iDrive\stephen\ak.db
262
+ ```
263
+
264
+ `config set` always writes the local config file. If `STEPHEN_AK_DB_PATH` or the legacy `STEPHEN_CLI_AK_DB_PATH` is also set, the file config still has higher priority for the effective runtime value, and `config get` / `config list` will show `source: "config"`.
265
+
266
+ The persisted record shape is conceptually:
267
+
268
+ ```ts
269
+ interface AkRecord {
270
+ id: string; // sha1(key)
271
+ env: string; // recommended values exist, custom values allowed
272
+ userId: string | null;
273
+ userName: string | null;
274
+ email: string | null;
275
+ phone: string | null;
276
+ keyCiphertext: string;
277
+ keySearchPrefix: string;
278
+ createdAt: string;
279
+ updatedAt: string;
280
+ }
281
+ ```
282
+
283
+ ## `disk cleanup` Command
284
+
285
+ The `disk cleanup` command provides layered Windows cleanup. It previews by default, uses JSON output by default, and avoids deleting user data such as Downloads.
286
+
287
+ Cleanup levels:
288
+
289
+ - `safe`: current conservative cache cleanup. This is the default.
290
+ - `dev`: `safe` plus common developer caches.
291
+ - `system`: `safe` plus Windows system cleanup actions. Applying this level requires `--confirm`.
292
+ - `deep`: `dev` plus `system`, and reports the top 100 largest Downloads files/folders without deleting them. Applying this level requires `--confirm`.
293
+
294
+ `safe` targets:
295
+
296
+ - `%USERPROFILE%\AppData\Local\npm-cache`
297
+ - `%USERPROFILE%\AppData\Local\NuGet`
298
+ - `%USERPROFILE%\.cache`
299
+ - `%USERPROFILE%\.m2`
300
+ - `%USERPROFILE%\AppData\Local\Temp`
301
+ - `%SystemRoot%\SoftwareDistribution\Download`
302
+
303
+ Additional `dev` targets:
304
+
305
+ - `%USERPROFILE%\.gradle\caches`
306
+ - `%USERPROFILE%\.pnpm-store`
307
+ - `%USERPROFILE%\AppData\Local\pnpm\store`
308
+ - `%USERPROFILE%\AppData\Local\Yarn\Cache`
309
+ - `%USERPROFILE%\AppData\Local\pip\Cache`
310
+
311
+ Additional `system` actions:
312
+
313
+ - `%SystemRoot%\Temp`
314
+ - `dism.exe /Online /Cleanup-Image /StartComponentCleanup`
315
+
316
+ ### Examples
317
+
318
+ Preview cleanup results in JSON:
319
+
320
+ ```bash
321
+ stephen disk cleanup
322
+ ```
323
+
324
+ Preview developer cleanup:
325
+
326
+ ```bash
327
+ stephen disk cleanup --level dev
328
+ ```
329
+
330
+ Preview deep cleanup, including Downloads top 100 entries:
331
+
332
+ ```bash
333
+ stephen disk cleanup --level deep
334
+ ```
335
+
336
+ Apply safe cleanup:
337
+
338
+ ```bash
339
+ stephen disk cleanup --apply
340
+ ```
341
+
342
+ Apply system cleanup after explicit confirmation:
343
+
344
+ ```bash
345
+ stephen disk cleanup --level system --apply --confirm
346
+ ```
347
+
348
+ Apply cleanup and disable Windows hibernation:
349
+
350
+ ```bash
351
+ stephen disk cleanup --apply --disable-hibernate
352
+ ```
353
+
354
+ Render cleanup targets as a table:
355
+
356
+ ```bash
357
+ stephen disk cleanup -t
358
+ ```
359
+
360
+ ### Output Rules
361
+
362
+ - Default output is JSON.
363
+ - `-t` or `--format table` switches to table rendering.
364
+ - Preview mode is the default.
365
+ - `--apply` is required before any cleanup is executed.
366
+ - `--confirm` is required for `system --apply` and `deep --apply`.
367
+ - Downloads is never deleted; `deep` only lists the largest 100 files/folders.
368
+
369
+ ## Verification Standard
370
+
371
+ Before calling work complete:
372
+
373
+ - run `npm test`
374
+ - run `npm run coverage`
375
+ - run `npm run build`
376
+
377
+ The project targets full unit coverage for the implemented modules.
@@ -0,0 +1,269 @@
1
+ import Database from 'better-sqlite3';
2
+ import { createInterface } from 'node:readline/promises';
3
+
4
+ type AkDatabase = Database.Database;
5
+
6
+ type AkEnv = string;
7
+ declare const AK_QUERY_FIELDS: readonly ["userId", "userName", "email", "phone", "key"];
8
+ type AkQueryField = (typeof AK_QUERY_FIELDS)[number];
9
+ interface AkRecord {
10
+ id: string;
11
+ env: AkEnv;
12
+ userId: string | null;
13
+ userName: string | null;
14
+ email: string | null;
15
+ phone: string | null;
16
+ keyCiphertext: string;
17
+ keySearchPrefix: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ }
21
+
22
+ interface AkListFilters {
23
+ env?: AkEnv;
24
+ fields?: AkQueryField[];
25
+ limit: number;
26
+ query?: string;
27
+ }
28
+ interface AkUpdateMetadataInput {
29
+ email?: string | null;
30
+ id: string;
31
+ phone?: string | null;
32
+ updatedAt: string;
33
+ userId?: string | null;
34
+ userName?: string | null;
35
+ }
36
+ declare class AkRepository {
37
+ #private;
38
+ constructor(database: AkDatabase);
39
+ insert(record: AkRecord): void;
40
+ getById(id: string): AkRecord | null;
41
+ getByEnvAndId(env: AkEnv, id: string): AkRecord | null;
42
+ list(filters: AkListFilters): AkRecord[];
43
+ updateMetadata(input: AkUpdateMetadataInput): AkRecord | null;
44
+ deleteById(id: string): boolean;
45
+ }
46
+
47
+ interface StephenCliPaths {
48
+ cache: string;
49
+ config: string;
50
+ data: string;
51
+ log: string;
52
+ temp: string;
53
+ }
54
+
55
+ interface DiskDownloadsEntry {
56
+ kind: 'file' | 'directory';
57
+ name: string;
58
+ path: string;
59
+ sizeBytes: number;
60
+ sizeGB: number;
61
+ }
62
+
63
+ interface DiskCleanupRuntime {
64
+ clearDirectoryContents: (path: string) => Promise<void>;
65
+ disableHibernation: () => Promise<void>;
66
+ inspectPath: (path: string) => Promise<{
67
+ exists: boolean;
68
+ isDirectory: boolean;
69
+ sizeBytes: number;
70
+ }>;
71
+ listTopEntriesBySize: (path: string, limit: number) => Promise<DiskDownloadsEntry[]>;
72
+ runCommand: (file: string, args: string[]) => Promise<void>;
73
+ }
74
+ interface DiskCleanupRoots {
75
+ systemRoot: string;
76
+ userProfileRoot: string;
77
+ }
78
+
79
+ type VideoCandidateType = 'm3u8' | 'mp4';
80
+ type VideoCandidateOrigin = 'network' | 'html' | 'script' | 'direct-input';
81
+ interface VideoCandidate {
82
+ confidence?: number;
83
+ mimeType?: string;
84
+ origin: VideoCandidateOrigin;
85
+ type: VideoCandidateType;
86
+ url: string;
87
+ }
88
+
89
+ interface VideoExecResult {
90
+ code: number;
91
+ stderr: string;
92
+ stdout: string;
93
+ }
94
+ interface VideoFetchResponse {
95
+ arrayBuffer: () => Promise<ArrayBuffer | Uint8Array>;
96
+ body?: ReadableStream<Uint8Array> | null;
97
+ headers: Headers;
98
+ ok: boolean;
99
+ status: number;
100
+ text: () => Promise<string>;
101
+ }
102
+ interface VideoRuntime {
103
+ execFile: (file: string, args: string[]) => Promise<VideoExecResult>;
104
+ fetch: (input: string, init?: RequestInit) => Promise<VideoFetchResponse>;
105
+ launchBrowserSniffer: (url: string, options?: {
106
+ noProxy?: boolean;
107
+ proxyUrl?: string;
108
+ }) => Promise<VideoCandidate[]>;
109
+ writeFile: (path: string, data: Uint8Array) => Promise<void>;
110
+ }
111
+
112
+ interface Kr36Request {
113
+ headers: Record<string, string>;
114
+ url: string;
115
+ }
116
+ interface Kr36JsonRequest {
117
+ body: unknown;
118
+ headers: Record<string, string>;
119
+ url: string;
120
+ }
121
+
122
+ interface Kr36Runtime {
123
+ fetchArticleHtml: (request: Kr36Request) => Promise<string>;
124
+ fetchJson: (request: Kr36JsonRequest) => Promise<string>;
125
+ }
126
+
127
+ type ToutiaoSource = 'tech' | 'AI' | '光刻机' | '芯片' | '半导体';
128
+ interface ToutiaoItem {
129
+ abstract?: string;
130
+ authorName?: string;
131
+ commentCount?: number;
132
+ id: string;
133
+ image?: string;
134
+ publishTime?: {
135
+ iso: string;
136
+ local: string;
137
+ seconds: number;
138
+ };
139
+ sourceUrl?: string;
140
+ title: string;
141
+ url: string;
142
+ }
143
+ interface ToutiaoAuthorRuntimeResult {
144
+ authorToken: string;
145
+ hasMore: boolean;
146
+ items: ToutiaoItem[];
147
+ next?: {
148
+ maxBehotTime?: number;
149
+ offset?: number;
150
+ };
151
+ }
152
+ interface ToutiaoArticle {
153
+ authorName?: string;
154
+ content: {
155
+ paragraphs: string[];
156
+ text: string;
157
+ };
158
+ id: string;
159
+ publishTimeText?: string;
160
+ request: {
161
+ input: string;
162
+ url: string;
163
+ };
164
+ title: string;
165
+ url: string;
166
+ }
167
+ interface ToutiaoRuntimeListResult {
168
+ hasMore: boolean;
169
+ items: ToutiaoItem[];
170
+ keyword?: string;
171
+ next?: {
172
+ maxBehotTime?: number;
173
+ offset?: number;
174
+ };
175
+ source: ToutiaoSource;
176
+ }
177
+
178
+ interface ToutiaoRuntime {
179
+ fetchArticle: (request: {
180
+ input: string;
181
+ url: string;
182
+ }) => Promise<ToutiaoArticle>;
183
+ fetchAuthorArticles: (options: {
184
+ authorToken: string;
185
+ pages: number;
186
+ url: string;
187
+ }) => Promise<ToutiaoAuthorRuntimeResult>;
188
+ fetchKeywordInformation: (options: {
189
+ keyword: ToutiaoSource;
190
+ pages: number;
191
+ source: ToutiaoSource;
192
+ }) => Promise<ToutiaoRuntimeListResult>;
193
+ fetchTechnologyChannel: (options: {
194
+ pages: number;
195
+ }) => Promise<ToutiaoRuntimeListResult>;
196
+ }
197
+
198
+ type HackerNewsStorySource = 'top' | 'new' | 'best';
199
+ type HackerNewsSearchSort = 'relevance' | 'date';
200
+ interface HackerNewsItem {
201
+ author?: string;
202
+ commentCount?: number;
203
+ id: number;
204
+ score?: number;
205
+ text?: string;
206
+ time?: {
207
+ iso: string;
208
+ seconds: number;
209
+ };
210
+ title: string;
211
+ type: 'story';
212
+ url: string;
213
+ }
214
+ interface HackerNewsStoriesRuntimeResult {
215
+ items: HackerNewsItem[];
216
+ source: HackerNewsStorySource;
217
+ }
218
+ interface HackerNewsSearchRuntimeResult {
219
+ items: HackerNewsItem[];
220
+ query: string;
221
+ }
222
+
223
+ interface HackerNewsRuntime {
224
+ fetchSearch: (options: {
225
+ limit: number;
226
+ query: string;
227
+ sort: HackerNewsSearchSort;
228
+ }) => Promise<HackerNewsSearchRuntimeResult>;
229
+ fetchStories: (options: {
230
+ limit: number;
231
+ source: HackerNewsStorySource;
232
+ }) => Promise<HackerNewsStoriesRuntimeResult>;
233
+ }
234
+
235
+ interface AkCliDependencies {
236
+ confirm: (message: string) => Promise<boolean>;
237
+ diskRuntime: DiskCleanupRuntime;
238
+ env: NodeJS.ProcessEnv;
239
+ getRepository: () => AkRepository;
240
+ hackerNewsRuntime: HackerNewsRuntime;
241
+ kr36Runtime: Kr36Runtime;
242
+ masterKey: Buffer;
243
+ now: () => string;
244
+ paths: StephenCliPaths;
245
+ resolveDiskCleanupRoots: () => DiskCleanupRoots;
246
+ stderr: (value: string) => void;
247
+ stdout: (value: string) => void;
248
+ toutiaoRuntime: ToutiaoRuntime;
249
+ videoRuntime: VideoRuntime;
250
+ }
251
+ interface AkCliRunner {
252
+ run: (args: string[]) => Promise<number>;
253
+ }
254
+
255
+ interface CreateCliOverrides extends Partial<Omit<AkCliDependencies, 'getRepository'>> {
256
+ diskRuntime?: DiskCleanupRuntime;
257
+ env?: NodeJS.ProcessEnv;
258
+ hackerNewsRuntime?: HackerNewsRuntime;
259
+ paths?: StephenCliPaths;
260
+ repository?: AkRepository;
261
+ kr36Runtime?: Kr36Runtime;
262
+ toutiaoRuntime?: ToutiaoRuntime;
263
+ videoRuntime?: VideoRuntime;
264
+ }
265
+ declare function createCli(overrides?: CreateCliOverrides): AkCliRunner;
266
+ declare function defaultConfirm(message: string, createReadline?: () => Pick<ReturnType<typeof createInterface>, 'question' | 'close'>): Promise<boolean>;
267
+ declare function isMainEntrypoint(moduleUrl: string, argv: string[]): boolean;
268
+
269
+ export { type CreateCliOverrides, createCli, defaultConfirm, isMainEntrypoint };