rvlib-shipkit 0.28.0 → 0.29.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 +4 -0
- package/package.json +1 -1
- package/src/init-repo.ts +14 -6
- package/src/start-repo.ts +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.29.0
|
|
4
|
+
|
|
5
|
+
- **Creation output states facts instead of listing chores.** A fresh `start` ended on five lines that meant nothing to the person reading them: `skip: lint/typecheck/test (no … script)` about scripts a repo born one second ago has no use for, plus `next:` nags to fill venues and mint identity assets, neither of which anybody has decided on yet. `init` now reports the gate floor as ONE line naming what resolved, and `start` closes with one measured summary (`<name> is ready — N file(s) committed, pushed to <remote>`). Venues raise themselves through the contract checker the day one is declared, and identity through rule SK002 the day the repo grows a public surface. An output that lists undecided work trains the reader to skip all of it.
|
|
6
|
+
|
|
3
7
|
## 0.28.0
|
|
4
8
|
|
|
5
9
|
- **The `.claude/` policy files are OPT-IN.** 0.27.0 wrote a pre-approved shell allowlist (`curl *`, `git push*`, `./deploy.sh`) and an attribution silencer into every started repo, gitignored and therefore invisible to review. Those are decisions about what an agent can do in a repo and what its git history says, so they now require the caller to declare a house (`claudePolicy`, which `start` enables when it seeds CLAUDE.md include lines), and the grant prints once by name when it lands. The verify skill still lands for everyone.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rvlib-shipkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"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",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/init-repo.ts
CHANGED
|
@@ -99,11 +99,15 @@ export async function initRepo(root: string, opts: InitOpts = {}): Promise<numbe
|
|
|
99
99
|
// `shipkit check --fix SK004`, one code path
|
|
100
100
|
const g = await gitignorePolicy.fix!({ root, config: defineRepo({ name }) })
|
|
101
101
|
p(`ok: .gitignore policy block ${g.changed ? 'written' : 'already current'}`)
|
|
102
|
-
//
|
|
103
|
-
// time
|
|
102
|
+
// what the gate actually runs, in ONE line: a thin floor must be seen at
|
|
103
|
+
// init time rather than discovered after a bad commit slipped through.
|
|
104
|
+
// The per-task resolution is diagnostics, and a `skip:` naming a script
|
|
105
|
+
// this repo has no use for yet reads as a chore list on a repo that was
|
|
106
|
+
// born a second ago. `shipkit ci` reports the same facts when they
|
|
107
|
+
// matter, and reports them about a repo that has code in it
|
|
104
108
|
const floor = resolveFloor(defineRepo({ name }), root)
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
if (floor.tasks.length > 0) p(`ok: gate floor: ${floor.tasks.map((t) => t.id).join(', ')}`)
|
|
110
|
+
else p(`WARN the gate would check NOTHING here (${floor.unfilled.map((u) => u.id).join(', ')} all unresolved) — see \`shipkit rules\``)
|
|
107
111
|
// every verb comes from the `shipkit` bin — dead on arrival unless the
|
|
108
112
|
// package is actually installed (bunx runs without adding the dep)
|
|
109
113
|
if (opts.bin == null) {
|
|
@@ -116,7 +120,11 @@ export async function initRepo(root: string, opts: InitOpts = {}): Promise<numbe
|
|
|
116
120
|
}
|
|
117
121
|
// last, so the first commit carries repo.config.ts and the scripts above
|
|
118
122
|
if (wired && opts.noPublish !== true) await publishRepo(root, { github: opts.github, gh: opts.gh, print: p })
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
// no chore list here. Venues belong in repo.config the day a venue is
|
|
124
|
+
// CHOSEN, and the contract checker fails the gate from that day on.
|
|
125
|
+
// Identity is needed once the repo has a public surface, and rule SK002
|
|
126
|
+
// warns exactly then. Both told at creation time are noise about a
|
|
127
|
+
// decision nobody has made yet. `start` owns the one closing line
|
|
128
|
+
if (opts.noPublish !== true) p('next: `shipkit ci` is the gate — run it to check your work')
|
|
121
129
|
return 0
|
|
122
130
|
}
|
package/src/start-repo.ts
CHANGED
|
@@ -148,6 +148,7 @@ export async function startRepo(name: string, opts: StartOpts = {}): Promise<num
|
|
|
148
148
|
}
|
|
149
149
|
// last line, so what to do next is the last thing read
|
|
150
150
|
if (unscaffolded) console.error(`next: scaffold the app in ${dir} (package.json), then \`shipkit init\` inside it — the commit gates arm on the first ci run`)
|
|
151
|
+
else console.error(`ok: ${name} is ready — ${await summarize(dir)}`)
|
|
151
152
|
}
|
|
152
153
|
// a child process cannot cd its parent shell, so the dir goes to stdout
|
|
153
154
|
// and a sourced wrapper does the move. Without one, say the move out
|
|
@@ -157,3 +158,20 @@ export async function startRepo(name: string, opts: StartOpts = {}): Promise<num
|
|
|
157
158
|
console.log(dir)
|
|
158
159
|
return 0
|
|
159
160
|
}
|
|
161
|
+
|
|
162
|
+
/** the one closing fact: what this repo IS now, measured rather than
|
|
163
|
+
* narrated. Everything a repo still needs is reported by the gate, about a
|
|
164
|
+
* repo with code in it, on the day it matters */
|
|
165
|
+
async function summarize(dir: string): Promise<string> {
|
|
166
|
+
const git = runner('git', dir, 30_000)
|
|
167
|
+
const files = (await git(['ls-files'])).out.trim().split('\n').filter((l) => l !== '').length
|
|
168
|
+
const head = await git(['log', '-1', '--format=%h'])
|
|
169
|
+
// git merges stderr into stdout, so a missing remote answers with its
|
|
170
|
+
// error text: only a zero exit means that output is a url
|
|
171
|
+
const origin = await git(['remote', 'get-url', 'origin'])
|
|
172
|
+
const pushed = (await git(['rev-parse', '--verify', '@{upstream}'])).code === 0
|
|
173
|
+
const bits = [head.code === 0 ? `${files} file(s) committed` : 'not committed yet']
|
|
174
|
+
if (origin.code === 0) bits.push(pushed ? `pushed to ${origin.out.trim()}` : `remote wired, nothing pushed yet`)
|
|
175
|
+
else bits.push('local only, no remote')
|
|
176
|
+
return bits.join(', ')
|
|
177
|
+
}
|