@oaklandzoo/ostup 0.6.0 → 0.7.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/package.json +1 -1
- package/src/mvp-flow.mjs +8 -0
- package/src/scaffold.mjs +8 -0
- package/src/templates.mjs +1 -0
- package/src/white-label.mjs +54 -0
- package/templates/.claude/commands/handoff-package.md +123 -0
- package/templates/AGENTS.md +3 -1
package/package.json
CHANGED
package/src/mvp-flow.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import { REGISTRY, OPTIONAL_REGISTRY } from './templates.mjs';
|
|
|
19
19
|
import { run as exec, isDryRun } from './exec.mjs';
|
|
20
20
|
import { loadBrief, writeBriefFiles } from './brief/index.mjs';
|
|
21
21
|
import { applyProfileOverlay } from './brief/profile-router.mjs';
|
|
22
|
+
import { applyWhiteLabel } from './white-label.mjs';
|
|
22
23
|
|
|
23
24
|
const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
24
25
|
const TEMPLATES_ROOT = resolve(PKG_ROOT, 'templates');
|
|
@@ -121,6 +122,13 @@ export async function runMvp({ flags = {}, cwd = process.cwd() } = {}) {
|
|
|
121
122
|
await writeProjectEnvFiles({ targetDir, collected: creds.collected });
|
|
122
123
|
await ensureGitignoreEnv({ targetDir });
|
|
123
124
|
|
|
125
|
+
if (flags.whiteLabel) {
|
|
126
|
+
const wl = await applyWhiteLabel({ targetDir });
|
|
127
|
+
if (wl.touched.length > 0) {
|
|
128
|
+
process.stdout.write(`[white-label] scrubbed OSTUP/Goodshin attribution in ${wl.touched.length} file(s)\n`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
124
132
|
await exec('git-init', 'git', ['init'], { cwd: targetDir });
|
|
125
133
|
await exec('git-branch','git', ['branch', '-M', 'main'], { cwd: targetDir });
|
|
126
134
|
await exec('git-add', 'git', ['add', '.'], { cwd: targetDir });
|
package/src/scaffold.mjs
CHANGED
|
@@ -51,6 +51,14 @@ export async function scaffold({ targetDir, flags, stdinIsTTY = process.stdin.is
|
|
|
51
51
|
await writeOne({ entry, absTarget, tokens });
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
if (flags.whiteLabel) {
|
|
55
|
+
const { applyWhiteLabel } = await import('./white-label.mjs');
|
|
56
|
+
const wl = await applyWhiteLabel({ targetDir: absTarget });
|
|
57
|
+
if (wl.touched.length > 0) {
|
|
58
|
+
process.stdout.write(`[white-label] scrubbed OSTUP/Goodshin attribution in ${wl.touched.length} file(s)\n`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
54
62
|
initGitIfNeeded(absTarget);
|
|
55
63
|
printNextSteps(absTarget);
|
|
56
64
|
}
|
package/src/templates.mjs
CHANGED
|
@@ -33,6 +33,7 @@ export const REGISTRY = [
|
|
|
33
33
|
{ src: '.claude/commands/break-into-stories.md', dest: '.claude/commands/break-into-stories.md' },
|
|
34
34
|
{ src: '.claude/commands/generate-brand-kit.md', dest: '.claude/commands/generate-brand-kit.md' },
|
|
35
35
|
{ src: '.claude/commands/generate-content-pack.md', dest: '.claude/commands/generate-content-pack.md' },
|
|
36
|
+
{ src: '.claude/commands/handoff-package.md', dest: '.claude/commands/handoff-package.md' },
|
|
36
37
|
{ src: 'CLAUDE.md', dest: 'CLAUDE.md' },
|
|
37
38
|
{ src: 'AGENTS.md', dest: 'AGENTS.md' },
|
|
38
39
|
{ src: 'START_HERE.md', dest: 'START_HERE.md' },
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// white-label.mjs: post-process specific generated files to strip OSTUP / Goodshin attribution.
|
|
2
|
+
// Used when `ostup init --white-label` is passed (Studio tier).
|
|
3
|
+
|
|
4
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
|
|
8
|
+
const TARGETS = [
|
|
9
|
+
'AGENTS.md',
|
|
10
|
+
'README.md',
|
|
11
|
+
'START_HERE.md',
|
|
12
|
+
'.claude/commands/bootstrap.md',
|
|
13
|
+
'.claude/commands/prompt-start.md',
|
|
14
|
+
'.claude/commands/prompt-end.md',
|
|
15
|
+
'.claude/commands/preflight.md',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const REPLACEMENTS = [
|
|
19
|
+
{ from: /Ostup Agent Kit/g, to: 'Project Kit' },
|
|
20
|
+
{ from: /the Ostup Agent Kit/g, to: 'the Project Kit' },
|
|
21
|
+
{ from: /scaffolded with ostup/gi, to: 'scaffolded' },
|
|
22
|
+
{ from: /Built by Goodshin\.?/gi, to: '' },
|
|
23
|
+
{ from: /Generated by `ostup brief`/g, to: 'Generated' },
|
|
24
|
+
{ from: /Generated by `ostup [a-z-]+`/g, to: 'Generated' },
|
|
25
|
+
{ from: /\bostup CLI subcommands.*\n/g, to: '' },
|
|
26
|
+
{ from: /^\s*-\s*`ostup [a-z-]+`.*$/gm, to: '' },
|
|
27
|
+
{ from: /\bnpx @oaklandzoo\/ostup [a-z-]+/g, to: 'project tooling' },
|
|
28
|
+
{ from: /\(Vercel \+ GitHub \+ Goodshin\)/g, to: '(Vercel + GitHub)' },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export async function applyWhiteLabel({ targetDir } = {}) {
|
|
32
|
+
const touched = [];
|
|
33
|
+
for (const rel of TARGETS) {
|
|
34
|
+
const path = join(targetDir, rel);
|
|
35
|
+
if (!existsSync(path)) continue;
|
|
36
|
+
let body = await readFile(path, 'utf8');
|
|
37
|
+
let changed = false;
|
|
38
|
+
for (const rule of REPLACEMENTS) {
|
|
39
|
+
if (rule.to === undefined) continue;
|
|
40
|
+
const next = body.replace(rule.from, rule.to);
|
|
41
|
+
if (next !== body) {
|
|
42
|
+
body = next;
|
|
43
|
+
changed = true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (changed) {
|
|
47
|
+
// Collapse stray double blank lines that replacements may have left.
|
|
48
|
+
body = body.replace(/\n{3,}/g, '\n\n');
|
|
49
|
+
await writeFile(path, body, 'utf8');
|
|
50
|
+
touched.push(rel);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { touched };
|
|
54
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bundle the current project state into a single client-ready handoff document. Useful for agencies handing off a project to a client or a new developer. Writes docs/HANDOFF_PACKAGE.md and optionally calls `ostup export-pro` for the ZIP.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /handoff-package
|
|
6
|
+
|
|
7
|
+
The Studio-tier (or any operator's) equivalent of a one-page handoff summary. Distills the current state into a single Markdown doc that someone new to the project can read in 10 minutes and understand:
|
|
8
|
+
|
|
9
|
+
- What this project is
|
|
10
|
+
- What is shipped
|
|
11
|
+
- What is in flight
|
|
12
|
+
- How to run it locally
|
|
13
|
+
- How to deploy
|
|
14
|
+
- Who to ask about what
|
|
15
|
+
|
|
16
|
+
## Step 1: read context
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
[ -f docs/brief.md ] && head -80 docs/brief.md
|
|
20
|
+
[ -f HANDOFF.md ] && cat HANDOFF.md
|
|
21
|
+
[ -f docs/PROJECT_STATE.md ] && cat docs/PROJECT_STATE.md
|
|
22
|
+
[ -f docs/MANUAL_TASKS.md ] && cat docs/MANUAL_TASKS.md
|
|
23
|
+
[ -f docs/ARCHITECTURE.md ] && cat docs/ARCHITECTURE.md
|
|
24
|
+
[ -f README.md ] && head -40 README.md
|
|
25
|
+
ls tasks/ 2>/dev/null
|
|
26
|
+
git log --oneline -10
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Step 2: write `docs/HANDOFF_PACKAGE.md`
|
|
30
|
+
|
|
31
|
+
```markdown
|
|
32
|
+
# Handoff: <project name>
|
|
33
|
+
|
|
34
|
+
> One-page client-ready overview. Generated <YYYY-MM-DD>.
|
|
35
|
+
> If something here is wrong, the source of truth is `docs/brief.md` and the git log.
|
|
36
|
+
|
|
37
|
+
## 1. What this project is
|
|
38
|
+
|
|
39
|
+
<one paragraph from brief.summary + audience>
|
|
40
|
+
|
|
41
|
+
## 2. Where it lives
|
|
42
|
+
|
|
43
|
+
- **Repo:** <git remote URL>
|
|
44
|
+
- **Live URL:** <from HANDOFF or brief>
|
|
45
|
+
- **Latest commit:** <SHA + subject>
|
|
46
|
+
|
|
47
|
+
## 3. What is shipped
|
|
48
|
+
|
|
49
|
+
<from PROJECT_STATE "Recently done" + git log of last 10 commits>
|
|
50
|
+
|
|
51
|
+
## 4. What is in flight
|
|
52
|
+
|
|
53
|
+
<from HANDOFF "Active context" / "What to do next">
|
|
54
|
+
|
|
55
|
+
## 5. How to run it locally
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone <repo URL>
|
|
59
|
+
cd <project>
|
|
60
|
+
npm install
|
|
61
|
+
cp .env.example .env.local # fill in the values
|
|
62
|
+
npm run dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 6. Environment variables required
|
|
66
|
+
|
|
67
|
+
| Var | Purpose | Where to get it |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
<list each from .env.example with brief purpose>
|
|
70
|
+
|
|
71
|
+
## 7. How to deploy
|
|
72
|
+
|
|
73
|
+
<from ARCHITECTURE.md or PROJECT_STATE — Vercel default; document any custom CI/CD>
|
|
74
|
+
|
|
75
|
+
## 8. Profile and add-ons
|
|
76
|
+
|
|
77
|
+
<from brief.scaffold.profile + brief.scaffold.addons; explain each add-on briefly>
|
|
78
|
+
|
|
79
|
+
## 9. Blockers + things the operator must do manually
|
|
80
|
+
|
|
81
|
+
<from MANUAL_TASKS.md "Active" section>
|
|
82
|
+
|
|
83
|
+
## 10. Who to ask
|
|
84
|
+
|
|
85
|
+
- **Project owner:** <from brief.project.owner_or_client>
|
|
86
|
+
- **Last agent / dev:** <from HANDOFF if recorded>
|
|
87
|
+
|
|
88
|
+
## 11. Recommended next steps for whoever picks this up
|
|
89
|
+
|
|
90
|
+
1. Run `/preflight` to confirm Vercel + GitHub + env state.
|
|
91
|
+
2. Run `/prompt-start` (or `/resume` if HANDOFF feels stale).
|
|
92
|
+
3. Read `docs/brief.md` end to end.
|
|
93
|
+
4. Pick the first item from "What is in flight" and confirm before changing anything.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Step 3: optionally bundle into a ZIP
|
|
97
|
+
|
|
98
|
+
Ask the operator: "Bundle into a ZIP via `ostup export-pro`?"
|
|
99
|
+
|
|
100
|
+
If yes:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
ostup export-pro --output handoff-<project>-$(date +%Y%m%d).zip
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The ZIP includes `docs/HANDOFF_PACKAGE.md` plus the standard pro-export contents (brief, brand, content, initial PRD, agent kit).
|
|
107
|
+
|
|
108
|
+
## Step 4: report
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Handoff package: docs/HANDOFF_PACKAGE.md
|
|
112
|
+
|
|
113
|
+
Optional bundle: handoff-<project>-<YYYY-MM-DD>.zip (run ostup export-pro to create)
|
|
114
|
+
|
|
115
|
+
The recipient can read the package in ~10 minutes and pick up the work.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Hard rules
|
|
119
|
+
|
|
120
|
+
- Pull every fact from existing files (brief, HANDOFF, PROJECT_STATE, ARCHITECTURE, MANUAL_TASKS, git log). Do not invent.
|
|
121
|
+
- If a section has no source, write `_TBD — operator to fill_` rather than guess.
|
|
122
|
+
- This is a SNAPSHOT. Regenerate when you re-hand-off.
|
|
123
|
+
- Operator can edit the file directly to refine; do not auto-regenerate on every session.
|
package/templates/AGENTS.md
CHANGED
|
@@ -29,7 +29,7 @@ Operator materials live in `{{INPUTS_PATH}}`. Read `{{INPUTS_PATH}}README.md` fo
|
|
|
29
29
|
|
|
30
30
|
Session lifecycle: `/bootstrap`, `/prompt-start`, `/prompt-mid`, `/prompt-end`, `/preflight`, `/resume`, `/handoff-doctor`
|
|
31
31
|
|
|
32
|
-
Building: `/create-prd`, `/break-into-stories`, `/generate-tasks`, `/update-image`, `/update-gui`, `/update-backend`, `/add-storage`, `/generate-image-prompt`, `/generate-image`
|
|
32
|
+
Building: `/create-prd`, `/break-into-stories`, `/generate-tasks`, `/update-image`, `/update-gui`, `/update-backend`, `/add-storage`, `/generate-image-prompt`, `/generate-image`, `/generate-brand-kit`, `/generate-content-pack`, `/handoff-package`
|
|
33
33
|
|
|
34
34
|
See each file under `.claude/commands/` for the full routine.
|
|
35
35
|
|
|
@@ -38,6 +38,8 @@ See each file under `.claude/commands/` for the full routine.
|
|
|
38
38
|
- `ostup brief` — 10-question operator intake; writes `docs/brief.md`, `docs/brief.json`, `tasks/prd-initial-build.md`.
|
|
39
39
|
- `ostup init --brief <path>` — scaffold using an existing brief.json; applies the matching profile overlay.
|
|
40
40
|
- `ostup init` — interactive scaffold without brief.
|
|
41
|
+
- `ostup init --white-label` — Studio tier; strips OSTUP/Goodshin attribution from generated docs.
|
|
42
|
+
- `ostup export-pro` — bundle docs/brief + assets/brand + assets/content + initial PRD into a ZIP for client handoff.
|
|
41
43
|
|
|
42
44
|
## Helpers
|
|
43
45
|
|