rvlib-shipkit 0.11.0 → 0.13.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 +166 -0
- package/README.md +17 -3
- package/package.json +5 -2
- package/src/asks/asks-queue.ts +8 -0
- package/src/assets/kit-config.ts +2 -3
- package/src/assets/roll-workspace.ts +2 -1
- package/src/assets/run-assets.ts +0 -11
- package/src/assets/server/studio-server.ts +7 -24
- package/src/cli/cmd_Assets.ts +3 -14
- package/src/cli/cmd_Check.ts +22 -4
- package/src/cli/cmd_Reflect.ts +116 -0
- package/src/cli/cmd_Rules.ts +32 -0
- package/src/cli/cmd_Serve.ts +1 -1
- package/src/cli.ts +5 -2
- package/src/collections/actions.ts +19 -0
- package/src/collections/collection-types.ts +13 -0
- package/src/collections/graphs.ts +34 -0
- package/src/collections/pings.ts +5 -1
- package/src/collections/posts.ts +20 -1
- package/src/collections/providers.ts +163 -50
- package/src/contracts/apply-contracts.ts +47 -0
- package/src/contracts/run-contracts.ts +8 -3
- package/src/core/canonical-scripts.ts +46 -0
- package/src/core/check-suite.ts +6 -3
- package/src/core/locked-write.ts +39 -0
- package/src/core/motherhome.ts +87 -0
- package/src/core/run-check.ts +28 -15
- package/src/core/run-ci.ts +4 -0
- package/src/core/write-status.ts +7 -26
- package/src/init-repo.ts +24 -11
- package/src/reflect/prompt-corpus.ts +305 -0
- package/src/repo-config.ts +20 -38
- package/src/rules/SK001-package-json-shape.ts +156 -0
- package/src/rules/SK002-contracts-fulfillness.ts +19 -0
- package/src/rules/SK003-claude-md-shape.ts +64 -0
- package/src/rules/SK004-gitignore-policy.ts +105 -0
- package/src/rules/SK005-rvlib-versions.ts +99 -0
- package/src/rules/SK006-npm-publish-safety.ts +42 -0
- package/src/rules/SK007-github-visibility.ts +63 -0
- package/src/rules/rule-registry.ts +32 -0
- package/src/rules/rule.ts +62 -0
- package/src/rules/run-fix.ts +57 -0
- package/src/serve/hub-app/col-card.tsx +192 -0
- package/src/serve/hub-app/cols-svc.ts +136 -0
- package/src/serve/hub-app/geometry-view.tsx +155 -0
- package/src/serve/hub-app/health-svc.ts +49 -0
- package/src/serve/hub-app/hub-app.tsx +236 -215
- package/src/serve/hub-app/hub-st.ts +169 -0
- package/src/serve/hub-app/hub-types.ts +72 -0
- package/src/serve/hub-app/hub.css +286 -59
- package/src/serve/hub-app/index.html +1 -1
- package/src/serve/hub-app/md.ts +24 -0
- package/src/serve/hub-app/media-svc.ts +429 -0
- package/src/serve/hub-app/media-view.tsx +299 -0
- package/src/serve/run-serve.ts +23 -9
- package/src/serve/serve-hub.ts +62 -47
- package/src/shipkit.ts +9 -5
- package/src/assets/server/studio-page.ts +0 -687
- package/src/core/package-json-check.ts +0 -88
- package/src/serve/hub-pages.ts +0 -38
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// built-in `package.json` probe for `shipkit check` — enforces the canonical
|
|
2
|
-
// shape (meta/rv-conventions/package-json.md): private:true, no license,
|
|
3
|
-
// capability-required script names FAIL, banned aliases + missing baseline
|
|
4
|
-
// trio WARN. Doctor surface only — never wired into the ci gate. Pure local
|
|
5
|
-
// fs, no TTL.
|
|
6
|
-
import { existsSync } from 'fs'
|
|
7
|
-
import { join } from 'path'
|
|
8
|
-
import type { CheckCtx } from './check-ctx.ts'
|
|
9
|
-
import type { RepoConfig } from '../repo-config.ts'
|
|
10
|
-
|
|
11
|
-
type Pkg = { name?: string; private?: boolean; license?: string; scripts?: Record<string, string> }
|
|
12
|
-
|
|
13
|
-
// alias → { canonical, bodyMatch } — WARN only when the body proves the
|
|
14
|
-
// alias really is the canonical capability (a `serve` that serves a dist/
|
|
15
|
-
// folder must not be told to rename)
|
|
16
|
-
const ALIASES: Record<string, { canonical: string; bodyMatch: RegExp }> = {
|
|
17
|
-
'serve': { canonical: 'hub', bodyMatch: /(shipkit|cli\.ts) serve\b/ },
|
|
18
|
-
'identity': { canonical: 'assets:identity', bodyMatch: /assets(:| )identity\b/ },
|
|
19
|
-
'pretty': { canonical: 'fmt', bodyMatch: /./ },
|
|
20
|
-
'check-types': { canonical: 'typecheck', bodyMatch: /./ },
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const BASELINE = ['test', 'lint', 'fmt'] as const
|
|
24
|
-
|
|
25
|
-
export async function evaluatePackageJson(t: CheckCtx, root: string, c: RepoConfig): Promise<void> {
|
|
26
|
-
const spec = `${c.docsBase ?? ''}meta/rv-conventions/package-json.md`
|
|
27
|
-
let pkg: Pkg
|
|
28
|
-
try {
|
|
29
|
-
pkg = (await Bun.file(join(root, 'package.json')).json()) as Pkg
|
|
30
|
-
} catch (e) {
|
|
31
|
-
t.fail(`package.json unreadable (${String(e).slice(0, 120)})`, spec)
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
const scripts = pkg.scripts ?? {}
|
|
35
|
-
// rvlib-* as a probe ROOT is theoretical (libs live as sub-packages and
|
|
36
|
-
// the probe only runs where repo.config.ts loads) — field inversion is
|
|
37
|
-
// still handled so a future lib-root repo fails correctly, not absurdly
|
|
38
|
-
const isLib = pkg.name?.startsWith('rvlib-') === true
|
|
39
|
-
|
|
40
|
-
// published rvlib-* roots invert the field rules (distribute/npm owns them)
|
|
41
|
-
if (isLib) {
|
|
42
|
-
if (pkg.license !== 'MIT') t.fail(`package.json: rvlib-* package must carry license MIT`, spec)
|
|
43
|
-
if (pkg.private === true) t.fail(`package.json: rvlib-* package must not be private`, spec)
|
|
44
|
-
} else {
|
|
45
|
-
if (pkg.private !== true) t.fail(`package.json: "private": true is required`, spec)
|
|
46
|
-
if (pkg.license != null) t.fail(`package.json: license field is banned on project repos (rvlib-* sub-packages excepted)`, spec)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// aliases first — an alias satisfies the requirement but earns a WARN,
|
|
50
|
-
// never a double report (alias WARN + missing-canonical FAIL). A banned
|
|
51
|
-
// alias lingering NEXT TO its canonical still WARNs (sweep on sight),
|
|
52
|
-
// it just doesn't satisfy anything.
|
|
53
|
-
const aliased = new Set<string>()
|
|
54
|
-
for (const [name, a] of Object.entries(ALIASES)) {
|
|
55
|
-
const body = scripts[name]
|
|
56
|
-
if (body == null || !a.bodyMatch.test(body)) continue
|
|
57
|
-
if (scripts[a.canonical] == null) aliased.add(a.canonical)
|
|
58
|
-
t.warn(`package.json: script '${name}' is the house '${a.canonical}' — ${scripts[a.canonical] == null ? 'rename it' : `delete it ('${a.canonical}' exists)`}`, spec)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const has = (name: string): boolean => scripts[name] != null || aliased.has(name)
|
|
62
|
-
|
|
63
|
-
// capability → required script names (FAIL); repo.config.ts existence is
|
|
64
|
-
// implied — this probe only runs under `shipkit check`
|
|
65
|
-
const required: Array<{ name: string; why: string }> = [
|
|
66
|
-
{ name: 'ci', why: 'shipkit repo' },
|
|
67
|
-
{ name: 'check', why: 'shipkit repo' },
|
|
68
|
-
{ name: 'contracts', why: 'shipkit repo' },
|
|
69
|
-
{ name: 'tui', why: 'shipkit repo' },
|
|
70
|
-
{ name: 'hub', why: 'shipkit repo' },
|
|
71
|
-
{ name: 'mv', why: 'shipkit repo' },
|
|
72
|
-
]
|
|
73
|
-
if (existsSync(join(root, '.rv-assets/kit.ts'))) required.push({ name: 'assets', why: '.rv-assets/kit.ts exists' })
|
|
74
|
-
if (existsSync(join(root, '.rv-identity/brand.ts'))) required.push({ name: 'assets:identity', why: '.rv-identity/brand.ts exists' })
|
|
75
|
-
if (existsSync(join(root, '.rv-comfy'))) required.push({ name: 'comfy:up', why: '.rv-comfy/ exists' })
|
|
76
|
-
if (existsSync(join(root, 'deploy.sh'))) required.push({ name: 'up', why: 'deploy.sh exists' })
|
|
77
|
-
if (existsSync(join(root, c.asks?.dir ?? 'asks'))) required.push({ name: 'asks', why: 'ask queue exists' })
|
|
78
|
-
|
|
79
|
-
const missing = required.filter((r) => !has(r.name))
|
|
80
|
-
for (const m of missing) t.fail(`package.json: missing script '${m.name}' (${m.why})`, spec)
|
|
81
|
-
|
|
82
|
-
const missingBaseline = BASELINE.filter((n) => !has(n))
|
|
83
|
-
if (missingBaseline.length > 0)
|
|
84
|
-
t.warn(`package.json: missing baseline script(s): ${missingBaseline.join(', ')}`, spec)
|
|
85
|
-
|
|
86
|
-
if (!t.failed && !t.warned)
|
|
87
|
-
t.ok(`package.json shape ok (private, no license, ${required.length} required scripts present)`)
|
|
88
|
-
}
|
package/src/serve/hub-pages.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Shared hub-page plumbing. The hub UI itself is the Bun-native React app
|
|
2
|
-
// in hub-app/ (HTML import, served by serve-hub.ts — build/webapp
|
|
3
|
-
// doctrine). This module keeps what the LEGACY pages (graph pages, studio
|
|
4
|
-
// SPA) still need until they migrate: the server-injected rail, and the
|
|
5
|
-
// attention section types the collector + React app share.
|
|
6
|
-
import type { HubTool } from './serve-hub.ts'
|
|
7
|
-
|
|
8
|
-
const esc = (s: string): string => s.replace(/&/g, '&').replace(/</g, '<').replace(/"/g, '"')
|
|
9
|
-
|
|
10
|
-
// ── the rail: thin fixed tab bar, injected into legacy hub-served pages ───
|
|
11
|
-
const RAIL_ICONS: Record<string, string> = { '/': '⚡', '/graph/wiki': '🕸', '/graph/agent': '🤖', '/assets/': '🖼', '/status': '📊' }
|
|
12
|
-
|
|
13
|
-
const RAIL_CSS = `
|
|
14
|
-
.skrail{position:fixed;left:0;top:0;bottom:0;width:46px;z-index:9999;display:flex;flex-direction:column;
|
|
15
|
-
align-items:center;padding-top:10px;gap:4px;background:#17140f;border-right:1px solid #332b22}
|
|
16
|
-
.skrail a{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:9px;
|
|
17
|
-
font-size:17px;text-decoration:none;border-left:2px solid transparent;filter:grayscale(35%);opacity:.75;position:relative}
|
|
18
|
-
.skrail a:hover{background:#262019;filter:none;opacity:1}
|
|
19
|
-
.skrail a.on{background:#262019;border-left-color:#e88c28;filter:none;opacity:1}
|
|
20
|
-
.skrail a i{position:absolute;top:4px;right:4px;width:8px;height:8px;border-radius:50%;background:#e05252}
|
|
21
|
-
body{padding-left:46px}`
|
|
22
|
-
|
|
23
|
-
/** Inject the rail into a legacy hub-served HTML document (post-<body>,
|
|
24
|
-
* fixed position — the page needs no layout knowledge). The React app
|
|
25
|
-
* renders its own identical rail from /hub.json. */
|
|
26
|
-
export function withRail(html: string, o: { tools: HubTool[]; active: string }): string {
|
|
27
|
-
const items = [{ path: '/', label: 'attention', desc: 'everything red' }, ...o.tools.filter((t) => t.path !== '/')]
|
|
28
|
-
.map((t) => {
|
|
29
|
-
const on = o.active === t.path || (t.path !== '/' && o.active.startsWith(t.path))
|
|
30
|
-
const dot = t.path === '/' ? '<i id=skdot style="display:none"></i>' : ''
|
|
31
|
-
return `<a class="${on ? 'on' : ''}" href="${esc(t.path)}" title="${esc(t.label)} — ${esc(t.desc)}">${RAIL_ICONS[t.path] ?? '·'}${dot}</a>`
|
|
32
|
-
})
|
|
33
|
-
.join('')
|
|
34
|
-
// the red dot fetches client-side: a passive page nav must never run the
|
|
35
|
-
// needs projection server-side (cost + heal side-effects)
|
|
36
|
-
const dotScript = `<script>fetch('/api/needs.json').then(r=>r.json()).then(j=>{const n=(j.needs||[]).filter(x=>x.severity==='red').length;if(n>0)document.getElementById('skdot').style.display=''}).catch(()=>{})</script>`
|
|
37
|
-
return html.replace(/<body([^>]*)>/, `<body$1><style>${RAIL_CSS}</style><nav class=skrail>${items}</nav>${dotScript}`)
|
|
38
|
-
}
|