procedure-cli 0.1.8 → 0.1.9

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.
@@ -9,13 +9,149 @@ interface Props {
9
9
  onComplete: (answers: Partial<WizardAnswers>) => void;
10
10
  }
11
11
 
12
- type Mode = "choosing" | "quickstart" | "advanced";
12
+ type Mode = "quickstart" | "advanced";
13
13
  type AdvancedStep = "language" | "framework" | "codeStyle";
14
14
 
15
- const PRESET_OPTIONS = [
16
- { label: "TypeScript + Node.js", value: "typescript-node" },
15
+ // ─── Presets ────────────────────────────────────────────────────────────────
16
+
17
+ interface Preset {
18
+ label: string;
19
+ description: string;
20
+ answers: Partial<WizardAnswers>;
21
+ }
22
+
23
+ const PRESETS: Record<string, Preset> = {
24
+ "typescript-node": {
25
+ label: "TypeScript + Node.js",
26
+ description: "Best for: CLI tools, backend APIs, npm packages, scripts",
27
+ answers: {
28
+ language: "TypeScript",
29
+ framework: "Node.js",
30
+ codeStyle: [
31
+ "TypeScript strict mode, ESM imports",
32
+ "camelCase for variables, PascalCase for types",
33
+ "stdlib → external → internal import ordering",
34
+ "Return errors, don't throw",
35
+ ],
36
+ buildCommand: "tsc",
37
+ testCommand: "node --test",
38
+ typecheckCommand: "tsc --noEmit",
39
+ lintCommand: "eslint src/",
40
+ prCommand: "npm run typecheck && npm run test",
41
+ },
42
+ },
43
+ "nextjs-fullstack": {
44
+ label: "Next.js Full-Stack",
45
+ description: "Best for: SaaS apps, marketing sites, SSR/SSG, API routes",
46
+ answers: {
47
+ language: "TypeScript",
48
+ framework: "Next.js",
49
+ codeStyle: [
50
+ "TypeScript strict mode",
51
+ "camelCase for variables, PascalCase for components",
52
+ "Server components by default, client components only when needed",
53
+ "Co-locate components with their routes",
54
+ ],
55
+ buildCommand: "next build",
56
+ testCommand: "vitest",
57
+ typecheckCommand: "tsc --noEmit",
58
+ lintCommand: "next lint",
59
+ prCommand: "npm run typecheck && npm run lint",
60
+ },
61
+ },
62
+ "react-spa": {
63
+ label: "React SPA",
64
+ description: "Best for: Dashboards, admin panels, SPAs without SSR",
65
+ answers: {
66
+ language: "TypeScript",
67
+ framework: "React",
68
+ codeStyle: [
69
+ "TypeScript strict mode",
70
+ "Functional components only, no class components",
71
+ "Prefer functional patterns, immutability",
72
+ "camelCase for variables, PascalCase for components",
73
+ ],
74
+ buildCommand: "vite build",
75
+ testCommand: "vitest",
76
+ typecheckCommand: "tsc --noEmit",
77
+ lintCommand: "eslint src/",
78
+ prCommand: "npm run typecheck && npm run test",
79
+ },
80
+ },
81
+ "python-fastapi": {
82
+ label: "Python + FastAPI",
83
+ description: "Best for: AI/ML backends, REST APIs, data services",
84
+ answers: {
85
+ language: "Python",
86
+ framework: "FastAPI",
87
+ codeStyle: [
88
+ "Type hints on all functions and class attributes",
89
+ "Black formatting, 88 char line length",
90
+ "Pydantic models for request/response schemas",
91
+ "Return errors explicitly, avoid bare exceptions",
92
+ ],
93
+ buildCommand: "python -m py_compile src/",
94
+ testCommand: "pytest",
95
+ typecheckCommand: "mypy .",
96
+ lintCommand: "ruff check .",
97
+ prCommand: "mypy . && pytest",
98
+ },
99
+ },
100
+ "go-service": {
101
+ label: "Go HTTP Service",
102
+ description: "Best for: High-perf APIs, microservices, concurrent workloads",
103
+ answers: {
104
+ language: "Go",
105
+ framework: "net/http",
106
+ codeStyle: [
107
+ "gofmt enforced, no exceptions",
108
+ "Errors are values — always handle, never ignore",
109
+ "Table-driven tests with t.Run subtests",
110
+ "Keep interfaces small, accept interfaces return structs",
111
+ ],
112
+ buildCommand: "go build ./...",
113
+ testCommand: "go test ./...",
114
+ typecheckCommand: "go vet ./...",
115
+ lintCommand: "golangci-lint run",
116
+ prCommand: "go vet ./... && go test ./...",
117
+ },
118
+ },
119
+ "react-native-expo": {
120
+ label: "React Native + Expo",
121
+ description: "Best for: Cross-platform mobile apps (iOS + Android)",
122
+ answers: {
123
+ language: "TypeScript",
124
+ framework: "React Native",
125
+ codeStyle: [
126
+ "TypeScript strict mode",
127
+ "Functional components with hooks",
128
+ "StyleSheet.create for styles, no inline objects",
129
+ "Platform-specific code via Platform.select or .ios.tsx / .android.tsx",
130
+ ],
131
+ buildCommand: "expo build",
132
+ testCommand: "jest",
133
+ typecheckCommand: "tsc --noEmit",
134
+ lintCommand: "eslint .",
135
+ prCommand: "npm run typecheck && npm run test",
136
+ },
137
+ },
138
+ };
139
+
140
+ const QUICKSTART_OPTIONS = [
141
+ ...Object.entries(PRESETS).map(([value, preset]) => ({
142
+ label: preset.label,
143
+ value,
144
+ description: preset.description,
145
+ })),
146
+ {
147
+ label: "Configure manually →",
148
+ value: "advanced",
149
+ description: "Choose languages, frameworks, and code style step by step",
150
+ },
17
151
  ];
18
152
 
153
+ // ─── Advanced options ────────────────────────────────────────────────────────
154
+
19
155
  const LANGUAGE_OPTIONS = [
20
156
  { label: "TypeScript", value: "TypeScript", description: "Typed JavaScript, strict mode recommended" },
21
157
  { label: "JavaScript", value: "JavaScript", description: "Dynamic, runs everywhere" },
@@ -57,83 +193,49 @@ const CODE_STYLE_OPTIONS = [
57
193
  function getFrameworkPreselect(languages: string[]): string[] {
58
194
  const langSet = new Set(languages.map((l) => l.toLowerCase()));
59
195
  const preselect: string[] = [];
60
- if (langSet.has("typescript") || langSet.has("javascript")) {
61
- preselect.push("Node.js");
62
- }
63
- if (langSet.has("python")) {
64
- preselect.push("Django");
65
- }
66
- if (langSet.has("ruby")) {
67
- preselect.push("Rails");
68
- }
196
+ if (langSet.has("typescript") || langSet.has("javascript")) preselect.push("Node.js");
197
+ if (langSet.has("python")) preselect.push("Django");
198
+ if (langSet.has("ruby")) preselect.push("Rails");
69
199
  return preselect;
70
200
  }
71
201
 
72
- const PRESETS: Record<string, Partial<WizardAnswers>> = {
73
- "typescript-node": {
74
- language: "TypeScript",
75
- framework: "Node.js",
76
- codeStyle: [
77
- "TypeScript strict mode, ESM imports",
78
- "camelCase for variables, PascalCase for types",
79
- "stdlib -> external -> internal import ordering",
80
- "Return errors, don't throw",
81
- ],
82
- buildCommand: "npm run build",
83
- testCommand: "npm run test",
84
- typecheckCommand: "npm run typecheck",
85
- lintCommand: "npm run lint",
86
- },
87
- };
202
+ // ─── Component ───────────────────────────────────────────────────────────────
88
203
 
89
204
  export default function StackStyle({ onComplete }: Props) {
90
- const [mode, setMode] = useState<Mode>("choosing");
205
+ const [mode, setMode] = useState<Mode>("quickstart");
91
206
  const [advancedStep, setAdvancedStep] = useState<AdvancedStep>("language");
92
207
  const [selectedLanguages, setSelectedLanguages] = useState<string[]>([]);
93
208
  const [selectedFrameworks, setSelectedFrameworks] = useState<string[]>([]);
94
209
 
95
- if (mode === "choosing") {
96
- return (
97
- <>
98
- <GutterLine>
99
- <Text bold>Setup mode:</Text>
100
- </GutterLine>
101
- <GutteredSelect
102
- options={[
103
- { label: "QuickStart (use a preset)", value: "quickstart" },
104
- { label: "Advanced (manual config)", value: "advanced" },
105
- ]}
106
- onChange={(val) => setMode(val as Mode)}
107
- />
108
- </>
109
- );
110
- }
111
-
210
+ // ── QuickStart ──
112
211
  if (mode === "quickstart") {
113
212
  return (
114
213
  <>
115
214
  <GutterLine>
116
- <Text bold>Select a stack preset:</Text>
215
+ <Text bold>Select a preset:</Text>
117
216
  </GutterLine>
118
217
  <GutteredSelect
119
- options={PRESET_OPTIONS}
218
+ options={QUICKSTART_OPTIONS}
120
219
  onChange={(val) => {
121
- const preset = PRESETS[val];
122
- if (preset) {
123
- onComplete(preset);
220
+ if (val === "advanced") {
221
+ setMode("advanced");
222
+ return;
124
223
  }
224
+ const preset = PRESETS[val];
225
+ if (preset) onComplete(preset.answers);
125
226
  }}
126
227
  />
127
228
  </>
128
229
  );
129
230
  }
130
231
 
131
- // Advanced mode
132
- const advStep = advancedStep as AdvancedStep;
133
-
134
- if (advStep === "language") {
232
+ // ── Advanced ──
233
+ if (advancedStep === "language") {
135
234
  return (
136
235
  <>
236
+ <GutterLine>
237
+ <Text color={C.overlay1}>Mode: manual configuration</Text>
238
+ </GutterLine>
137
239
  <GutterLine>
138
240
  <Text bold>Programming languages:</Text>
139
241
  </GutterLine>
@@ -150,7 +252,7 @@ export default function StackStyle({ onComplete }: Props) {
150
252
  );
151
253
  }
152
254
 
153
- if (advStep === "framework") {
255
+ if (advancedStep === "framework") {
154
256
  return (
155
257
  <>
156
258
  <GutterLine>