rvlib-shipkit 0.2.0 → 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 +60 -0
- package/package.json +1 -1
- package/src/assets/kit-config.ts +19 -1
- package/src/assets/kits/identity-kit.ts +62 -23
- package/src/assets/run-assets.ts +25 -5
- package/src/assets/server/studio-page.ts +37 -4
- package/src/assets/server/studio-server.ts +265 -213
- package/src/cli/cmd_Serve.ts +34 -0
- package/src/cli.ts +2 -0
- package/src/repo-config.ts +16 -1
- 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 +10 -5
package/src/repo-config.ts
CHANGED
|
@@ -17,6 +17,19 @@ import type { ContractManifest } from './contracts/contract-types.ts'
|
|
|
17
17
|
import type { TaskDef } from './core/task-runner.ts'
|
|
18
18
|
import type { CheckCtx } from './core/check-ctx.ts'
|
|
19
19
|
import type { TuiPanelDef } from './tui/tui-panel.ts'
|
|
20
|
+
import type { MdGraph } from './wiki/md-graph.ts'
|
|
21
|
+
|
|
22
|
+
// `shipkit serve` — the ONE hub server per repo (run-serve.ts resolves the
|
|
23
|
+
// rest by convention: agent/ graph when the dir exists, studio when the
|
|
24
|
+
// kit loads)
|
|
25
|
+
export type ServeConfig = {
|
|
26
|
+
/** hub port — house range 4800+; default hashes the repo name into 4800-4979 */
|
|
27
|
+
port?: number
|
|
28
|
+
/** custom wiki-graph provider for repos with their own link semantics; default: generic md scan of the repo root */
|
|
29
|
+
wikiGraph?: { title?: string; load: () => MdGraph }
|
|
30
|
+
/** agent/ graph entrypoint (default: index.md AND README.md) */
|
|
31
|
+
agentIndex?: string
|
|
32
|
+
}
|
|
20
33
|
|
|
21
34
|
export type RepoConfig = {
|
|
22
35
|
name: string
|
|
@@ -35,10 +48,12 @@ export type RepoConfig = {
|
|
|
35
48
|
contracts?: { exempt?: Record<string, string>; extra?: ContractManifest[] }
|
|
36
49
|
/** extra dashboard panels appended after the built-in Tasks/Checks (`shipkit tui`) */
|
|
37
50
|
tui?: { panels?: TuiPanelDef[] }
|
|
51
|
+
/** the `shipkit serve` hub: port + optional graph hooks */
|
|
52
|
+
serve?: ServeConfig
|
|
38
53
|
logDir?: string
|
|
39
54
|
}
|
|
40
55
|
|
|
41
|
-
const KNOWN_KEYS = new Set(['name', 'venues', 'social', 'docsBase', 'defaults', 'tasks', 'asks', 'contracts', 'tui', 'logDir'])
|
|
56
|
+
const KNOWN_KEYS = new Set(['name', 'venues', 'social', 'docsBase', 'defaults', 'tasks', 'asks', 'contracts', 'tui', 'serve', 'logDir'])
|
|
42
57
|
|
|
43
58
|
export function defineRepo(c: RepoConfig): RepoConfig {
|
|
44
59
|
if (typeof c.name !== 'string' || c.name === '') throw new Error('defineRepo: name is required')
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// The hub's two no-build pages (served by serve-hub.ts): the landing page
|
|
2
|
+
// whose links ARE the toolbox, and the /status page (STATUS.md + a
|
|
3
|
+
// "run check" button streaming wire lines). Same style family as the
|
|
4
|
+
// studio: one template string, vanilla JS, no build step, no CDN.
|
|
5
|
+
import type { HubTool } from './serve-hub.ts'
|
|
6
|
+
|
|
7
|
+
const esc = (s: string): string => s.replace(/&/g, '&').replace(/</g, '<')
|
|
8
|
+
|
|
9
|
+
const SHELL = `
|
|
10
|
+
:root{--bg:#141210;--panel:#1e1a15;--panel2:#262019;--line:#332b22;--ink:#f3ebe0;--dim:#a89a88;
|
|
11
|
+
--accent:#e88c28;--gold:#ffcf5c;--teal:#58c0b0;--red:#e05252}
|
|
12
|
+
*{box-sizing:border-box}
|
|
13
|
+
body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.6 system-ui,sans-serif;min-height:100vh}
|
|
14
|
+
.wrap{max-width:860px;margin:0 auto;padding:40px 24px}
|
|
15
|
+
h1{font-size:20px;margin:0}
|
|
16
|
+
h1 small{color:var(--dim);font-weight:400;font-size:13px;margin-left:10px}
|
|
17
|
+
.crumb{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:6px}
|
|
18
|
+
.crumb a{color:var(--accent);text-decoration:none}.crumb a:hover{color:var(--gold)}
|
|
19
|
+
`
|
|
20
|
+
|
|
21
|
+
export function landingPage(o: { name: string; port: number; tools: HubTool[] }): string {
|
|
22
|
+
const cards = o.tools
|
|
23
|
+
.map((t) => `<a class=card href="${esc(t.path)}"><b>${esc(t.label)}</b><span>${esc(t.desc)}</span><code>${esc(t.path)}</code></a>`)
|
|
24
|
+
.join('\n')
|
|
25
|
+
return `<!doctype html><html><head><meta charset=utf-8>
|
|
26
|
+
<meta name=viewport content="width=device-width,initial-scale=1"><title>${esc(o.name)} · shipkit</title>
|
|
27
|
+
<style>${SHELL}
|
|
28
|
+
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin-top:26px}
|
|
29
|
+
.card{display:flex;flex-direction:column;gap:6px;background:var(--panel);border:1px solid var(--line);border-radius:12px;
|
|
30
|
+
padding:16px;text-decoration:none;color:var(--ink)}
|
|
31
|
+
.card:hover{border-color:var(--accent);background:var(--panel2)}
|
|
32
|
+
.card b{font-size:15px}.card span{font-size:13px;color:var(--dim)}
|
|
33
|
+
.card code{font:11px ui-monospace,Menlo,monospace;color:var(--teal)}
|
|
34
|
+
</style></head><body><div class=wrap>
|
|
35
|
+
<div class=crumb>shipkit hub</div>
|
|
36
|
+
<h1>${esc(o.name)}<small>http://localhost:${o.port}</small></h1>
|
|
37
|
+
<div class=cards>
|
|
38
|
+
${cards}
|
|
39
|
+
</div>
|
|
40
|
+
</div></body></html>`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function statusPage(o: { name: string; statusMd: string | null }): string {
|
|
44
|
+
const body = o.statusMd ?? 'no STATUS.md yet — hit "run check" (or run: shipkit check)'
|
|
45
|
+
return `<!doctype html><html><head><meta charset=utf-8>
|
|
46
|
+
<meta name=viewport content="width=device-width,initial-scale=1"><title>${esc(o.name)} · status</title>
|
|
47
|
+
<style>${SHELL}
|
|
48
|
+
.bar{display:flex;align-items:center;gap:12px;margin:18px 0 12px}
|
|
49
|
+
button{background:var(--accent);color:#1a1206;border:0;border-radius:9px;padding:8px 14px;font-weight:650;cursor:pointer}
|
|
50
|
+
button:disabled{opacity:.45;cursor:default}
|
|
51
|
+
#note{font-size:12px;color:var(--dim)}
|
|
52
|
+
pre{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px;overflow-x:auto;
|
|
53
|
+
font:12.5px/1.55 ui-monospace,Menlo,monospace;white-space:pre-wrap}
|
|
54
|
+
.ok{color:var(--teal)}.warn{color:var(--gold)}.fail{color:var(--red)}.dim{color:var(--dim)}
|
|
55
|
+
</style></head><body><div class=wrap>
|
|
56
|
+
<div class=crumb><a href="/">shipkit hub</a> / status</div>
|
|
57
|
+
<h1>${esc(o.name)}<small>STATUS.md</small></h1>
|
|
58
|
+
<div class=bar><button id=run>run check</button><span id=note>shells <code>shipkit check</code>, wire lines stream in below</span></div>
|
|
59
|
+
<pre id=out></pre>
|
|
60
|
+
<script>
|
|
61
|
+
const out=document.getElementById('out'),btn=document.getElementById('run'),note=document.getElementById('note')
|
|
62
|
+
// wire-line coloring: ok/WARN/FAIL/skip prefixes → the house palette
|
|
63
|
+
const esc=s=>s.replace(/&/g,'&').replace(/</g,'<')
|
|
64
|
+
const cls=l=>{const t=l.trimStart()
|
|
65
|
+
if(t.startsWith('FAIL')||t.startsWith('✗'))return 'fail'
|
|
66
|
+
if(t.startsWith('WARN')||t.startsWith('⚠'))return 'warn'
|
|
67
|
+
if(t.startsWith('ok')||t.startsWith('✓'))return 'ok'
|
|
68
|
+
if(t.startsWith('skip')||t.startsWith('fix:')||t.startsWith('#'))return 'dim'
|
|
69
|
+
return ''}
|
|
70
|
+
const paint=text=>{out.innerHTML=text.split('\\n').map(l=>'<span class="'+cls(l)+'">'+esc(l)+'</span>').join('\\n')}
|
|
71
|
+
paint(${JSON.stringify(body).replaceAll('<', '\\u003c')})
|
|
72
|
+
btn.onclick=async()=>{
|
|
73
|
+
btn.disabled=true;note.textContent='running…';let text=''
|
|
74
|
+
try{
|
|
75
|
+
const r=await fetch('status/run',{method:'POST'})
|
|
76
|
+
const rd=r.body.getReader(),dec=new TextDecoder()
|
|
77
|
+
for(;;){const{done,value}=await rd.read();if(done)break;text+=dec.decode(value,{stream:true});paint(text)}
|
|
78
|
+
note.textContent='done — STATUS.md refreshed on disk'
|
|
79
|
+
}catch(e){text+='\\nFAIL stream broke: '+e;paint(text);note.textContent='stream broke'}
|
|
80
|
+
btn.disabled=false
|
|
81
|
+
}
|
|
82
|
+
</script>
|
|
83
|
+
</div></body></html>`
|
|
84
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// shipkit serve — resolve the repo's toolbox and run the hub. What mounts
|
|
2
|
+
// comes from convention + repo.config's `serve` block: the wiki graph is
|
|
3
|
+
// always on (custom provider via serve.wikiGraph, else the generic md
|
|
4
|
+
// scan), agent/ graph when the dir exists, the studio when .rv-assets/
|
|
5
|
+
// kit.ts loads. Port: --port > serve.port > a deterministic house-range
|
|
6
|
+
// default (4800-4979, hashed from the repo name — stable across launches;
|
|
7
|
+
// pin serve.port when two repos collide).
|
|
8
|
+
import { existsSync } from 'fs'
|
|
9
|
+
import { join } from 'path'
|
|
10
|
+
import { fileURLToPath } from 'url'
|
|
11
|
+
import { loadKit } from '../assets/kit-config.ts'
|
|
12
|
+
import { page as studioPage } from '../assets/server/studio-page.ts'
|
|
13
|
+
import { studioRoutes, type StudioRoutes } from '../assets/server/studio-server.ts'
|
|
14
|
+
import { loadRepoConfig, type RepoConfig } from '../repo-config.ts'
|
|
15
|
+
import { scanMdGraph } from '../wiki/scan-md.ts'
|
|
16
|
+
import { serveHub, type HubDeps } from './serve-hub.ts'
|
|
17
|
+
|
|
18
|
+
export type ServeIo = { print: (l: string) => void; printErr: (l: string) => void }
|
|
19
|
+
|
|
20
|
+
export function defaultHubPort(name: string): number {
|
|
21
|
+
let h = 0
|
|
22
|
+
for (const c of name) h = (h * 31 + c.charCodeAt(0)) >>> 0
|
|
23
|
+
return 4800 + (h % 180)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function resolveHubDeps(root: string, c: RepoConfig, io: ServeIo, o?: { port?: number }): Promise<HubDeps> {
|
|
27
|
+
const wikiGraph = c.serve?.wikiGraph != null
|
|
28
|
+
? { title: c.serve.wikiGraph.title ?? `${c.name} wiki`, load: c.serve.wikiGraph.load }
|
|
29
|
+
: { title: `${c.name} wiki`, load: () => scanMdGraph({ root }) }
|
|
30
|
+
const agentRoot = join(root, 'agent')
|
|
31
|
+
const agentGraph = existsSync(agentRoot)
|
|
32
|
+
? { title: `${c.name} agent/`, load: () => scanMdGraph({ root: agentRoot, index: c.serve?.agentIndex }) }
|
|
33
|
+
: null
|
|
34
|
+
let studio: StudioRoutes | null = null
|
|
35
|
+
if (existsSync(join(root, '.rv-assets/kit.ts'))) {
|
|
36
|
+
// a broken kit must not take the graphs and status down with it —
|
|
37
|
+
// WARN + mount everything else
|
|
38
|
+
try {
|
|
39
|
+
studio = await studioRoutes({ kit: await loadKit(root), root, page: studioPage })
|
|
40
|
+
} catch (e) {
|
|
41
|
+
io.print(`WARN assets studio not mounted: ${(e as Error).message}`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const cli = fileURLToPath(new URL('../cli.ts', import.meta.url))
|
|
45
|
+
return {
|
|
46
|
+
root,
|
|
47
|
+
name: c.name,
|
|
48
|
+
port: o?.port ?? c.serve?.port ?? defaultHubPort(c.name),
|
|
49
|
+
wikiGraph,
|
|
50
|
+
agentGraph,
|
|
51
|
+
studio,
|
|
52
|
+
checkCmd: [process.execPath, cli, 'check'],
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function runServe(root: string, io: ServeIo, o?: { port?: number }): Promise<number> {
|
|
57
|
+
const c = await loadRepoConfig(root)
|
|
58
|
+
const deps = await resolveHubDeps(root, c, io, o)
|
|
59
|
+
try {
|
|
60
|
+
const hub = serveHub(deps)
|
|
61
|
+
const base = `http://localhost:${hub.server.port}`
|
|
62
|
+
io.print(`ok: ${c.name} hub → ${base}`)
|
|
63
|
+
for (const t of hub.tools) io.print(`ok: ${t.label} → ${base}${t.path}`)
|
|
64
|
+
await new Promise(() => {}) // the hub owns the process — never resolve
|
|
65
|
+
return 0
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if (e instanceof Error && e.message.includes('in use')) {
|
|
68
|
+
// same repo in another window is fine; a different repo hashed
|
|
69
|
+
// onto this port is a real collision — never claim its hub
|
|
70
|
+
const owner = await fetch(`http://127.0.0.1:${deps.port}/hub.json`, { signal: AbortSignal.timeout(1500) })
|
|
71
|
+
.then((r) => r.json() as Promise<{ hub?: string; name?: string; tools?: { path: string; label: string }[] }>)
|
|
72
|
+
.catch(() => null)
|
|
73
|
+
if (owner?.hub === 'shipkit' && owner.name === c.name) {
|
|
74
|
+
// a re-run terminal stays as clickable as a first run — the
|
|
75
|
+
// owner's /hub.json tool list is the same source of truth
|
|
76
|
+
io.print(`ok: hub already served → http://localhost:${deps.port} (another window owns it)`)
|
|
77
|
+
for (const t of owner.tools ?? []) io.print(`ok: ${t.label} → http://localhost:${deps.port}${t.path}`)
|
|
78
|
+
return 0
|
|
79
|
+
}
|
|
80
|
+
io.printErr(`FAIL: port ${deps.port} is taken by ${owner?.name != null ? `repo '${owner.name}'` : 'another process'} — set serve: { port } in repo.config.ts to a free one`)
|
|
81
|
+
return 1
|
|
82
|
+
}
|
|
83
|
+
throw e
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// shipkit serve — ONE hub server per repo, ONE port (his call 2026-07-22:
|
|
2
|
+
// "a single shipkit task in vscode with multiple urls I can click"). The
|
|
3
|
+
// landing page's links are the whole toolbox: /graph/wiki · /graph/agent ·
|
|
4
|
+
// /assets/ (the studio, mounted IN-PROCESS) · /status (STATUS.md + run
|
|
5
|
+
// check). Route logic only — resolving WHAT to mount from repo.config is
|
|
6
|
+
// run-serve.ts's job.
|
|
7
|
+
import { existsSync } from 'fs'
|
|
8
|
+
import { join } from 'path'
|
|
9
|
+
import { graphHtml } from 'rvlib-shipkit/src/wiki/graph-page.ts'
|
|
10
|
+
import type { MdGraph } from 'rvlib-shipkit/src/wiki/md-graph.ts'
|
|
11
|
+
import type { StudioRoutes } from '../assets/server/studio-server.ts'
|
|
12
|
+
import { landingPage, statusPage } from './hub-pages.ts'
|
|
13
|
+
|
|
14
|
+
export type HubGraph = { title: string; load: () => MdGraph }
|
|
15
|
+
export type HubTool = { path: string; label: string; desc: string }
|
|
16
|
+
export type HubDeps = {
|
|
17
|
+
root: string
|
|
18
|
+
name: string
|
|
19
|
+
/** 0 = random (tests); real launches pass repo.config/default */
|
|
20
|
+
port: number
|
|
21
|
+
wikiGraph: HubGraph
|
|
22
|
+
/** null = no agent/ dir */
|
|
23
|
+
agentGraph: HubGraph | null
|
|
24
|
+
/** null = no .rv-assets/kit.ts (or it failed to load — caller prints the WARN) */
|
|
25
|
+
studio: StudioRoutes | null
|
|
26
|
+
/** argv shelling the check run streamed by /status/run (test seam) */
|
|
27
|
+
checkCmd: string[]
|
|
28
|
+
}
|
|
29
|
+
export type Hub = { server: ReturnType<typeof Bun.serve>; tools: HubTool[]; stop: () => void }
|
|
30
|
+
|
|
31
|
+
// the toolbox as data — the landing page, /hub.json, and the stdout ok:
|
|
32
|
+
// lines all render THIS list, so they can never disagree
|
|
33
|
+
export function hubTools(d: Pick<HubDeps, 'wikiGraph' | 'agentGraph' | 'studio'>): HubTool[] {
|
|
34
|
+
const tools: HubTool[] = [{ path: '/graph/wiki', label: 'wiki graph', desc: d.wikiGraph.title }]
|
|
35
|
+
if (d.agentGraph != null) tools.push({ path: '/graph/agent', label: 'agent graph', desc: d.agentGraph.title })
|
|
36
|
+
if (d.studio != null) tools.push({ path: '/assets/', label: 'assets studio', desc: 'roll, curate, pick, ship' })
|
|
37
|
+
tools.push({ path: '/status', label: 'status', desc: 'STATUS.md + run check' })
|
|
38
|
+
return tools
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function serveHub(d: HubDeps): Hub {
|
|
42
|
+
const tools = hubTools(d)
|
|
43
|
+
const html = (s: string): Response => new Response(s, { headers: { 'content-type': 'text/html; charset=utf-8' } })
|
|
44
|
+
const server: ReturnType<typeof Bun.serve> = Bun.serve({
|
|
45
|
+
hostname: '127.0.0.1',
|
|
46
|
+
port: d.port,
|
|
47
|
+
async fetch(req): Promise<Response> {
|
|
48
|
+
const path = new URL(req.url).pathname
|
|
49
|
+
if (path === '/') return html(landingPage({ name: d.name, port: server.port ?? d.port, tools }))
|
|
50
|
+
// identity probe: lets a second launch tell "same repo, another
|
|
51
|
+
// window" from "a DIFFERENT repo hashed onto my port"
|
|
52
|
+
if (path === '/hub.json') return Response.json({ hub: 'shipkit', name: d.name, tools })
|
|
53
|
+
if (path === '/graph/wiki') return html(graphHtml(d.wikiGraph.load(), { title: d.wikiGraph.title }))
|
|
54
|
+
if (path === '/graph/wiki/graph.json') return Response.json(d.wikiGraph.load())
|
|
55
|
+
if (d.agentGraph != null && path === '/graph/agent') return html(graphHtml(d.agentGraph.load(), { title: d.agentGraph.title }))
|
|
56
|
+
if (d.agentGraph != null && path === '/graph/agent/graph.json') return Response.json(d.agentGraph.load())
|
|
57
|
+
if (path === '/status') {
|
|
58
|
+
const p = join(d.root, 'STATUS.md')
|
|
59
|
+
return html(statusPage({ name: d.name, statusMd: existsSync(p) ? await Bun.file(p).text() : null }))
|
|
60
|
+
}
|
|
61
|
+
if (path === '/status/run' && req.method === 'POST') {
|
|
62
|
+
// stream wire lines as the check emits them; sh merges stderr
|
|
63
|
+
// so FAIL lines reach the page, not just the terminal
|
|
64
|
+
const proc = Bun.spawn(['sh', '-c', 'exec "$0" "$@" 2>&1', ...d.checkCmd], { cwd: d.root, stdout: 'pipe', stderr: 'ignore' })
|
|
65
|
+
return new Response(proc.stdout, { headers: { 'content-type': 'text/plain; charset=utf-8', 'cache-control': 'no-store' } })
|
|
66
|
+
}
|
|
67
|
+
if (d.studio != null) {
|
|
68
|
+
// the studio page fetches RELATIVE urls — it must live under
|
|
69
|
+
// the slash-terminated prefix for them to resolve
|
|
70
|
+
if (path === '/assets') return new Response(null, { status: 307, headers: { location: '/assets/' } })
|
|
71
|
+
if (path.startsWith('/assets/')) return d.studio.handle(req, path.slice('/assets'.length))
|
|
72
|
+
}
|
|
73
|
+
return new Response('not found', { status: 404 })
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
return { server, tools, stop: () => server.stop(true) }
|
|
77
|
+
}
|
package/src/shipkit.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// rvlib-shipkit — barrel. One import per repo: defineRepo in repo.config.ts;
|
|
2
2
|
// everything else is the machinery behind the shipkit CLI.
|
|
3
3
|
export { defineRepo, loadRepoConfig, resolveFloor, allTasks, contractsTask, contractsConfigFrom, activeContracts } from './repo-config.ts'
|
|
4
|
-
export type { RepoConfig, FloorResolution, FloorSource } from './repo-config.ts'
|
|
4
|
+
export type { RepoConfig, ServeConfig, FloorResolution, FloorSource } from './repo-config.ts'
|
|
5
|
+
// the hub (`shipkit serve`): one server, one port, every tool a click away
|
|
6
|
+
export { serveHub, hubTools } from './serve/serve-hub.ts'
|
|
7
|
+
export type { Hub, HubDeps, HubGraph, HubTool } from './serve/serve-hub.ts'
|
|
8
|
+
export { runServe, resolveHubDeps, defaultHubPort } from './serve/run-serve.ts'
|
|
9
|
+
export { landingPage, statusPage } from './serve/hub-pages.ts'
|
|
5
10
|
export { discoverChecks } from './core/discover-checks.ts'
|
|
6
11
|
export type { DiscoveredCheck } from './core/discover-checks.ts'
|
|
7
12
|
export { runTasks, selectTasks } from './core/task-runner.ts'
|
|
@@ -29,11 +34,11 @@ export type { Ask, CreateOpts } from './asks/asks-queue.ts'
|
|
|
29
34
|
// package is frozen). A repo's .rv-assets/kit.ts imports defineKit and
|
|
30
35
|
// declares its kinds; `shipkit assets …` derives the rest.
|
|
31
36
|
export { defineKit, defineKind, comfy, canvas, geometryPanel, gridPanel, customPanel, validateKit, missingPanelScripts, loadKit, findAsset, allAssets, categoriesOf } from './assets/kit-config.ts'
|
|
32
|
-
export type { KitConfig, ResolvedKit, Kind, KindMeta, AssetSpec, GeneratorSpec, ComfyGen, CanvasGen, PanelSpec, GeometryPanelSpec, GridPanelSpec, CustomPanelSpec, FoundAsset } from './assets/kit-config.ts'
|
|
33
|
-
export { identityKinds, renderIdentity, FAVICON_SIZE, OG_W, OG_H, LOGO_SIZE } from './assets/kits/identity-kit.ts'
|
|
37
|
+
export type { KitConfig, ResolvedKit, Kind, KindMeta, AssetSpec, GeneratorSpec, ComfyGen, CanvasGen, PanelSpec, GeometryPanelSpec, GridPanelSpec, CustomPanelSpec, FoundAsset, ShipContext, ShipFn } from './assets/kit-config.ts'
|
|
38
|
+
export { identityKinds, renderIdentity, renderIdentityFromMark, NO_PICK_FIX, FAVICON_SIZE, OG_W, OG_H, LOGO_SIZE } from './assets/kits/identity-kit.ts'
|
|
34
39
|
export type { Brand } from './assets/kits/identity-kit.ts'
|
|
35
|
-
export { serveStudio } from './assets/server/studio-server.ts'
|
|
36
|
-
export type { Studio, StudioDeps } from './assets/server/studio-server.ts'
|
|
40
|
+
export { serveStudio, studioRoutes } from './assets/server/studio-server.ts'
|
|
41
|
+
export type { Studio, StudioDeps, StudioRoutes } from './assets/server/studio-server.ts'
|
|
37
42
|
export { page as studioPage } from './assets/server/studio-page.ts'
|
|
38
43
|
export { StudioQueue } from './assets/server/studio-queue.ts'
|
|
39
44
|
export type { Job, QueueState } from './assets/server/studio-queue.ts'
|