rvlib-shipkit 2.4.0 → 2.6.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/CHANGELOG.md +12 -0
- package/package.json +2 -2
- package/src/cli/cmd_Commands.ts +26 -5
- package/src/cli/cmd_FleetPush.ts +47 -0
- package/src/cli/cmd_GlobalProcesses.ts +5 -5
- package/src/cli/cmd_Review.ts +16 -1
- package/src/cli/cmd_Trailer.ts +4 -1
- package/src/cli/family-pages.ts +49 -0
- package/src/cli/kit/builtins.ts +1 -0
- package/src/cli/registry.ts +137 -0
- package/src/cli.ts +47 -135
- package/src/core/last-good.ts +217 -0
- package/src/core/load-probe.ts +71 -0
- package/src/core/reexec.ts +5 -3
- package/src/fleet/push-fleet.ts +80 -0
- package/src/home/home-routes.ts +12 -2
- package/src/home/lib-watch.ts +110 -20
- package/src/home/process-rows.ts +4 -2
- package/src/home/run-daemon.ts +1 -1
- package/src/review/model.ts +19 -0
- package/src/review/paste.ts +30 -0
- package/src/review/routes.ts +10 -3
- package/src/scaffold/files/agent-index.md +2 -2
- package/src/scaffold/project-scaffold.ts +2 -2
- package/src/serve/hub-app/activity-st.ts +31 -0
- package/src/serve/hub-app/activity-view.tsx +9 -0
- package/src/serve/hub-app/activity.css +6 -0
- package/src/serve/hub-app/home-strip.tsx +3 -1
- package/src/serve/hub-app/machine-st.ts +1 -1
- package/src/serve/hub-app/review/review-answer.tsx +16 -37
- package/src/serve/hub-app/review/review-page.tsx +8 -1
- package/src/serve/hub-app/review/review-st.ts +51 -3
- package/src/serve/hub-app/review/review-views.tsx +1 -1
- package/src/serve/hub-app/review.css +4 -4
- package/src/serve/run-serve.ts +25 -0
- package/src/serve/serve-hub.ts +8 -1
- package/src/serve/stale-restart.ts +19 -2
- package/src/trailer/build.ts +16 -7
- package/src/trailer/ffmpeg.ts +21 -1
- package/src/trailer/grammar.ts +56 -11
- package/src/trailer/look.ts +31 -16
- package/src/trailer/prune.ts +59 -12
- package/src/trailer/score/dsp.ts +87 -27
- package/src/trailer/score/pattern.ts +1 -1
- package/src/trailer/score/synth.ts +26 -5
- package/src/trailer/titles.ts +63 -34
- package/src/trailer/vocab.ts +65 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 2.6.0
|
|
2
|
+
|
|
3
|
+
- **A trailer's score sounds as the game's browser synth, section for section.** A note that starts inside a 128 frame block takes the phase the browser gives it (it runs at the default 440 Hz until its own frame of that block), so overlapping notes of one pitch, a timpani roll, add or cancel as in the browser; `osc: 'square'` is the browser's own square wave, no longer a sine; the master's compressor and limiter are the browser's kernel (32 frame divisions, adaptive release, the sine warp on the gain). pkm-multi's main4 score: 38 of 38 sections within 0.1 dB of the game's render (were 18), each octave band within 0.15 dB. Every score renders again once.
|
|
4
|
+
|
|
5
|
+
## 2.5.0
|
|
6
|
+
|
|
7
|
+
- **A review card hands itself to any agent session.** A small copy icon on the card's header (or C) copies one block: its title and state, its repo, `cd <repo> && sk review show <id>`, its link here and on the phone when the repo has a public host; a toast says what was copied. `sk review show <id> --paste` prints the same block.
|
|
8
|
+
- **The overall comment box sits under the card's header**, after the verdicts, on every card and in every layout.
|
|
9
|
+
- **Push every unpushed repo: `sk fleet push` and a button on the activity page.** Each house repo with commits its remote lacks gets a plain `git push`, never a force; a branch with no upstream goes `-u` to its one remote; a branch that is also behind, a gone upstream or a detached head is skipped with the reason. `--dry` plans only.
|
|
10
|
+
|
|
11
|
+
- **A new repo's agent/index.md routes with `→`.** The scaffold's table rows, the project CLI's row and its `next:` hint write `→ agent/<page>.md`, the wiki's form for a page to open, instead of a backticked path.
|
|
12
|
+
|
|
1
13
|
## 2.3.0
|
|
2
14
|
|
|
3
15
|
- **A sound is a review view.** `sk review add --audio <sound>`, a sound in `--view`, `add-view <id> "<label>" --audio <sound>`, or a before and after of two sounds: the store keeps the sound and draws its waveform (`wave.png`, `before-wave.png`), and the hub shows each waveform over a player, one row a side. A sound takes reactions and words, never a rectangle; a pair is never a sound and an image.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rvlib-shipkit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"funding": "https://github.com/sponsors/rvion",
|
|
5
5
|
"description": "All-in-one repo companion: ci gate (task DAG), auto-discovered health checks, release-contract fulfillness, asks queue, md-wiki tools, asset atelier, live tui",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@floating-ui/react": "^0.27.20",
|
|
39
|
-
"@napi-rs/canvas": "^1.0
|
|
39
|
+
"@napi-rs/canvas": "^1.1.0",
|
|
40
40
|
"clipanion": "^4.0.0-rc.4",
|
|
41
41
|
"comfy-ts": "^2.9.0",
|
|
42
42
|
"ink": "^7.1.1",
|
package/src/cli/cmd_Commands.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// (the kit in cli/kit/) come out of these functions.
|
|
6
6
|
import { Command, Option } from 'clipanion'
|
|
7
7
|
import { spliceMarkedBlock } from '../core/doc-block.ts'
|
|
8
|
+
import { FAMILY_PAGES } from './family-pages.ts'
|
|
8
9
|
import { type Essential, type Film, marksOf, ROW_OF, runText } from './kit/verb.ts'
|
|
9
10
|
|
|
10
11
|
export type CommandOption = { definition: string; description: string }
|
|
@@ -117,12 +118,13 @@ export function renderMarkdown(rows: CommandRow[], bin = 'sk'): string {
|
|
|
117
118
|
|
|
118
119
|
/** the eager form: one line per command, its positional arguments and its
|
|
119
120
|
* description. Flags and examples are `<bin> <command> --help`, so a page every
|
|
120
|
-
* session loads costs a line per command, not a screen
|
|
121
|
-
|
|
121
|
+
* session loads costs a line per command, not a screen. `pages` puts each
|
|
122
|
+
* family's owner page in its heading: `### Trailer → build/trailer.md` */
|
|
123
|
+
export function renderCompact(rows: CommandRow[], bin = 'sk', pages: Readonly<Record<string, string>> | null = null): string {
|
|
122
124
|
const out: string[] = []
|
|
123
125
|
let cat = ''
|
|
124
126
|
for (const r of rows) {
|
|
125
|
-
if (r.category !== cat) { cat = r.category; out.push(`\n### ${cat}\n`) }
|
|
127
|
+
if (r.category !== cat) { cat = r.category; out.push(`\n### ${cat}${pages?.[cat] != null ? ` → ${pages[cat]}` : ''}\n`) }
|
|
126
128
|
const sig = r.usage.replace(/^\$0/, bin).replace(/\s+\[(?:-|<\w+>)[^\]]*\]/g, '').trim() || `${bin} ${r.path}`
|
|
127
129
|
out.push(`- \`${sig}\` — ${r.description}`)
|
|
128
130
|
}
|
|
@@ -154,6 +156,15 @@ export function renderEssentials(rows: CommandRow[], bin: string, command: strin
|
|
|
154
156
|
return `${out.join('\n')}\n`
|
|
155
157
|
}
|
|
156
158
|
|
|
159
|
+
/** a family with no owner page, and a page for a family no command has: one line each */
|
|
160
|
+
export function familyProblems(rows: CommandRow[], pages: Readonly<Record<string, string>>): string[] {
|
|
161
|
+
const families = new Set(rows.map((r) => r.category))
|
|
162
|
+
return [
|
|
163
|
+
...[...families].filter((f) => pages[f] == null).map((f) => `family ${f}: no owner page in src/cli/family-pages.ts`),
|
|
164
|
+
...Object.keys(pages).filter((f) => !families.has(f)).map((f) => `family ${f}: src/cli/family-pages.ts names a page for a family no command has`),
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
|
|
157
168
|
/** what a project CLI's registry must hold for its pages and its listing to
|
|
158
169
|
* teach right: a category, a description under the cap, and an example that
|
|
159
170
|
* starts with the command's own words. One line per breach */
|
|
@@ -209,6 +220,9 @@ export class CommandsCommand extends Command {
|
|
|
209
220
|
* a breach), and its --out creates a missing page */
|
|
210
221
|
static shapeRule = false
|
|
211
222
|
|
|
223
|
+
/** each family's owner page, named in the compact page's headings; a project CLI has none */
|
|
224
|
+
static familyPages: Readonly<Record<string, string>> | null = FAMILY_PAGES
|
|
225
|
+
|
|
212
226
|
json = Option.Boolean('--json', false, { description: 'machine-readable rows, with film and essential where a command carries them' })
|
|
213
227
|
out = Option.String('--out', { description: 'host file carrying the <bin>:commands markers. The block between them is rewritten' })
|
|
214
228
|
check = Option.Boolean('--check', false, { description: 'with --out or --essentials: exit 1 if a page is stale, write nothing' })
|
|
@@ -225,10 +239,17 @@ export class CommandsCommand extends Command {
|
|
|
225
239
|
classes,
|
|
226
240
|
)
|
|
227
241
|
const write = (s: string): void => void this.context.stdout.write(s)
|
|
242
|
+
const pages = (this.constructor as typeof CommandsCommand).familyPages
|
|
243
|
+
const render = (): string => (this.compact ? renderCompact(rows, bin, pages) : renderMarkdown(rows, bin))
|
|
228
244
|
if (this.out == null && this.essentials == null) {
|
|
229
|
-
write(this.json ? `${JSON.stringify(rows)}\n` : `${(
|
|
245
|
+
write(this.json ? `${JSON.stringify(rows)}\n` : `${render()}\n`)
|
|
230
246
|
return 0
|
|
231
247
|
}
|
|
248
|
+
if (this.out != null && this.compact && pages != null) {
|
|
249
|
+
const bad = familyProblems(rows, pages)
|
|
250
|
+
for (const b of bad) write(`FAIL: ${b}\n`)
|
|
251
|
+
if (bad.length > 0) { write(' fix: one row per family in src/cli/family-pages.ts, the wiki page that owns it\n'); return 1 }
|
|
252
|
+
}
|
|
232
253
|
if ((this.constructor as typeof CommandsCommand).shapeRule) {
|
|
233
254
|
const bad = shapeProblems(rows, bin)
|
|
234
255
|
for (const b of bad) write(`FAIL: ${b}\n`)
|
|
@@ -250,7 +271,7 @@ export class CommandsCommand extends Command {
|
|
|
250
271
|
const project = (this.constructor as typeof CommandsCommand).shapeRule
|
|
251
272
|
if (!existsSync(this.out) && (!project || this.check)) { write(`FAIL: ${this.out} does not exist\n`); return 1 }
|
|
252
273
|
const host = existsSync(this.out) ? readFileSync(this.out, 'utf8') : newCommandsPage(bin, this.out)
|
|
253
|
-
const next = spliceBlock(host, (
|
|
274
|
+
const next = spliceBlock(host, render(), bin)
|
|
254
275
|
if (next == null) { write(`FAIL: ${this.out} has no ${begin} / ${end} markers\n`); return 1 }
|
|
255
276
|
if (next === host) { write(`ok: ${this.out} command index current (${rows.length} commands)\n`); return code }
|
|
256
277
|
if (this.check) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// shipkit fleet push — every house repo that holds commits its remote does
|
|
2
|
+
// not, pushed: a plain git push, never a force (fleet/push-fleet.ts, the same
|
|
3
|
+
// path as the activity page's push button). A repo that fell behind waits for
|
|
4
|
+
// a pull, and says so.
|
|
5
|
+
import { Command, Option } from 'clipanion'
|
|
6
|
+
import { homedir } from 'os'
|
|
7
|
+
import { gitRoot } from '../core/git-root.ts'
|
|
8
|
+
import { pushFleet } from '../fleet/push-fleet.ts'
|
|
9
|
+
import { houseRepos } from '../serve/project-gutter.ts'
|
|
10
|
+
import { listFlag } from './list-flag.ts'
|
|
11
|
+
|
|
12
|
+
export class FleetPushCommand extends Command {
|
|
13
|
+
static override paths = [['fleet', 'push']]
|
|
14
|
+
|
|
15
|
+
static override usage = Command.Usage({
|
|
16
|
+
category: 'Health',
|
|
17
|
+
description: 'push every house repo with unpushed commits: a plain git push, never a force',
|
|
18
|
+
examples: [
|
|
19
|
+
['push what is unpushed, everywhere', 'sk fleet push'],
|
|
20
|
+
['what would go out', 'sk fleet push --dry'],
|
|
21
|
+
['some repos only', 'sk fleet push --only my-app --only other'],
|
|
22
|
+
],
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
dry = Option.Boolean('--dry', false, { description: 'plan only: say what would be pushed and what is skipped, push nothing' })
|
|
26
|
+
only = Option.Array('--only', { description: 'limit to these repo names (repeatable)' })
|
|
27
|
+
all = Option.Boolean('--all', false, { description: 'also print the repos that have nothing to push' })
|
|
28
|
+
|
|
29
|
+
async execute(): Promise<number> {
|
|
30
|
+
const root = gitRoot(process.cwd())?.top ?? process.cwd()
|
|
31
|
+
let repos = houseRepos(root, homedir()).repos.map((r) => ({ name: r.name, path: r.path }))
|
|
32
|
+
const only = listFlag(this.only)
|
|
33
|
+
if (only.length > 0) repos = repos.filter((r) => only.includes(r.name))
|
|
34
|
+
const w = (l: string) => this.context.stdout.write(`${l}\n`)
|
|
35
|
+
if (repos.length === 0) {
|
|
36
|
+
w(`skip: no house repo found from ${root}`)
|
|
37
|
+
return 0
|
|
38
|
+
}
|
|
39
|
+
const res = await pushFleet(repos, { dry: this.dry })
|
|
40
|
+
for (const r of res) if (this.all || r.action !== 'none') w(r.line)
|
|
41
|
+
const pushed = res.filter((r) => r.ok && (r.action === 'push' || r.action === 'push-upstream')).length
|
|
42
|
+
const failed = res.filter((r) => !r.ok && r.action !== 'skip').length
|
|
43
|
+
const skipped = res.filter((r) => r.action === 'skip').length
|
|
44
|
+
w(`${failed > 0 ? 'FAIL' : 'ok'}: ${repos.length} repos, ${this.dry ? `${res.filter((r) => r.action === 'push' || r.action === 'push-upstream').length} would push` : `${pushed} pushed`}, ${skipped} skipped${failed > 0 ? `, ${failed} failed` : ''}`)
|
|
45
|
+
return failed > 0 ? 1 : 0
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -28,7 +28,7 @@ export type GlobalProcessesAnswer = {
|
|
|
28
28
|
export type GlobalProcessesDeps = {
|
|
29
29
|
pm: () => Promise<PmAnswer | null>
|
|
30
30
|
/** the daemon's identity, for its version; null when it does not answer */
|
|
31
|
-
daemon?: () => Promise<{ version: string } | null>
|
|
31
|
+
daemon?: () => Promise<{ version: string; held?: string | null } | null>
|
|
32
32
|
/** the declared units, read like pm reads them; null when no house is found */
|
|
33
33
|
declared: () => Promise<Pick<PmConfig, 'processes' | 'errors'> | null>
|
|
34
34
|
/** the project list's order */
|
|
@@ -43,18 +43,18 @@ const localPorts = () => ({ pm: pmPort(), daemon: daemonPort(), web: homePort()
|
|
|
43
43
|
* pm does not answer */
|
|
44
44
|
export async function globalProcessesAnswer(d: GlobalProcessesDeps): Promise<GlobalProcessesAnswer> {
|
|
45
45
|
const [pm, daemon] = await Promise.all([d.pm(), d.daemon?.() ?? null])
|
|
46
|
-
const core = { daemonVersion: daemon?.version ?? null, ports: localPorts() }
|
|
46
|
+
const core = { daemonVersion: daemon?.version ?? null, daemonHeld: daemon?.held ?? null, ports: localPorts() }
|
|
47
47
|
if (pm != null) return { pm: { pid: pm.pid, version: pm.version }, now: d.now, groups: processGroups(pm, d.order, core), errors: pm.unitErrors, house: true }
|
|
48
48
|
const c = await d.declared()
|
|
49
49
|
return { pm: null, now: d.now, groups: [coreGroup(null, core), ...groupRows((c?.processes ?? []).map(declaredRow), d.order)], errors: c?.errors ?? [], house: c != null }
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/** the daemon's identity at /hub.json, or null */
|
|
53
|
-
export async function askDaemon(url = daemonUrl()): Promise<{ version: string } | null> {
|
|
53
|
+
export async function askDaemon(url = daemonUrl()): Promise<{ version: string; held: string | null } | null> {
|
|
54
54
|
try {
|
|
55
55
|
const r = await fetch(`${url}/hub.json`, { signal: AbortSignal.timeout(3_000) })
|
|
56
|
-
const j = r.ok ? ((await r.json()) as { hub?: string; version?: string }) : null
|
|
57
|
-
return j?.hub === 'shipkit-home' && typeof j.version === 'string' ? { version: j.version } : null
|
|
56
|
+
const j = r.ok ? ((await r.json()) as { hub?: string; version?: string; held?: string | null }) : null
|
|
57
|
+
return j?.hub === 'shipkit-home' && typeof j.version === 'string' ? { version: j.version, held: j.held ?? null } : null
|
|
58
58
|
} catch {
|
|
59
59
|
return null
|
|
60
60
|
}
|
package/src/cli/cmd_Review.ts
CHANGED
|
@@ -345,8 +345,14 @@ export class ReviewLsCommand extends Command {
|
|
|
345
345
|
|
|
346
346
|
export class ReviewShowCommand extends Command {
|
|
347
347
|
static override paths = [['review', 'show']]
|
|
348
|
-
static override usage = Command.Usage({
|
|
348
|
+
static override usage = Command.Usage({
|
|
349
|
+
category: 'Review',
|
|
350
|
+
description: 'one item and its thread: the verdict, rectangles, reactions, the whole conversation',
|
|
351
|
+
details: `${DETAILS}\n\nTakes an item id or a player report's ref (live#3). --paste prints the short block that hands the card to another agent session (the hub's copy button gives the same).`,
|
|
352
|
+
examples: [['hand a card to another session', 'sk review show <id> --paste']],
|
|
353
|
+
})
|
|
349
354
|
id = Option.String()
|
|
355
|
+
paste = Option.Boolean('--paste', false, { description: 'the block another agent session acts on: title, repo, this command, the links' })
|
|
350
356
|
|
|
351
357
|
async execute(): Promise<number> {
|
|
352
358
|
return run(this.context, async (h) => {
|
|
@@ -357,6 +363,15 @@ export class ReviewShowCommand extends Command {
|
|
|
357
363
|
const all = readAllCached(h.dir)
|
|
358
364
|
const x = all.items.find((y) => y.item.id === id)
|
|
359
365
|
if (!x) throw new Error(`no item ${this.id}`)
|
|
366
|
+
if (this.paste) {
|
|
367
|
+
const { dirname } = await import('node:path')
|
|
368
|
+
const { pasteHosts, cardUrl } = await import('../review/paste.ts')
|
|
369
|
+
const { pasteBlock, STATUS_LABEL } = await import('../review/model.ts')
|
|
370
|
+
const { statusOf } = await import('../review/threads.ts')
|
|
371
|
+
const w = await pasteHosts(dirname(dirname(h.dir)))
|
|
372
|
+
h.out(pasteBlock(x.item, STATUS_LABEL[statusOf(x, all.items)], { root: w.root, open: cardUrl(w.open, x.item.id), phone: w.phone ? cardUrl(w.phone, x.item.id) : null }))
|
|
373
|
+
return 0
|
|
374
|
+
}
|
|
360
375
|
const t = threadOfItem(x.item.id, threadsOf(all.items))
|
|
361
376
|
h.out(t && (t.head.item.id === x.item.id || t.answers.length > 0) ? threadDetail(t, h.dir, true, h.say) : detail(x, h.dir, true, false, h.say))
|
|
362
377
|
return 0
|
package/src/cli/cmd_Trailer.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// sk trailer: a cut's .trailer file → its mp4, filming only the takes whose film line changed (trailer/build.ts).
|
|
2
2
|
// Every module loads inside execute: the cli registers this file on every `sk` call
|
|
3
3
|
import { Command, Option } from 'clipanion'
|
|
4
|
+
import { pageAt } from './family-pages.ts'
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
+
const PAGE = pageAt('build/trailer.md')
|
|
7
|
+
const DETAILS = `the trailer language: shots with a film line each (clip <file>, image <file>, card, run "<cmd {out}>", url <route> through the shot service, grid and split of other takes, or a film row of the project CLI), footage blocks, titles in the brand's look, cuts, sections in bars, music, sfx and voice; a \`vertical\` header finishes a short with the brand's lockup, watermark and end card. A repo plugs in one trailer({...}) unit: sounds by id, the world's paths, content checks, a line's own take. Outputs land in trailer/<trailer>/out/. Read first: ${PAGE}, then its folder build/trailer/ (the score, the craft, a book of ideas, extending the language)`
|
|
6
8
|
|
|
7
9
|
/** --refilm alone: every stale take; --refilm a,b: those shots */
|
|
8
10
|
const refilmOf = (v: string | boolean | undefined): 'stale' | ReadonlySet<string> | null => (v === undefined || v === false ? null : v === true ? 'stale' : new Set(v.split(',')))
|
|
@@ -16,6 +18,7 @@ async function run(context: { stdout: NodeJS.WritableStream; stderr: NodeJS.Writ
|
|
|
16
18
|
return await body(say, findRepoRoot(cwd), cwd)
|
|
17
19
|
} catch (e) {
|
|
18
20
|
context.stderr.write(`FAIL: ${e instanceof Refused ? `trailer: ${e.message}` : e instanceof Error ? (e.stack ?? e.message) : String(e)}\n`)
|
|
21
|
+
if (e instanceof Refused) context.stderr.write(` fix: the language is ${PAGE}\n`)
|
|
19
22
|
return 1
|
|
20
23
|
}
|
|
21
24
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// the wiki page that owns each sk command family, a path from the root of the wiki the lib lives in. The always
|
|
2
|
+
// loaded command page names it in the family's heading, so `sk commands --out` fails on a family missing here
|
|
3
|
+
import { existsSync } from 'fs'
|
|
4
|
+
import { homedir } from 'os'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
|
|
7
|
+
export const FAMILY_PAGES: Readonly<Record<string, string>> = {
|
|
8
|
+
Asks: 'world/human-loop.md',
|
|
9
|
+
Assets: 'build/generate-assets.md',
|
|
10
|
+
Gate: 'build/shipkit.md',
|
|
11
|
+
Health: 'build/shipkit.md',
|
|
12
|
+
Home: 'build/shipkit/home.md',
|
|
13
|
+
Refactor: 'build/typescript.md',
|
|
14
|
+
Review: 'build/shipkit/review.md',
|
|
15
|
+
Scaffold: 'build/pocketbase.md',
|
|
16
|
+
Serve: 'build/shipkit/home.md',
|
|
17
|
+
Setup: 'meta/rv-conventions.md',
|
|
18
|
+
Sound: 'build/trailer.md',
|
|
19
|
+
Trailer: 'build/trailer.md',
|
|
20
|
+
Wiki: 'build/mdwiki.md',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** a page as a path any repo can read, when the lib runs from inside its wiki (`<wiki>/build/shipkit/rvlib-shipkit`);
|
|
24
|
+
* from an install, the page's wiki path */
|
|
25
|
+
export function pageAt(rel: string): string {
|
|
26
|
+
const abs = join(import.meta.dir, '../../../../..', rel)
|
|
27
|
+
if (!existsSync(abs)) return `wiki ${rel}`
|
|
28
|
+
const home = homedir()
|
|
29
|
+
return abs.startsWith(`${home}/`) ? `~${abs.slice(home.length)}` : abs
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Listed = { contexts?: { commandClass: { usage?: { category?: string | null } } }[]; commands?: number[]; execute(): Promise<number | void>; context: { stdout: { write(s: string): unknown } } }
|
|
33
|
+
|
|
34
|
+
/** `sk <family> --help` lists the family's commands (clipanion's help for several matches): the family's page
|
|
35
|
+
* follows the list. Any other command passes through */
|
|
36
|
+
export function withFamilyPage<C extends object>(command: C, pages: Readonly<Record<string, string>> = FAMILY_PAGES): C {
|
|
37
|
+
const h = command as C & Listed
|
|
38
|
+
if (!Array.isArray(h.contexts) || !Array.isArray(h.commands) || h.commands.length < 2) return command
|
|
39
|
+
const families = new Set(h.commands.map((i) => h.contexts?.[i]?.commandClass.usage?.category ?? ''))
|
|
40
|
+
const page = families.size === 1 ? pages[[...families][0]!] : undefined
|
|
41
|
+
if (page == null) return command
|
|
42
|
+
const list = h.execute.bind(h)
|
|
43
|
+
h.execute = async () => {
|
|
44
|
+
const code = await list()
|
|
45
|
+
h.context.stdout.write(`Read first: ${pageAt(page)}\n`)
|
|
46
|
+
return code
|
|
47
|
+
}
|
|
48
|
+
return command
|
|
49
|
+
}
|
package/src/cli/kit/builtins.ts
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// the command registry: one command FAMILY per file in this folder
|
|
2
|
+
// (cmd_<Name>.ts), logic in plain modules the commands call. The boot
|
|
3
|
+
// (../cli.ts) loads it with an await import, so a file that fails to load is
|
|
4
|
+
// caught there. A new command registers here.
|
|
5
|
+
import { LIB_VERSION } from '../core/lib-version.ts'
|
|
6
|
+
import { Builtins, Cli, type Command } from 'clipanion'
|
|
7
|
+
import { AskNewCommand, AsksCheckCommand, AsksCommand } from './cmd_Asks.ts'
|
|
8
|
+
import { AssetsAddCommand, AssetsCheckCommand, AssetsFillCommand, AssetsGenCommand, AssetsIdentityCommand } from './cmd_Assets.ts'
|
|
9
|
+
import { BumpCommand } from './cmd_Bump.ts'
|
|
10
|
+
import { CallsCommand } from './cmd_Calls.ts'
|
|
11
|
+
import { TimeCommand } from './cmd_Time.ts'
|
|
12
|
+
import { CheckCommand } from './cmd_Check.ts'
|
|
13
|
+
import { CommandsCommand } from './cmd_Commands.ts'
|
|
14
|
+
import { withFamilyPage } from './family-pages.ts'
|
|
15
|
+
import { aliasArgs, CrossRepoActivityCommand } from './cmd_CrossRepoActivity.ts'
|
|
16
|
+
import { ConfigKeysCommand } from './cmd_ConfigKeys.ts'
|
|
17
|
+
import { GlobalProcessesCommand, GlobalProcessOpenCommand, GlobalProcessRestartCommand, GlobalProcessStartCommand, GlobalProcessStopCommand } from './cmd_GlobalProcesses.ts'
|
|
18
|
+
import { PlannedCommand } from './cmd_Planned.ts'
|
|
19
|
+
import { InsightsCommand } from './cmd_Insights.ts'
|
|
20
|
+
import { GlobalContextCommand } from './cmd_GlobalContext.ts'
|
|
21
|
+
import { OverviewCommand } from './cmd_Overview.ts'
|
|
22
|
+
import { CiCommand } from './cmd_Ci.ts'
|
|
23
|
+
import { ContractsCommand } from './cmd_Contracts.ts'
|
|
24
|
+
import { FleetCommand } from './cmd_Fleet.ts'
|
|
25
|
+
import { FleetPushCommand } from './cmd_FleetPush.ts'
|
|
26
|
+
import { DaemonCommand, GuiCommand, PmCommand, PmInstallCommand, PmUninstallCommand, WebCommand } from './cmd_Home.ts'
|
|
27
|
+
import { HooksCommitMsgCommand, HooksInstallCommand, HooksListCommand, HooksPreCommitCommand } from './cmd_Hooks.ts'
|
|
28
|
+
import { InitCommand } from './cmd_Init.ts'
|
|
29
|
+
import { KeysCommand } from './cmd_Keys.ts'
|
|
30
|
+
import { MvCommand } from './cmd_Mv.ts'
|
|
31
|
+
import { NeedsCommand } from './cmd_Needs.ts'
|
|
32
|
+
import { PbCollectionCommand } from './cmd_Pb.ts'
|
|
33
|
+
import { ReflectCommand } from './cmd_Reflect.ts'
|
|
34
|
+
import { ReleaseCommand } from './cmd_Release.ts'
|
|
35
|
+
import { ReleasesCommand } from './cmd_Releases.ts'
|
|
36
|
+
import { ChecksCommand, UnitsAliasCommand } from './cmd_Checks.ts'
|
|
37
|
+
import { WhenCommand } from './cmd_When.ts'
|
|
38
|
+
import { CacheAuditCommand } from './cmd_CacheAudit.ts'
|
|
39
|
+
import { TraceAuditCommand } from './cmd_TraceAudit.ts'
|
|
40
|
+
import { ServeCommand } from './cmd_Serve.ts'
|
|
41
|
+
import { SmokeCommand } from './cmd_Smoke.ts'
|
|
42
|
+
import { ShotCommand } from './cmd_Shot.ts'
|
|
43
|
+
import { StatusCommand } from './cmd_Status.ts'
|
|
44
|
+
import { StartCommand } from './cmd_Start.ts'
|
|
45
|
+
import { TRAILER_COMMANDS } from './cmd_Trailer.ts'
|
|
46
|
+
import { SOUND_COMMANDS } from './cmd_Sound.ts'
|
|
47
|
+
import { REVIEW_COMMANDS } from './cmd_Review.ts'
|
|
48
|
+
import { TuiCommand } from './cmd_Tui.ts'
|
|
49
|
+
import { WikiLintCommand, WikiServeCommand } from './cmd_Wiki.ts'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
/** `sk <family> --help` names the family's page under its list */
|
|
53
|
+
class FamilyHelpCli extends Cli {
|
|
54
|
+
override process(...args: unknown[]): Command {
|
|
55
|
+
return withFamilyPage((super.process as (...a: unknown[]) => Command).apply(this, args))
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** the registry, built but NOT run: a test drives the real binary in process
|
|
60
|
+
* instead of paying a cold bun start per assertion (~250ms each), and the
|
|
61
|
+
* wiring it exercises is the wiring that ships. */
|
|
62
|
+
export function buildCli(): Cli {
|
|
63
|
+
const cli = new FamilyHelpCli({
|
|
64
|
+
binaryLabel: 'shipkit — repo toolkit',
|
|
65
|
+
binaryName: 'sk',
|
|
66
|
+
binaryVersion: LIB_VERSION,
|
|
67
|
+
enableCapture: true, // console output pipes into the command streams (testable)
|
|
68
|
+
enableColors: true,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
cli.register(Builtins.HelpCommand)
|
|
72
|
+
cli.register(Builtins.VersionCommand)
|
|
73
|
+
cli.register(CiCommand)
|
|
74
|
+
cli.register(StatusCommand)
|
|
75
|
+
cli.register(BumpCommand)
|
|
76
|
+
cli.register(ReleaseCommand)
|
|
77
|
+
cli.register(ReleasesCommand)
|
|
78
|
+
cli.register(HooksInstallCommand)
|
|
79
|
+
cli.register(HooksPreCommitCommand)
|
|
80
|
+
cli.register(HooksCommitMsgCommand)
|
|
81
|
+
cli.register(HooksListCommand)
|
|
82
|
+
cli.register(MvCommand)
|
|
83
|
+
cli.register(CheckCommand)
|
|
84
|
+
cli.register(TuiCommand)
|
|
85
|
+
for (const c of TRAILER_COMMANDS) cli.register(c)
|
|
86
|
+
for (const c of SOUND_COMMANDS) cli.register(c)
|
|
87
|
+
for (const c of REVIEW_COMMANDS) cli.register(c)
|
|
88
|
+
cli.register(ServeCommand)
|
|
89
|
+
cli.register(PmCommand)
|
|
90
|
+
cli.register(DaemonCommand)
|
|
91
|
+
cli.register(WebCommand)
|
|
92
|
+
cli.register(PmInstallCommand)
|
|
93
|
+
cli.register(PmUninstallCommand)
|
|
94
|
+
cli.register(GuiCommand)
|
|
95
|
+
cli.register(ContractsCommand)
|
|
96
|
+
cli.register(AsksCommand)
|
|
97
|
+
cli.register(AsksCheckCommand)
|
|
98
|
+
cli.register(AskNewCommand)
|
|
99
|
+
cli.register(WikiServeCommand)
|
|
100
|
+
cli.register(WikiLintCommand)
|
|
101
|
+
cli.register(AssetsFillCommand)
|
|
102
|
+
cli.register(AssetsAddCommand)
|
|
103
|
+
cli.register(AssetsGenCommand)
|
|
104
|
+
cli.register(AssetsIdentityCommand)
|
|
105
|
+
cli.register(AssetsCheckCommand)
|
|
106
|
+
cli.register(InitCommand)
|
|
107
|
+
cli.register(StartCommand)
|
|
108
|
+
cli.register(NeedsCommand)
|
|
109
|
+
cli.register(FleetCommand)
|
|
110
|
+
cli.register(FleetPushCommand)
|
|
111
|
+
cli.register(PbCollectionCommand)
|
|
112
|
+
cli.register(SmokeCommand)
|
|
113
|
+
cli.register(ShotCommand)
|
|
114
|
+
cli.register(ReflectCommand)
|
|
115
|
+
cli.register(KeysCommand)
|
|
116
|
+
cli.register(GlobalProcessesCommand)
|
|
117
|
+
cli.register(GlobalProcessStartCommand)
|
|
118
|
+
cli.register(GlobalProcessStopCommand)
|
|
119
|
+
cli.register(GlobalProcessRestartCommand)
|
|
120
|
+
cli.register(GlobalProcessOpenCommand)
|
|
121
|
+
cli.register(CrossRepoActivityCommand)
|
|
122
|
+
cli.register(PlannedCommand)
|
|
123
|
+
cli.register(InsightsCommand)
|
|
124
|
+
cli.register(GlobalContextCommand)
|
|
125
|
+
cli.register(OverviewCommand)
|
|
126
|
+
cli.register(ChecksCommand)
|
|
127
|
+
cli.register(WhenCommand)
|
|
128
|
+
cli.register(CacheAuditCommand)
|
|
129
|
+
cli.register(TraceAuditCommand)
|
|
130
|
+
cli.register(UnitsAliasCommand)
|
|
131
|
+
cli.register(CommandsCommand)
|
|
132
|
+
cli.register(CallsCommand)
|
|
133
|
+
cli.register(TimeCommand)
|
|
134
|
+
cli.register(ConfigKeysCommand)
|
|
135
|
+
|
|
136
|
+
return cli
|
|
137
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,146 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import { CheckCommand } from './cli/cmd_Check.ts'
|
|
13
|
-
import { CommandsCommand } from './cli/cmd_Commands.ts'
|
|
14
|
-
import { aliasArgs, CrossRepoActivityCommand } from './cli/cmd_CrossRepoActivity.ts'
|
|
15
|
-
import { ConfigKeysCommand } from './cli/cmd_ConfigKeys.ts'
|
|
16
|
-
import { GlobalProcessesCommand, GlobalProcessOpenCommand, GlobalProcessRestartCommand, GlobalProcessStartCommand, GlobalProcessStopCommand } from './cli/cmd_GlobalProcesses.ts'
|
|
17
|
-
import { PlannedCommand } from './cli/cmd_Planned.ts'
|
|
18
|
-
import { InsightsCommand } from './cli/cmd_Insights.ts'
|
|
19
|
-
import { GlobalContextCommand } from './cli/cmd_GlobalContext.ts'
|
|
20
|
-
import { OverviewCommand } from './cli/cmd_Overview.ts'
|
|
21
|
-
import { CiCommand } from './cli/cmd_Ci.ts'
|
|
22
|
-
import { ContractsCommand } from './cli/cmd_Contracts.ts'
|
|
23
|
-
import { FleetCommand } from './cli/cmd_Fleet.ts'
|
|
24
|
-
import { DaemonCommand, GuiCommand, PmCommand, PmInstallCommand, PmUninstallCommand, WebCommand } from './cli/cmd_Home.ts'
|
|
25
|
-
import { HooksCommitMsgCommand, HooksInstallCommand, HooksListCommand, HooksPreCommitCommand } from './cli/cmd_Hooks.ts'
|
|
26
|
-
import { InitCommand } from './cli/cmd_Init.ts'
|
|
27
|
-
import { KeysCommand } from './cli/cmd_Keys.ts'
|
|
28
|
-
import { MvCommand } from './cli/cmd_Mv.ts'
|
|
29
|
-
import { NeedsCommand } from './cli/cmd_Needs.ts'
|
|
30
|
-
import { PbCollectionCommand } from './cli/cmd_Pb.ts'
|
|
31
|
-
import { ReflectCommand } from './cli/cmd_Reflect.ts'
|
|
32
|
-
import { ReleaseCommand } from './cli/cmd_Release.ts'
|
|
33
|
-
import { ReleasesCommand } from './cli/cmd_Releases.ts'
|
|
34
|
-
import { ChecksCommand, UnitsAliasCommand } from './cli/cmd_Checks.ts'
|
|
35
|
-
import { WhenCommand } from './cli/cmd_When.ts'
|
|
36
|
-
import { CacheAuditCommand } from './cli/cmd_CacheAudit.ts'
|
|
37
|
-
import { TraceAuditCommand } from './cli/cmd_TraceAudit.ts'
|
|
38
|
-
import { ServeCommand } from './cli/cmd_Serve.ts'
|
|
39
|
-
import { SmokeCommand } from './cli/cmd_Smoke.ts'
|
|
40
|
-
import { ShotCommand } from './cli/cmd_Shot.ts'
|
|
41
|
-
import { StatusCommand } from './cli/cmd_Status.ts'
|
|
42
|
-
import { StartCommand } from './cli/cmd_Start.ts'
|
|
43
|
-
import { TRAILER_COMMANDS } from './cli/cmd_Trailer.ts'
|
|
44
|
-
import { SOUND_COMMANDS } from './cli/cmd_Sound.ts'
|
|
45
|
-
import { REVIEW_COMMANDS } from './cli/cmd_Review.ts'
|
|
46
|
-
import { TuiCommand } from './cli/cmd_Tui.ts'
|
|
47
|
-
import { WikiLintCommand, WikiServeCommand } from './cli/cmd_Wiki.ts'
|
|
2
|
+
// the way in: the launcher, a repo's install handing off, the commit hooks
|
|
3
|
+
// and pm's roles all run this file. It loads the registry (cli/registry.ts)
|
|
4
|
+
// and the boot steps with await import, so a file of the tree that fails to
|
|
5
|
+
// load is caught here and the last good copy runs instead, with one line
|
|
6
|
+
// (core/last-good.ts). An error once the command runs is the command's own.
|
|
7
|
+
//
|
|
8
|
+
// the one constraint a reader breaks first: no static import but
|
|
9
|
+
// core/last-good.ts, else a broken file stops this file before it can fall
|
|
10
|
+
// back (tests/cli-boot.test.ts).
|
|
11
|
+
import { bootLoaded, runLastGood } from './core/last-good.ts'
|
|
48
12
|
|
|
13
|
+
/** a long running role's runner, which its command loads by await import:
|
|
14
|
+
* loaded here, a role pm starts on a broken tree runs the copy too */
|
|
15
|
+
const loadRole = (cmd: string | undefined): Promise<unknown> | null =>
|
|
16
|
+
cmd === 'daemon' ? import('./home/run-daemon.ts')
|
|
17
|
+
: cmd === 'web' ? import('./home/run-web.ts')
|
|
18
|
+
: cmd === 'pm' ? import('./home/run-pm.ts')
|
|
19
|
+
: cmd === 'serve' ? import('./serve/run-serve.ts')
|
|
20
|
+
: null
|
|
49
21
|
|
|
50
|
-
/** the
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
22
|
+
/** every module the boot runs, loaded, with the runner of the role `cmd`
|
|
23
|
+
* names. The load probe asks it too (core/load-probe.ts), so a restart is
|
|
24
|
+
* tried on exactly this */
|
|
25
|
+
export const loadBoot = (cmd?: string) =>
|
|
26
|
+
Promise.all([
|
|
27
|
+
import('./cli/registry.ts'),
|
|
28
|
+
import('./cli/cmd_CrossRepoActivity.ts'),
|
|
29
|
+
import('./home/handoff.ts'),
|
|
30
|
+
import('./core/one-lib.ts'),
|
|
31
|
+
import('./cli/kit/calls.ts'),
|
|
32
|
+
import('./home/autostart.ts'),
|
|
33
|
+
loadRole(cmd),
|
|
34
|
+
])
|
|
61
35
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
cli.register(ReleaseCommand)
|
|
68
|
-
cli.register(ReleasesCommand)
|
|
69
|
-
cli.register(HooksInstallCommand)
|
|
70
|
-
cli.register(HooksPreCommitCommand)
|
|
71
|
-
cli.register(HooksCommitMsgCommand)
|
|
72
|
-
cli.register(HooksListCommand)
|
|
73
|
-
cli.register(MvCommand)
|
|
74
|
-
cli.register(CheckCommand)
|
|
75
|
-
cli.register(TuiCommand)
|
|
76
|
-
for (const c of TRAILER_COMMANDS) cli.register(c)
|
|
77
|
-
for (const c of SOUND_COMMANDS) cli.register(c)
|
|
78
|
-
for (const c of REVIEW_COMMANDS) cli.register(c)
|
|
79
|
-
cli.register(ServeCommand)
|
|
80
|
-
cli.register(PmCommand)
|
|
81
|
-
cli.register(DaemonCommand)
|
|
82
|
-
cli.register(WebCommand)
|
|
83
|
-
cli.register(PmInstallCommand)
|
|
84
|
-
cli.register(PmUninstallCommand)
|
|
85
|
-
cli.register(GuiCommand)
|
|
86
|
-
cli.register(ContractsCommand)
|
|
87
|
-
cli.register(AsksCommand)
|
|
88
|
-
cli.register(AsksCheckCommand)
|
|
89
|
-
cli.register(AskNewCommand)
|
|
90
|
-
cli.register(WikiServeCommand)
|
|
91
|
-
cli.register(WikiLintCommand)
|
|
92
|
-
cli.register(AssetsFillCommand)
|
|
93
|
-
cli.register(AssetsAddCommand)
|
|
94
|
-
cli.register(AssetsGenCommand)
|
|
95
|
-
cli.register(AssetsIdentityCommand)
|
|
96
|
-
cli.register(AssetsCheckCommand)
|
|
97
|
-
cli.register(InitCommand)
|
|
98
|
-
cli.register(StartCommand)
|
|
99
|
-
cli.register(NeedsCommand)
|
|
100
|
-
cli.register(FleetCommand)
|
|
101
|
-
cli.register(PbCollectionCommand)
|
|
102
|
-
cli.register(SmokeCommand)
|
|
103
|
-
cli.register(ShotCommand)
|
|
104
|
-
cli.register(ReflectCommand)
|
|
105
|
-
cli.register(KeysCommand)
|
|
106
|
-
cli.register(GlobalProcessesCommand)
|
|
107
|
-
cli.register(GlobalProcessStartCommand)
|
|
108
|
-
cli.register(GlobalProcessStopCommand)
|
|
109
|
-
cli.register(GlobalProcessRestartCommand)
|
|
110
|
-
cli.register(GlobalProcessOpenCommand)
|
|
111
|
-
cli.register(CrossRepoActivityCommand)
|
|
112
|
-
cli.register(PlannedCommand)
|
|
113
|
-
cli.register(InsightsCommand)
|
|
114
|
-
cli.register(GlobalContextCommand)
|
|
115
|
-
cli.register(OverviewCommand)
|
|
116
|
-
cli.register(ChecksCommand)
|
|
117
|
-
cli.register(WhenCommand)
|
|
118
|
-
cli.register(CacheAuditCommand)
|
|
119
|
-
cli.register(TraceAuditCommand)
|
|
120
|
-
cli.register(UnitsAliasCommand)
|
|
121
|
-
cli.register(CommandsCommand)
|
|
122
|
-
cli.register(CallsCommand)
|
|
123
|
-
cli.register(TimeCommand)
|
|
124
|
-
cli.register(ConfigKeysCommand)
|
|
125
|
-
|
|
126
|
-
return cli
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// only when this file IS the process, so importing it costs nothing. A repo's
|
|
130
|
-
// installed copy first hands the command to the house source (handoff.ts). One copy
|
|
131
|
-
// of the lib per process: a repo config that imports its own install lands on
|
|
132
|
-
// this one (one-lib.ts), so the machine's version runs in every repo. The run
|
|
133
|
-
// is logged (cli/kit/calls.ts, read back by `sk calls`). Then pm is started
|
|
134
|
-
// when it is down (autostart.ts), before the command runs
|
|
36
|
+
// only when this file IS the process. A repo's installed copy first hands the
|
|
37
|
+
// command to the house source (handoff.ts). One copy of the lib per process:
|
|
38
|
+
// a repo config that imports its own install lands on this one (one-lib.ts).
|
|
39
|
+
// The run is logged (cli/kit/calls.ts, read back by `sk calls`). Then pm is
|
|
40
|
+
// started when it is down (autostart.ts), before the command runs
|
|
135
41
|
if (import.meta.main) {
|
|
136
|
-
const
|
|
137
|
-
|
|
42
|
+
const raw = process.argv.slice(2)
|
|
43
|
+
let m
|
|
44
|
+
try {
|
|
45
|
+
m = await loadBoot(raw[0])
|
|
46
|
+
} catch (e) {
|
|
47
|
+
runLastGood(e, raw)
|
|
48
|
+
throw e
|
|
49
|
+
}
|
|
50
|
+
bootLoaded()
|
|
51
|
+
const [{ buildCli }, { aliasArgs }, { handoff }, { installOneLib }, { callsFile, logCall }, { autostart }] = m
|
|
52
|
+
const argv = aliasArgs(raw)
|
|
138
53
|
handoff(argv)
|
|
139
|
-
const { installOneLib } = await import('./core/one-lib.ts')
|
|
140
54
|
installOneLib()
|
|
141
|
-
const { callsFile, logCall } = await import('./cli/kit/calls.ts')
|
|
142
55
|
logCall(callsFile((await import('os')).homedir(), 'sk'), 'sk', argv)
|
|
143
|
-
const { autostart } = await import('./home/autostart.ts')
|
|
144
56
|
await autostart(argv)
|
|
145
57
|
void buildCli().runExit(argv)
|
|
146
58
|
}
|