@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 +21 -0
- package/README.md +377 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.js +4239 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
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.
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|