rvlib-shipkit 0.25.0 → 0.26.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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.26.0
4
+
5
+ - **start means START: the full bootstrap runs on any dir with no commit history.** 0.25.0 widened the scaffold to empty dirs and commitless husks, and the very next field run hit the remaining wall: a folder holding one stray readme was still refused. The gate is now commit history alone: no commits means the dir is startable, and loose files simply ride in the first commit as the repo's first backup. What start still refuses is structural: a repo with real history is never scaffolded or pushed over, a subdirectory of another work tree gets nothing, a temp dir never mints a github repo, and the risky-file refusal still blocks a first commit carrying a `.env` or `node_modules` anywhere in the tree.
6
+
3
7
  ## 0.25.0
4
8
 
5
9
  - **A pre-existing EMPTY dir (or a commitless git-only husk) starts like a brand-new one.** The full-bootstrap scaffold keyed on "this run created the dir", so `mkdir foo` followed by `shipkit start foo`, or a re-run over the husk an older shipkit left, still ended in git-only plus manual next steps. The everyday-cd guard exists to protect a folder holding files, and an empty folder holds none: emptiness (junk like `.DS_Store` aside) now counts as starting intent, a `.git` with no commits counts too, and a git dir with real history stays untouched. A folder with files keeps the old behavior exactly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rvlib-shipkit",
3
- "version": "0.25.0",
3
+ "version": "0.26.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",
@@ -9,7 +9,7 @@ export class StartCommand extends Command {
9
9
 
10
10
  static override usage = Command.Usage({
11
11
  category: 'Setup',
12
- description: 'create (or enter) ~/dev/<name> from ANY cwd, READY to work in: ensures the dir, seeds CLAUDE.md include lines, and on a BRAND-NEW dir scaffolds a minimal package.json + src/index.ts + the rvlib-shipkit dev dep, wires shipkit (repo.config.ts via init), then runs the whole bootstrap chain: git init, first commit, PRIVATE github repo, push. A pre-existing folder counts as brand new when it is EMPTY or a commitless git husk. One holding files gets git only, never a scaffold (--github forces only the github half for it). Prints the dir on stdout so a shell alias can cd there. cwd-only sibling: `shipkit init`',
12
+ description: 'create (or enter) ~/dev/<name> from ANY cwd, READY to work in: ensures the dir, seeds CLAUDE.md include lines, scaffolds a minimal package.json + src/index.ts + the rvlib-shipkit dev dep on any dir with no commit history (loose files ride in the first commit), wires shipkit (repo.config.ts via init), then runs the whole bootstrap chain: git init, first commit, PRIVATE github repo, push. Only a repo with real history is left as it is. Prints the dir on stdout so a shell alias can cd there. cwd-only sibling: `shipkit init`',
13
13
  examples: [
14
14
  ['create or enter ~/dev/pong: dir, package.json, shipkit wiring, git, first commit, private github repo, push', 'shipkit start pong'],
15
15
  ['seed CLAUDE.md includes', "shipkit start pong --include '@~/wiki/index.md' --include '@./agent/index.md'"],
package/src/start-repo.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  // output is the resolved dir, so a sourced shell alias can
5
5
  // `cd "$(shipkit start <name>)"` (the one thing a child process can't do
6
6
  // for its parent shell).
7
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
8
8
  import { homedir } from 'os'
9
9
  import { join } from 'path'
10
10
  import { ensureGitRepo, firstGhLine, IGNORE_BASELINE, isScratch, publishRepo, runner, type Run } from './git-bootstrap.ts'
@@ -35,18 +35,7 @@ export async function startRepo(name: string, opts: StartOpts = {}): Promise<num
35
35
  return 2
36
36
  }
37
37
  const dir = join(opts.root ?? join(homedir(), 'dev'), name)
38
- // this run creating the dir is the strongest signal that a repo is being
39
- // STARTED, which is what the scaffold and the github half key on:
40
- // `ship <name>` is also the everyday cd into a folder that already
41
- // exists. A pre-existing dir with NOTHING in it carries the same intent
42
- // (there are no files to protect), and so does a git-only husk with no
43
- // commits (what an interrupted start leaves behind). Captured here,
44
- // BEFORE the include seeding writes CLAUDE.md into the dir
45
38
  const justCreated = !existsSync(dir)
46
- const JUNK = new Set(['.DS_Store', '.localized'])
47
- const entries = justCreated ? [] : readdirSync(dir).filter((e) => !JUNK.has(e))
48
- const emptyDir = !justCreated && entries.length === 0
49
- const gitOnlyDir = !justCreated && entries.length === 1 && entries[0] === '.git'
50
39
  if (justCreated) {
51
40
  mkdirSync(dir, { recursive: true })
52
41
  console.error(`ok: created ${dir}`)
@@ -78,14 +67,12 @@ export async function startRepo(name: string, opts: StartOpts = {}): Promise<num
78
67
  }
79
68
  }
80
69
  // start is the from-anywhere verb, and a STARTED repo comes out READY:
81
- // a brand-new dir gets a minimal package.json, a first src/index.ts, the
82
- // rvlib-shipkit dev dep, repo.config.ts via init, git, first commit,
83
- // private github repo, push. A dir that already holds a project
84
- // (package.json) gets the same minus the scaffold. A PRE-EXISTING dir
85
- // with NO project is the everyday cd into some old folder: git only,
86
- // never a scaffold (--github forces only the github half, so it must
87
- // never write a package.json into a folder that holds someone's files).
88
- // init itself stays cwd-only, like git init.
70
+ // any dir with no commit history gets a minimal package.json, a first
71
+ // src/index.ts, the rvlib-shipkit dev dep, repo.config.ts via init, git,
72
+ // first commit, private github repo, push. A dir that already holds a
73
+ // project (package.json) gets the same minus the scaffold. Only a repo
74
+ // with real history is left as it is (git wiring aside): that history
75
+ // owns the dir. init itself stays cwd-only, like git init.
89
76
  // --skip means shipkit NEVER TOUCHES a listed repo (a day-job checkout
90
77
  // belongs on that list), not just no CLAUDE.md. And the cd contract survives a
91
78
  // failed adoption: the dir always prints, wiring trouble is a WARN.
@@ -98,17 +85,16 @@ export async function startRepo(name: string, opts: StartOpts = {}): Promise<num
98
85
  let wired = false
99
86
  try { wired = await ensureGitRepo(dir, { print }) }
100
87
  catch (e) { console.error(`WARN could not wire git in ${dir}: ${e instanceof Error ? e.message : String(e)} — the dir is still yours`) }
101
- // the scaffold fires for a dir this run created, a pre-existing dir
102
- // that was EMPTY, or a commitless git-only husk (never --github
103
- // alone: forcing the github half on a folder holding files must not
104
- // write a project into it), and only where git actually wired (a
105
- // subdirectory of another work tree gets nothing): the minimal
106
- // package.json lands so init below has its floor and the first
107
- // commit carries a working repo, not an empty husk
108
- let startable = justCreated || emptyDir
109
- if (!startable && gitOnlyDir && wired)
110
- startable = (await runner('git', dir, 120_000)(['rev-parse', '--verify', 'HEAD'])).code !== 0
111
- if (wired && startable && !existsSync(join(dir, 'package.json')) && !existsSync(join(dir, 'repo.config.ts'))) {
88
+ // start means START: the scaffold fires for ANY dir with no commit
89
+ // history (created this run, found empty, found holding loose files,
90
+ // or the husk an interrupted start left). Pre-existing files simply
91
+ // ride in the first commit, which backs them up. What it never
92
+ // touches: a repo with real history (that history owns the dir), a
93
+ // subdirectory of another work tree (git refused, wired is false),
94
+ // and the risky-file commit refusal downstream still guards .env and
95
+ // node_modules
96
+ const startable = wired && (await runner('git', dir, 120_000)(['rev-parse', '--verify', 'HEAD'])).code !== 0
97
+ if (startable && !existsSync(join(dir, 'package.json')) && !existsSync(join(dir, 'repo.config.ts'))) {
112
98
  const pkg = { name, version: '0.0.0', private: true, type: 'module', scripts: {} }
113
99
  writeFileSync(join(dir, 'package.json'), JSON.stringify(pkg, null, 4) + '\n')
114
100
  // the first source file, so the ci gate is green from commit one: