rvlib-shipkit 0.1.1 → 0.3.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 +137 -0
- package/README.md +23 -8
- package/package.json +15 -3
- package/src/asks/asks-queue.ts +20 -7
- package/src/assets/gen/comfy-gen.ts +106 -0
- package/src/assets/gen/generate-roll.ts +57 -0
- package/src/assets/gen/workflow-loader.ts +67 -0
- package/src/assets/image-ops.ts +30 -0
- package/src/assets/json-store.ts +27 -0
- package/src/assets/kit-config.ts +179 -0
- package/src/assets/kits/identity-kit.ts +119 -0
- package/src/assets/native-deps.ts +18 -0
- package/src/assets/panels/geometry-rects.ts +84 -0
- package/src/assets/roll-workspace.ts +41 -0
- package/src/assets/run-assets.ts +142 -0
- package/src/assets/server/studio-page.ts +620 -0
- package/src/assets/server/studio-queue.ts +58 -0
- package/src/assets/server/studio-server.ts +412 -0
- package/src/assets/vite.ts +62 -0
- package/src/cli/cmd_Asks.ts +83 -0
- package/src/cli/cmd_Assets.ts +120 -0
- package/src/cli/cmd_Check.ts +30 -0
- package/src/cli/cmd_Ci.ts +41 -0
- package/src/cli/cmd_Contracts.ts +35 -0
- package/src/cli/cmd_Init.ts +28 -0
- package/src/cli/cmd_Serve.ts +34 -0
- package/src/cli/cmd_Tui.ts +36 -0
- package/src/cli/cmd_Wiki.ts +53 -0
- package/src/cli.ts +44 -25
- package/src/contracts/run-contracts.ts +33 -0
- package/src/core/check-ctx.ts +3 -16
- package/src/core/check-suite.ts +16 -2
- package/src/core/discover-checks.ts +48 -0
- package/src/core/run-check.ts +73 -0
- package/src/core/run-ci.ts +54 -0
- package/src/core/spawn-timeout.ts +65 -0
- package/src/core/task-runner.ts +36 -43
- package/src/core/wire.ts +20 -0
- package/src/core/write-status.ts +70 -0
- package/src/init-repo.ts +60 -0
- package/src/repo-config.ts +82 -15
- package/src/serve/hub-pages.ts +84 -0
- package/src/serve/run-serve.ts +85 -0
- package/src/serve/serve-hub.ts +77 -0
- package/src/shipkit.ts +39 -3
- package/src/tui/checks-panel.ts +39 -0
- package/src/tui/tasks-panel.ts +54 -0
- package/src/tui/tui-app.tsx +91 -0
- package/src/tui/tui-panel.ts +57 -0
- package/src/tui/tui-store.ts +98 -0
- package/src/wiki/run-wiki.ts +50 -0
- package/src/cli/shipkit-asks.ts +0 -26
- package/src/cli/shipkit-check.ts +0 -26
- package/src/cli/shipkit-ci.ts +0 -30
- package/src/cli/shipkit-contracts.ts +0 -26
- package/src/cli/shipkit-init.ts +0 -41
- package/src/cli/shipkit-wiki.ts +0 -74
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// md-wiki graph server + link lint (folded in from the standalone mdwiki
|
|
2
|
+
// lib; that npm package is frozen). Plain modules behind cmd_Wiki —
|
|
3
|
+
// clipanion owns the option parsing.
|
|
4
|
+
import { basename, relative, resolve } from 'path'
|
|
5
|
+
import { lintMd } from './lint-md.ts'
|
|
6
|
+
import { scanMdGraph } from './scan-md.ts'
|
|
7
|
+
import { serveMdGraph } from './serve-graph.ts'
|
|
8
|
+
|
|
9
|
+
export type WikiScanOpts = { root: string; index?: string; skip?: string }
|
|
10
|
+
|
|
11
|
+
const scanConfig = (o: WikiScanOpts): { root: string; index?: string; skipDirs?: string[] } => ({
|
|
12
|
+
root: resolve(process.cwd(), o.root),
|
|
13
|
+
index: o.index,
|
|
14
|
+
skipDirs: o.skip?.split(',').filter(Boolean),
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export async function runWikiServe(o: WikiScanOpts & { port: number; title?: string }): Promise<number> {
|
|
18
|
+
const cfg = scanConfig(o)
|
|
19
|
+
const rel = relative(process.cwd(), cfg.root)
|
|
20
|
+
const title = o.title ?? (rel === '' ? basename(cfg.root) : `${basename(process.cwd())} ${rel}`)
|
|
21
|
+
try {
|
|
22
|
+
serveMdGraph({ port: o.port, title, load: () => scanMdGraph(cfg) })
|
|
23
|
+
console.log(`wiki graph → http://localhost:${o.port} (open in browser, or VSCode "Simple Browser: Show")`)
|
|
24
|
+
// keep the server alive — the command must not resolve
|
|
25
|
+
await new Promise(() => {})
|
|
26
|
+
return 0
|
|
27
|
+
} catch (e) {
|
|
28
|
+
if (e instanceof Error && e.message.includes('in use')) {
|
|
29
|
+
console.log(`wiki graph already served → http://localhost:${o.port} (another window owns it)`)
|
|
30
|
+
return 0
|
|
31
|
+
}
|
|
32
|
+
throw e
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function runWikiLint(o: WikiScanOpts): number {
|
|
37
|
+
const cfg = scanConfig(o)
|
|
38
|
+
const r = lintMd(cfg)
|
|
39
|
+
if (r.index == null) {
|
|
40
|
+
console.log(o.index != null
|
|
41
|
+
? `FAIL entrypoint '${o.index}' not found in ${cfg.root}`
|
|
42
|
+
: `FAIL no entrypoint: neither index.md nor README.md in ${cfg.root} — pass --index <entry.md>`)
|
|
43
|
+
return 1
|
|
44
|
+
}
|
|
45
|
+
for (const f of r.orphans) console.log(`FAIL orphan: ${f} — unreachable from ${r.index}; link it or delete it`)
|
|
46
|
+
for (const d of r.dangling) console.log(`FAIL dangling: ${d.from} → ${d.token} — target not found`)
|
|
47
|
+
if (!r.ok) { console.log(`FAIL mdwiki lint: ${r.orphans.length} orphan(s), ${r.dangling.length} dangling ref(s) in ${cfg.root}`); return 1 }
|
|
48
|
+
console.log(`ok mdwiki lint: ${r.files} files, all reachable from ${r.index}, no dangling refs`)
|
|
49
|
+
return 0
|
|
50
|
+
}
|
package/src/cli/shipkit-asks.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// shipkit asks — the per-repo human queue. `asks` lists, `asks check`
|
|
2
|
-
// probes + archives, `ask "<title>"` (dispatch rewrites to `asks new`).
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import { checkAsks, createAsk, renderAsksTable } from '../asks/asks-queue.ts'
|
|
5
|
-
import { loadRepoConfig } from '../repo-config.ts'
|
|
6
|
-
|
|
7
|
-
const flagVal = (args: string[], name: string): string | undefined => {
|
|
8
|
-
const i = args.indexOf(`--${name}`)
|
|
9
|
-
return i !== -1 ? args[i + 1] : undefined
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function main(args: string[]): Promise<number> {
|
|
13
|
-
const root = process.cwd()
|
|
14
|
-
const dir = join(root, (await loadRepoConfig(root)).asks?.dir ?? 'asks')
|
|
15
|
-
const sub = args[0]
|
|
16
|
-
if (sub === 'check') { checkAsks(dir); return 0 }
|
|
17
|
-
if (sub === 'new') {
|
|
18
|
-
const title = args[1]
|
|
19
|
-
if (title == null || title === '') { console.error('usage: shipkit ask "<title>" [--kind action|info] [--blocks <what>] [--check "<cmd>"]'); return 2 }
|
|
20
|
-
const file = createAsk(dir, title, { kind: flagVal(args, 'kind'), blocks: flagVal(args, 'blocks'), check: flagVal(args, 'check') })
|
|
21
|
-
console.log(`created ${dir}/${file}`)
|
|
22
|
-
return 0
|
|
23
|
-
}
|
|
24
|
-
renderAsksTable(dir)
|
|
25
|
-
return 0
|
|
26
|
-
}
|
package/src/cli/shipkit-check.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// shipkit check — periodic health: contracts + the repo's TTL'd checks.
|
|
2
|
-
// Clean passes replay from cache; SHIPKIT_FRESH=1 (or --fresh) busts.
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import { CheckSuite } from '../core/check-suite.ts'
|
|
5
|
-
import { activeContracts, applyContractsResult, contractsConfigFrom, loadRepoConfig } from '../repo-config.ts'
|
|
6
|
-
import { evaluateContracts } from '../contracts/contracts-engine.ts'
|
|
7
|
-
|
|
8
|
-
export async function main(args: string[]): Promise<number> {
|
|
9
|
-
const root = process.cwd()
|
|
10
|
-
const c = await loadRepoConfig(root)
|
|
11
|
-
if (args.includes('--fresh')) process.env.SHIPKIT_FRESH = '1'
|
|
12
|
-
const suite = new CheckSuite({ name: c.name, cacheDir: join(root, 'tmp/.shipkit-cache') })
|
|
13
|
-
suite.addCheck({
|
|
14
|
-
name: 'contracts',
|
|
15
|
-
logic: async (t) => {
|
|
16
|
-
applyContractsResult(t, await evaluateContracts(activeContracts(c), contractsConfigFrom(c, root)))
|
|
17
|
-
},
|
|
18
|
-
})
|
|
19
|
-
for (const chk of c.checks ?? []) suite.addCheck({ name: chk.id, remainValidFor: chk.remainValidFor, version: chk.version, logic: chk.logic })
|
|
20
|
-
const r = await suite.execute()
|
|
21
|
-
if (args.includes('--json')) { console.log(JSON.stringify(r)); return r.exitCode }
|
|
22
|
-
const { formatLine } = await import('../core/wire.ts')
|
|
23
|
-
const color = process.stdout.isTTY && process.env.NO_COLOR == null
|
|
24
|
-
for (const l of r.lines) console.log(formatLine(l, color))
|
|
25
|
-
return r.exitCode
|
|
26
|
-
}
|
package/src/cli/shipkit-ci.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// shipkit ci — the commit/deploy gate: floor + contracts + repo tasks
|
|
2
|
-
// through the DAG runner. Exit 0/1; --json prints the structured summary.
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import { allTasks, loadRepoConfig } from '../repo-config.ts'
|
|
5
|
-
import { runTasks } from '../core/task-runner.ts'
|
|
6
|
-
|
|
7
|
-
const flagVals = (args: string[], name: string): string[] => {
|
|
8
|
-
const out: string[] = []
|
|
9
|
-
for (let i = 0; i < args.length; i++) if (args[i] === name && args[i + 1] != null) out.push(args[i + 1]!)
|
|
10
|
-
return out
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function main(args: string[]): Promise<number> {
|
|
14
|
-
const root = process.cwd()
|
|
15
|
-
const c = await loadRepoConfig(root)
|
|
16
|
-
const { tasks, disabled } = allTasks(c, root)
|
|
17
|
-
for (const d of disabled) console.log(`skip: ${d} (skipped-by-config)`)
|
|
18
|
-
const summary = await runTasks({
|
|
19
|
-
tasks,
|
|
20
|
-
logDir: c.logDir ?? join(root, 'tmp/shipkit-ci'),
|
|
21
|
-
cwd: root,
|
|
22
|
-
bail: args.includes('--bail'),
|
|
23
|
-
skipGroups: flagVals(args, '--skip'),
|
|
24
|
-
withIds: flagVals(args, '--with'),
|
|
25
|
-
onlyIds: flagVals(args, '--only'),
|
|
26
|
-
})
|
|
27
|
-
if (args.includes('--json'))
|
|
28
|
-
console.log(JSON.stringify({ ok: summary.ok, interrupted: summary.interrupted, disabled, tasks: summary.results.map((r) => ({ ...r, lines: undefined })) }))
|
|
29
|
-
return summary.ok ? 0 : 1
|
|
30
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// shipkit contracts — fulfillness alone, fast and filesystem-only.
|
|
2
|
-
// Venue deploy scripts call this before any upload.
|
|
3
|
-
import { activeContracts, contractsConfigFrom, loadRepoConfig } from '../repo-config.ts'
|
|
4
|
-
import { evaluateContracts } from '../contracts/contracts-engine.ts'
|
|
5
|
-
import { formatLine } from '../core/wire.ts'
|
|
6
|
-
|
|
7
|
-
export async function main(args: string[]): Promise<number> {
|
|
8
|
-
const root = process.cwd()
|
|
9
|
-
const c = await loadRepoConfig(root)
|
|
10
|
-
const venueIdx = args.indexOf('--venue')
|
|
11
|
-
const only = venueIdx !== -1 ? args[venueIdx + 1] : null
|
|
12
|
-
let manifests = activeContracts(c)
|
|
13
|
-
if (only != null) {
|
|
14
|
-
manifests = manifests.filter((m) => m.venue === only)
|
|
15
|
-
if (manifests.length === 0) { console.error(`FAIL: unknown venue '${only}'`); return 1 }
|
|
16
|
-
}
|
|
17
|
-
const r = await evaluateContracts(manifests, contractsConfigFrom(c, root))
|
|
18
|
-
if (args.includes('--json')) {
|
|
19
|
-
console.log(JSON.stringify({ ok: r.exitCode === 0, outcomes: r.outcomes }))
|
|
20
|
-
return r.exitCode
|
|
21
|
-
}
|
|
22
|
-
const color = process.stdout.isTTY && process.env.NO_COLOR == null
|
|
23
|
-
for (const l of r.lines) console.log(formatLine(l, color))
|
|
24
|
-
if (r.lines.length === 0) console.log('ok: no contracts apply (nothing declared, nothing detected)')
|
|
25
|
-
return r.exitCode
|
|
26
|
-
}
|
package/src/cli/shipkit-init.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// shipkit init — scaffold repo.config.ts + package.json scripts. Refuses to
|
|
2
|
-
// overwrite an existing config; script merge never clobbers existing keys.
|
|
3
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
4
|
-
import { join } from 'path'
|
|
5
|
-
|
|
6
|
-
const CONFIG_TEMPLATE = (name: string): string => `import { defineRepo } from 'rvlib-shipkit'
|
|
7
|
-
|
|
8
|
-
export default defineRepo({
|
|
9
|
-
name: '${name}',
|
|
10
|
-
venues: [], // e.g. ['itch', 'steam'] — selects which .rv-<venue>/ contracts are REQUIRED
|
|
11
|
-
social: [], // e.g. ['x', 'discord'] — .rv-social/<channel>/ post folders (+ .rv-discord/)
|
|
12
|
-
tasks: [], // repo commit-gate tasks; deps double as race guards
|
|
13
|
-
checks: [], // periodic health, TTL-cached
|
|
14
|
-
})
|
|
15
|
-
`
|
|
16
|
-
|
|
17
|
-
export async function main(_args: string[]): Promise<number> {
|
|
18
|
-
const root = process.cwd()
|
|
19
|
-
const configPath = join(root, 'repo.config.ts')
|
|
20
|
-
if (existsSync(configPath)) { console.log(`skip: repo.config.ts already exists`); return 0 }
|
|
21
|
-
const pkgPath = join(root, 'package.json')
|
|
22
|
-
if (!existsSync(pkgPath)) { console.error('FAIL: no package.json here — run from the repo root'); return 1 }
|
|
23
|
-
const pkgRaw = readFileSync(pkgPath, 'utf8')
|
|
24
|
-
const pkg = JSON.parse(pkgRaw) as { name?: string; scripts?: Record<string, string> }
|
|
25
|
-
writeFileSync(configPath, CONFIG_TEMPLATE(pkg.name ?? 'my-repo'))
|
|
26
|
-
console.log('ok: repo.config.ts created')
|
|
27
|
-
const indent = pkgRaw.match(/^(\s+)"/m)?.[1] ?? ' '
|
|
28
|
-
pkg.scripts ??= {}
|
|
29
|
-
let added = 0
|
|
30
|
-
for (const [k, v] of [['ci', 'shipkit ci'], ['check', 'shipkit check'], ['contracts', 'shipkit contracts']] as const) {
|
|
31
|
-
if (pkg.scripts[k] == null) { pkg.scripts[k] = v; added++ }
|
|
32
|
-
else if (pkg.scripts[k] !== v) console.log(`skip: package.json script '${k}' exists — left untouched`)
|
|
33
|
-
}
|
|
34
|
-
if (added > 0) {
|
|
35
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, indent) + '\n')
|
|
36
|
-
console.log(`ok: ${added} package.json script(s) added`)
|
|
37
|
-
}
|
|
38
|
-
console.log('next: fill venues/social in repo.config.ts, then `bun run ci`')
|
|
39
|
-
console.log('next: identity+assets — `bun add -d rvlib-atelier`, mint .rv-identity/brand.ts + .rv-assets/kit.ts, `rvlib-atelier identity` (the identity contract expects public/ favicon+og+logo)')
|
|
40
|
-
return 0
|
|
41
|
-
}
|
package/src/cli/shipkit-wiki.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// shipkit wiki — md-wiki graph server + link lint (folded in from the
|
|
2
|
-
// standalone mdwiki lib; that npm package is frozen).
|
|
3
|
-
// shipkit wiki serve --root agent --port 4800 [--title t] [--index e.md] [--skip a,b]
|
|
4
|
-
// shipkit wiki lint --root agent [--index e.md]
|
|
5
|
-
import { basename, relative, resolve } from 'path'
|
|
6
|
-
import { parseArgs } from 'util'
|
|
7
|
-
import { lintMd } from '../wiki/lint-md.ts'
|
|
8
|
-
import { scanMdGraph } from '../wiki/scan-md.ts'
|
|
9
|
-
import { serveMdGraph } from '../wiki/serve-graph.ts'
|
|
10
|
-
|
|
11
|
-
const USAGE = `usage: shipkit wiki <serve|lint> [--root <dir>] [--index <entry.md>] [--skip <dir,dir>]
|
|
12
|
-
serve --port <n> (default 6161) --title <t> live link-graph server, reload = rescan
|
|
13
|
-
lint fail on orphans + dangling refs (exit 1)
|
|
14
|
-
--root defaults to cwd; default entrypoints: index.md + README.md (--index <e> = only that one)`
|
|
15
|
-
|
|
16
|
-
export async function main(args: string[]): Promise<number> {
|
|
17
|
-
let parsed: ReturnType<typeof parseArgs<{ options: { root: { type: 'string'; default: string }; port: { type: 'string'; default: string }; title: { type: 'string' }; index: { type: 'string' }; skip: { type: 'string' } }; allowPositionals: true }>>
|
|
18
|
-
try {
|
|
19
|
-
parsed = parseArgs({
|
|
20
|
-
args,
|
|
21
|
-
allowPositionals: true,
|
|
22
|
-
options: {
|
|
23
|
-
root: { type: 'string', default: '.' },
|
|
24
|
-
port: { type: 'string', default: '6161' },
|
|
25
|
-
title: { type: 'string' },
|
|
26
|
-
index: { type: 'string' },
|
|
27
|
-
skip: { type: 'string' },
|
|
28
|
-
},
|
|
29
|
-
})
|
|
30
|
-
} catch (e) {
|
|
31
|
-
console.log(`FAIL ${e instanceof Error ? e.message : e}\n${USAGE}`)
|
|
32
|
-
return 2
|
|
33
|
-
}
|
|
34
|
-
const { values, positionals } = parsed
|
|
35
|
-
const cmd = positionals[0]
|
|
36
|
-
const root = resolve(process.cwd(), values.root)
|
|
37
|
-
const scanCfg = { root, index: values.index, skipDirs: values.skip?.split(',').filter(Boolean) }
|
|
38
|
-
|
|
39
|
-
if (cmd === 'serve') {
|
|
40
|
-
const port = Number(values.port)
|
|
41
|
-
if (!Number.isInteger(port) || port <= 0) { console.log(`FAIL --port '${values.port}' is not a port number`); return 2 }
|
|
42
|
-
const rel = relative(process.cwd(), root)
|
|
43
|
-
const title = values.title ?? (rel === '' ? basename(root) : `${basename(process.cwd())} ${rel}`)
|
|
44
|
-
try {
|
|
45
|
-
serveMdGraph({ port, title, load: () => scanMdGraph(scanCfg) })
|
|
46
|
-
console.log(`wiki graph → http://localhost:${port} (open in browser, or VSCode "Simple Browser: Show")`)
|
|
47
|
-
// keep the server alive — dispatch must not exit
|
|
48
|
-
await new Promise(() => {})
|
|
49
|
-
return 0
|
|
50
|
-
} catch (e) {
|
|
51
|
-
if (e instanceof Error && e.message.includes('in use')) {
|
|
52
|
-
console.log(`wiki graph already served → http://localhost:${port} (another window owns it)`)
|
|
53
|
-
return 0
|
|
54
|
-
}
|
|
55
|
-
throw e
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (cmd === 'lint') {
|
|
59
|
-
const r = lintMd(scanCfg)
|
|
60
|
-
if (r.index == null) {
|
|
61
|
-
console.log(values.index != null
|
|
62
|
-
? `FAIL entrypoint '${values.index}' not found in ${root}`
|
|
63
|
-
: `FAIL no entrypoint: neither index.md nor README.md in ${root} — pass --index <entry.md>`)
|
|
64
|
-
return 1
|
|
65
|
-
}
|
|
66
|
-
for (const f of r.orphans) console.log(`FAIL orphan: ${f} — unreachable from ${r.index}; link it or delete it`)
|
|
67
|
-
for (const d of r.dangling) console.log(`FAIL dangling: ${d.from} → ${d.token} — target not found`)
|
|
68
|
-
if (!r.ok) { console.log(`FAIL mdwiki lint: ${r.orphans.length} orphan(s), ${r.dangling.length} dangling ref(s) in ${root}`); return 1 }
|
|
69
|
-
console.log(`ok mdwiki lint: ${r.files} files, all reachable from ${r.index}, no dangling refs`)
|
|
70
|
-
return 0
|
|
71
|
-
}
|
|
72
|
-
console.log(USAGE)
|
|
73
|
-
return 2
|
|
74
|
-
}
|