procedure-cli 0.1.13 → 0.1.14

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.
Files changed (42) hide show
  1. package/dist/steps/build-test.js +1 -1
  2. package/dist/steps/build-test.js.map +1 -1
  3. package/dist/steps/product-context.js +1 -1
  4. package/dist/steps/product-context.js.map +1 -1
  5. package/dist/steps/project-info.js +1 -1
  6. package/dist/steps/project-info.js.map +1 -1
  7. package/package.json +5 -1
  8. package/.claude/settings.local.json +0 -27
  9. package/.env.example +0 -2
  10. package/AGENTS.md +0 -134
  11. package/CLAUDE.md +0 -138
  12. package/CODE-FIXED.md +0 -252
  13. package/CODE-REVIEW.md +0 -558
  14. package/config/defaults.json +0 -8
  15. package/config/powerline-config.json +0 -52
  16. package/config/stacks/typescript-node.json +0 -15
  17. package/docs/GIAI-THICH-CLAUDE-MD.md +0 -206
  18. package/docs/PRD.md +0 -141
  19. package/docs/USER-STORIES.md +0 -324
  20. package/src/app.tsx +0 -213
  21. package/src/cli.tsx +0 -19
  22. package/src/components/banner.tsx +0 -23
  23. package/src/components/gutter-line.tsx +0 -16
  24. package/src/components/guttered-select.tsx +0 -231
  25. package/src/components/step-indicator.tsx +0 -32
  26. package/src/components/timeline.tsx +0 -57
  27. package/src/lib/fs.ts +0 -23
  28. package/src/lib/git.ts +0 -41
  29. package/src/lib/powerline.ts +0 -48
  30. package/src/lib/template.ts +0 -161
  31. package/src/lib/types.ts +0 -70
  32. package/src/providers/openai.ts +0 -5
  33. package/src/providers/zai.ts +0 -7
  34. package/src/steps/architecture.tsx +0 -72
  35. package/src/steps/build-test.tsx +0 -114
  36. package/src/steps/generation.tsx +0 -176
  37. package/src/steps/powerline.tsx +0 -254
  38. package/src/steps/product-context.tsx +0 -269
  39. package/src/steps/project-info.tsx +0 -183
  40. package/src/steps/stack-style.tsx +0 -304
  41. package/src/theme.ts +0 -15
  42. package/tsconfig.json +0 -17
@@ -1,254 +0,0 @@
1
- import React, { useState } from "react";
2
- import { Text, useInput } from "ink";
3
- import { ConfirmInput, Spinner } from "@inkjs/ui";
4
- import { GutterLine } from "../components/gutter-line.js";
5
- import { setupPowerline } from "../lib/powerline.js";
6
- import { initGit } from "../lib/git.js";
7
- import { scaffoldRelease, ensurePackageJsonReleaseScripts } from "../lib/template.js";
8
- import type { WizardAnswers } from "../lib/types.js";
9
- import { C } from "../theme.js";
10
-
11
- interface Props {
12
- answers: WizardAnswers;
13
- onComplete: (answers: Partial<WizardAnswers>) => void;
14
- }
15
-
16
- type Phase =
17
- | "ask-powerline"
18
- | "ask-git"
19
- | "ask-release"
20
- | "running"
21
- | "done"
22
- | "error";
23
-
24
- interface SetupResult {
25
- gitCommitted?: boolean;
26
- gitWarning?: string;
27
- releaseCreated?: boolean;
28
- releaseSkipped?: boolean;
29
- pkgModified?: boolean;
30
- pkgCreated?: boolean;
31
- }
32
-
33
- export default function Powerline({ answers, onComplete }: Props) {
34
- const [phase, setPhase] = useState<Phase>("ask-powerline");
35
- const [wantPowerline, setWantPowerline] = useState(false);
36
- const [wantGit, setWantGit] = useState(false);
37
- const [wantRelease, setWantRelease] = useState(false);
38
- const [errorMsg, setErrorMsg] = useState("");
39
- const [setupResult, setSetupResult] = useState<SetupResult>({});
40
-
41
- useInput(
42
- (input, key) => {
43
- if (key.shift && key.tab) {
44
- if (phase === "ask-git") setPhase("ask-powerline");
45
- else if (phase === "ask-release") setPhase("ask-git");
46
- }
47
- },
48
- { isActive: phase === "ask-git" || phase === "ask-release" }
49
- );
50
-
51
- function runSetup(powerline: boolean, git: boolean, release: boolean) {
52
- setPhase("running");
53
- try {
54
- const targetDir = process.cwd();
55
- const projectName = answers.projectName || "untitled";
56
- const result: SetupResult = {};
57
-
58
- if (powerline) setupPowerline(targetDir);
59
-
60
- if (git) {
61
- const gitResult = initGit(targetDir);
62
- result.gitCommitted = gitResult.committed;
63
- result.gitWarning = gitResult.committed ? undefined : gitResult.reason;
64
- }
65
-
66
- if (release) {
67
- const releaseRes = scaffoldRelease(projectName, answers);
68
- const pkgRes = ensurePackageJsonReleaseScripts(targetDir, projectName);
69
- result.releaseCreated = !releaseRes.skipped;
70
- result.releaseSkipped = releaseRes.skipped;
71
- result.pkgModified = pkgRes.modified;
72
- result.pkgCreated = pkgRes.created;
73
- }
74
-
75
- setSetupResult(result);
76
- setPhase("done");
77
- setTimeout(() => onComplete({ setupPowerline: powerline, setupGit: git, setupRelease: release }), 1000);
78
- } catch (err) {
79
- setPhase("error");
80
- setErrorMsg(err instanceof Error ? err.message : String(err));
81
- }
82
- }
83
-
84
- // ── Ask: Powerline ──────────────────────────────────────────────────────────
85
- if (phase === "ask-powerline") {
86
- return (
87
- <>
88
- <GutterLine>
89
- <Text bold>Claude Powerline</Text>
90
- </GutterLine>
91
- <GutterLine>
92
- <Text color={C.overlay1}>Adds a live status bar to Claude Code showing: git branch,</Text>
93
- </GutterLine>
94
- <GutterLine>
95
- <Text color={C.overlay1}>context usage %, session cost, and active tools.</Text>
96
- </GutterLine>
97
- <GutterLine>
98
- <Text color={C.overlay1}>Runs via npx on each session — no global install needed.</Text>
99
- </GutterLine>
100
- <GutterLine>
101
- <Text> </Text>
102
- </GutterLine>
103
- <GutterLine>
104
- <Text bold>Set up Powerline? </Text>
105
- <ConfirmInput
106
- onConfirm={() => { setWantPowerline(true); setPhase("ask-git"); }}
107
- onCancel={() => { setWantPowerline(false); setPhase("ask-git"); }}
108
- />
109
- </GutterLine>
110
- </>
111
- );
112
- }
113
-
114
- // ── Ask: Git ────────────────────────────────────────────────────────────────
115
- if (phase === "ask-git") {
116
- return (
117
- <>
118
- {wantPowerline && (
119
- <GutterLine>
120
- <Text color={C.overlay1}>Powerline: yes</Text>
121
- </GutterLine>
122
- )}
123
- <GutterLine>
124
- <Text bold>Git repository</Text>
125
- </GutterLine>
126
- <GutterLine>
127
- <Text color={C.overlay1}>Runs git init and makes an initial commit with the generated</Text>
128
- </GutterLine>
129
- <GutterLine>
130
- <Text color={C.overlay1}>files — clean starting point for your project history.</Text>
131
- </GutterLine>
132
- <GutterLine>
133
- <Text> </Text>
134
- </GutterLine>
135
- <GutterLine>
136
- <Text bold>Initialize git repo? </Text>
137
- <ConfirmInput
138
- onConfirm={() => { setWantGit(true); setPhase("ask-release"); }}
139
- onCancel={() => { setWantGit(false); setPhase("ask-release"); }}
140
- />
141
- </GutterLine>
142
- <GutterLine>
143
- <Text color={C.overlay1}>{"Shift+Tab prev y/n answer"}</Text>
144
- </GutterLine>
145
- </>
146
- );
147
- }
148
-
149
- // ── Ask: Release scripts ────────────────────────────────────────────────────
150
- if (phase === "ask-release") {
151
- const projectName = answers.projectName || "untitled";
152
- return (
153
- <>
154
- {wantPowerline && (
155
- <GutterLine>
156
- <Text color={C.overlay1}>Powerline: yes</Text>
157
- </GutterLine>
158
- )}
159
- {wantGit && (
160
- <GutterLine>
161
- <Text color={C.overlay1}>Git: yes</Text>
162
- </GutterLine>
163
- )}
164
- <GutterLine>
165
- <Text bold>npm release scripts</Text>
166
- </GutterLine>
167
- <GutterLine>
168
- <Text color={C.overlay1}>Creates ~/bin/{projectName}-release and adds release:patch /</Text>
169
- </GutterLine>
170
- <GutterLine>
171
- <Text color={C.overlay1}>minor / major scripts to package.json. One command to build,</Text>
172
- </GutterLine>
173
- <GutterLine>
174
- <Text color={C.overlay1}>version-bump, push tags, and publish to npm.</Text>
175
- </GutterLine>
176
- <GutterLine>
177
- <Text color={C.overlay1}>Requires: npm login. Best for packages published to npm.</Text>
178
- </GutterLine>
179
- <GutterLine>
180
- <Text> </Text>
181
- </GutterLine>
182
- <GutterLine>
183
- <Text bold>Set up release scripts? </Text>
184
- <ConfirmInput
185
- onConfirm={() => { setWantRelease(true); runSetup(wantPowerline, wantGit, true); }}
186
- onCancel={() => { setWantRelease(false); runSetup(wantPowerline, wantGit, false); }}
187
- />
188
- </GutterLine>
189
- <GutterLine>
190
- <Text color={C.overlay1}>{"Shift+Tab prev y/n answer"}</Text>
191
- </GutterLine>
192
- </>
193
- );
194
- }
195
-
196
- // ── Running ─────────────────────────────────────────────────────────────────
197
- if (phase === "running") {
198
- return (
199
- <GutterLine>
200
- <Spinner label="Running setup tasks..." />
201
- </GutterLine>
202
- );
203
- }
204
-
205
- // ── Error ───────────────────────────────────────────────────────────────────
206
- if (phase === "error") {
207
- return (
208
- <GutterLine>
209
- <Text color={C.red}>Setup error: {errorMsg}</Text>
210
- </GutterLine>
211
- );
212
- }
213
-
214
- // ── Done ────────────────────────────────────────────────────────────────────
215
- return (
216
- <>
217
- {wantPowerline && (
218
- <GutterLine>
219
- <Text color={C.green}>Powerline configured.</Text>
220
- </GutterLine>
221
- )}
222
- {wantGit && setupResult.gitCommitted && (
223
- <GutterLine>
224
- <Text color={C.green}>Git repository initialized.</Text>
225
- </GutterLine>
226
- )}
227
- {wantGit && !setupResult.gitCommitted && setupResult.gitWarning && (
228
- <GutterLine>
229
- <Text color={C.peach}>{"⚠ Git: "}{setupResult.gitWarning}</Text>
230
- </GutterLine>
231
- )}
232
- {wantRelease && setupResult.releaseCreated && (
233
- <GutterLine>
234
- <Text color={C.green}>
235
- Release script created.{setupResult.pkgModified ? " package.json updated." : setupResult.pkgCreated ? " package.json created." : ""}
236
- </Text>
237
- </GutterLine>
238
- )}
239
- {wantRelease && setupResult.releaseSkipped && (
240
- <GutterLine>
241
- <Text color={C.overlay1}>Release script already exists — skipped.</Text>
242
- </GutterLine>
243
- )}
244
- {!wantPowerline && !wantGit && !wantRelease && (
245
- <GutterLine>
246
- <Text color={C.overlay1}>No extras configured.</Text>
247
- </GutterLine>
248
- )}
249
- <GutterLine>
250
- <Text color={C.green} bold>Setup complete!</Text>
251
- </GutterLine>
252
- </>
253
- );
254
- }
@@ -1,269 +0,0 @@
1
- import React, { useState, useEffect } from "react";
2
- import { Text, useInput } from "ink";
3
- import { TextInput } from "@inkjs/ui";
4
- import { GutterLine } from "../components/gutter-line.js";
5
- import { GutteredMultiSelect } from "../components/guttered-select.js";
6
- import type { WizardAnswers } from "../lib/types.js";
7
- import { C } from "../theme.js";
8
-
9
- interface Props {
10
- initialValues?: Partial<WizardAnswers>;
11
- onComplete: (answers: Partial<WizardAnswers>) => void;
12
- }
13
-
14
- type Phase = "problem" | "users" | "techStack" | "coreFeatures" | "nonGoals";
15
-
16
- const CORE_FEATURE_OPTIONS = [
17
- { label: "Authentication", value: "Authentication", description: "Login, signup, sessions" },
18
- { label: "Authorization", value: "Authorization", description: "Roles, permissions, RBAC" },
19
- { label: "API / REST", value: "API / REST", description: "RESTful endpoints" },
20
- { label: "GraphQL API", value: "GraphQL API", description: "GraphQL schema & resolvers" },
21
- { label: "Dashboard", value: "Dashboard", description: "Admin or user dashboard" },
22
- { label: "CRUD Operations", value: "CRUD Operations", description: "Create, read, update, delete" },
23
- { label: "File Upload", value: "File Upload", description: "Upload and manage files" },
24
- { label: "Search", value: "Search", description: "Full-text or filtered search" },
25
- { label: "Notifications", value: "Notifications", description: "Email, push, in-app" },
26
- { label: "Payments", value: "Payments", description: "Billing, subscriptions, checkout" },
27
- { label: "Real-time", value: "Real-time", description: "WebSockets, live updates" },
28
- { label: "Analytics", value: "Analytics", description: "Usage tracking, metrics" },
29
- { label: "CLI", value: "CLI", description: "Command-line interface" },
30
- { label: "CI/CD", value: "CI/CD", description: "Continuous integration & deployment" },
31
- ];
32
-
33
- const TECH_STACK_OPTIONS = [
34
- { label: "React", value: "React", description: "UI component library" },
35
- { label: "Next.js", value: "Next.js", description: "Full-stack React framework" },
36
- { label: "Vue", value: "Vue", description: "Progressive UI framework" },
37
- { label: "Svelte", value: "Svelte", description: "Compile-time UI framework" },
38
- { label: "Node.js", value: "Node.js", description: "Server-side JavaScript runtime" },
39
- { label: "Express", value: "Express", description: "Minimal Node.js web framework" },
40
- { label: "Fastify", value: "Fastify", description: "High-performance Node.js framework" },
41
- { label: "PostgreSQL", value: "PostgreSQL", description: "Relational database" },
42
- { label: "MongoDB", value: "MongoDB", description: "Document database" },
43
- { label: "Redis", value: "Redis", description: "In-memory data store / cache" },
44
- { label: "Supabase", value: "Supabase", description: "Open-source Firebase alternative" },
45
- { label: "Prisma", value: "Prisma", description: "TypeScript ORM" },
46
- { label: "Docker", value: "Docker", description: "Container platform" },
47
- { label: "Tailwind CSS", value: "Tailwind CSS", description: "Utility-first CSS framework" },
48
- { label: "TypeScript", value: "TypeScript", description: "Typed JavaScript superset" },
49
- { label: "Python", value: "Python", description: "General-purpose language" },
50
- { label: "Go", value: "Go", description: "Systems programming language" },
51
- { label: "Rust", value: "Rust", description: "Memory-safe systems language" },
52
- ];
53
-
54
- const PHASE_ORDER: Phase[] = ["problem", "users", "techStack", "coreFeatures", "nonGoals"];
55
-
56
- export default function ProductContext({ initialValues, onComplete }: Props) {
57
- const [phaseIndex, setPhaseIndex] = useState(0);
58
- const [answers, setAnswers] = useState<Record<string, string>>({});
59
- const [error, setError] = useState("");
60
- const [liveInput, setLiveInput] = useState("");
61
-
62
- // Prefill tech stack from Stack & Style selections (language + framework)
63
- const prefillTechStack: string[] = [];
64
- if (initialValues?.language) {
65
- const match = TECH_STACK_OPTIONS.find(
66
- (o) => o.value.toLowerCase() === initialValues.language!.toLowerCase()
67
- );
68
- if (match) prefillTechStack.push(match.value);
69
- }
70
- if (initialValues?.framework) {
71
- const match = TECH_STACK_OPTIONS.find(
72
- (o) => o.value.toLowerCase() === initialValues.framework!.toLowerCase()
73
- );
74
- if (match) prefillTechStack.push(match.value);
75
- }
76
-
77
- const currentPhase = PHASE_ORDER[phaseIndex]!;
78
- const isFirst = phaseIndex === 0;
79
- const isLast = phaseIndex === PHASE_ORDER.length - 1;
80
-
81
- // Reset live input when navigating to a different field
82
- useEffect(() => {
83
- setLiveInput("");
84
- }, [phaseIndex]);
85
-
86
- const isMultiSelectPhase = currentPhase === "techStack" || currentPhase === "coreFeatures";
87
-
88
- useInput((input, key) => {
89
- if (key.shift && key.tab && phaseIndex > 0) {
90
- setPhaseIndex((i) => i - 1);
91
- setError("");
92
- } else if (key.tab && !key.shift && !isMultiSelectPhase) {
93
- // Tab only advances text phases — multi-select phases use Enter to confirm
94
- const required = currentPhase === "problem" || currentPhase === "users";
95
- const val = liveInput.trim() || answers[currentPhase] || "";
96
- if (required && !val) {
97
- setError("This field is required");
98
- return;
99
- }
100
- setError("");
101
- const next = { ...answers, [currentPhase]: val };
102
- setAnswers(next);
103
- if (phaseIndex < PHASE_ORDER.length - 1) {
104
- setPhaseIndex((i) => i + 1);
105
- } else {
106
- finalize(next);
107
- }
108
- }
109
- });
110
-
111
- function finalize(data: Record<string, string>) {
112
- onComplete({
113
- problem: data.problem,
114
- users: data.users,
115
- techStack: data.techStack,
116
- coreFeatures: (data.coreFeatures || "")
117
- .split(",")
118
- .map((s) => s.trim())
119
- .filter(Boolean),
120
- nonGoals: (data.nonGoals || "")
121
- .split(",")
122
- .map((s) => s.trim())
123
- .filter(Boolean),
124
- userStories: [],
125
- envVars: [],
126
- });
127
- }
128
-
129
- function advanceToNext(key: string, value: string) {
130
- const next = { ...answers, [key]: value };
131
- setAnswers(next);
132
- setError("");
133
-
134
- if (phaseIndex < PHASE_ORDER.length - 1) {
135
- setPhaseIndex(phaseIndex + 1);
136
- } else {
137
- finalize(next);
138
- }
139
- }
140
-
141
- function handleTextSubmit(key: string, required: boolean) {
142
- return (value: string) => {
143
- const val = value.trim();
144
- if (required && !val) {
145
- setError("This field is required");
146
- return;
147
- }
148
- advanceToNext(key, val);
149
- };
150
- }
151
-
152
- function handleTechStackSubmit(values: string[]) {
153
- advanceToNext("techStack", values.join(", "));
154
- }
155
-
156
- function handleCoreFeaturesSubmit(values: string[]) {
157
- advanceToNext("coreFeatures", values.join(", "));
158
- }
159
-
160
- // Build completed fields display
161
- const completedFields = PHASE_ORDER.slice(0, phaseIndex).map((key) => (
162
- <GutterLine key={key}>
163
- <Text color={C.overlay1}>
164
- {key === "problem" && `Problem: ${answers[key]}`}
165
- {key === "users" && `Users: ${answers[key]}`}
166
- {key === "techStack" && `Tech stack: ${answers[key]}`}
167
- {key === "coreFeatures" && `Core features: ${answers[key]}`}
168
- {key === "nonGoals" && `Non-goals: ${answers[key]}`}
169
- </Text>
170
- </GutterLine>
171
- ));
172
-
173
- const usersPlaceholder = answers["problem"]
174
- ? `People affected by: ${answers["problem"]}`
175
- : "e.g. Developers, PMs, designers...";
176
-
177
- return (
178
- <>
179
- {completedFields}
180
-
181
- {currentPhase === "problem" && (
182
- <>
183
- <GutterLine>
184
- <Text bold>What problem does this solve? </Text>
185
- <TextInput
186
- placeholder="Describe the core problem..."
187
- onChange={setLiveInput}
188
- onSubmit={handleTextSubmit("problem", true)}
189
- />
190
- </GutterLine>
191
- <GutterLine>
192
- <Text color={C.overlay1}>{"Tab next Enter confirm"}</Text>
193
- </GutterLine>
194
- </>
195
- )}
196
-
197
- {currentPhase === "users" && (
198
- <>
199
- <GutterLine>
200
- <Text bold>Who are the users? </Text>
201
- <TextInput
202
- placeholder={usersPlaceholder}
203
- onChange={setLiveInput}
204
- onSubmit={handleTextSubmit("users", true)}
205
- />
206
- </GutterLine>
207
- <GutterLine>
208
- <Text color={C.overlay1}>{"Shift+Tab prev Tab next Enter confirm"}</Text>
209
- </GutterLine>
210
- </>
211
- )}
212
-
213
- {currentPhase === "techStack" && (
214
- <>
215
- <GutterLine>
216
- <Text bold>Tech stack:</Text>
217
- </GutterLine>
218
- <GutteredMultiSelect
219
- options={TECH_STACK_OPTIONS}
220
- initialSelected={prefillTechStack}
221
- onSubmit={handleTechStackSubmit}
222
- />
223
- <GutterLine>
224
- <Text color={C.overlay1}>{"Shift+Tab prev ↑↓ move Space toggle Enter confirm"}</Text>
225
- </GutterLine>
226
- </>
227
- )}
228
-
229
- {currentPhase === "coreFeatures" && (
230
- <>
231
- <GutterLine>
232
- <Text bold>Core features:</Text>
233
- </GutterLine>
234
- <GutteredMultiSelect
235
- options={CORE_FEATURE_OPTIONS}
236
- onSubmit={handleCoreFeaturesSubmit}
237
- allowCustom
238
- customPlaceholder="e.g. Export PDF, Onboarding flow..."
239
- />
240
- <GutterLine>
241
- <Text color={C.overlay1}>{"Shift+Tab prev ↑↓ move Space toggle Enter confirm"}</Text>
242
- </GutterLine>
243
- </>
244
- )}
245
-
246
- {currentPhase === "nonGoals" && (
247
- <>
248
- <GutterLine>
249
- <Text bold>Non-goals (comma-separated): </Text>
250
- <TextInput
251
- placeholder="e.g. Mobile app, Real-time sync..."
252
- onChange={setLiveInput}
253
- onSubmit={handleTextSubmit("nonGoals", false)}
254
- />
255
- </GutterLine>
256
- <GutterLine>
257
- <Text color={C.overlay1}>{"Shift+Tab prev Tab / Enter confirm"}</Text>
258
- </GutterLine>
259
- </>
260
- )}
261
-
262
- {error && (
263
- <GutterLine>
264
- <Text color={C.red}>{error}</Text>
265
- </GutterLine>
266
- )}
267
- </>
268
- );
269
- }