@shahmarasy/prodo 0.1.4 → 0.1.5

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 (173) hide show
  1. package/README.md +201 -97
  2. package/bin/prodo.cjs +6 -6
  3. package/dist/agents/agent-registry.d.ts +13 -0
  4. package/dist/agents/agent-registry.js +79 -0
  5. package/dist/agents/anthropic/index.d.ts +9 -0
  6. package/dist/agents/anthropic/index.js +55 -0
  7. package/dist/agents/base.d.ts +25 -0
  8. package/dist/agents/base.js +71 -0
  9. package/dist/agents/google/index.d.ts +9 -0
  10. package/dist/agents/google/index.js +53 -0
  11. package/dist/agents/mock/index.d.ts +11 -0
  12. package/dist/agents/mock/index.js +26 -0
  13. package/dist/agents/openai/index.d.ts +9 -0
  14. package/dist/agents/openai/index.js +57 -0
  15. package/dist/agents/system-prompts.d.ts +3 -0
  16. package/dist/agents/system-prompts.js +32 -0
  17. package/dist/cli/agent-command-installer.d.ts +4 -0
  18. package/dist/cli/agent-command-installer.js +148 -0
  19. package/dist/cli/agent-ids.d.ts +15 -0
  20. package/dist/cli/agent-ids.js +49 -0
  21. package/dist/cli/doctor.d.ts +1 -0
  22. package/dist/cli/doctor.js +144 -0
  23. package/dist/cli/fix-tui.d.ts +4 -0
  24. package/dist/cli/fix-tui.js +79 -0
  25. package/dist/cli/index.d.ts +9 -0
  26. package/dist/cli/index.js +465 -0
  27. package/dist/cli/init-tui.d.ts +23 -0
  28. package/dist/cli/init-tui.js +176 -0
  29. package/dist/cli/init.d.ts +11 -0
  30. package/dist/cli/init.js +334 -0
  31. package/dist/cli/normalize-interactive.d.ts +8 -0
  32. package/dist/cli/normalize-interactive.js +167 -0
  33. package/dist/cli/preset-loader.d.ts +4 -0
  34. package/dist/cli/preset-loader.js +210 -0
  35. package/dist/core/artifact-registry.d.ts +11 -0
  36. package/dist/core/artifact-registry.js +49 -0
  37. package/dist/core/artifacts.d.ts +10 -0
  38. package/dist/core/artifacts.js +892 -0
  39. package/dist/core/clean.d.ts +10 -0
  40. package/dist/core/clean.js +74 -0
  41. package/dist/core/consistency.d.ts +8 -0
  42. package/dist/core/consistency.js +328 -0
  43. package/dist/core/constants.d.ts +7 -0
  44. package/dist/core/constants.js +64 -0
  45. package/dist/core/errors.d.ts +3 -0
  46. package/dist/core/errors.js +10 -0
  47. package/dist/core/fix.d.ts +31 -0
  48. package/dist/core/fix.js +188 -0
  49. package/dist/core/hook-executor.d.ts +1 -0
  50. package/dist/core/hook-executor.js +175 -0
  51. package/dist/core/markdown.d.ts +16 -0
  52. package/dist/core/markdown.js +81 -0
  53. package/dist/core/normalize.d.ts +8 -0
  54. package/dist/core/normalize.js +125 -0
  55. package/dist/core/normalized-brief.d.ts +48 -0
  56. package/dist/core/normalized-brief.js +182 -0
  57. package/dist/core/output-index.d.ts +13 -0
  58. package/dist/core/output-index.js +55 -0
  59. package/dist/core/paths.d.ts +17 -0
  60. package/dist/core/paths.js +80 -0
  61. package/dist/core/project-config.d.ts +14 -0
  62. package/dist/core/project-config.js +69 -0
  63. package/dist/core/registry.d.ts +13 -0
  64. package/dist/core/registry.js +115 -0
  65. package/dist/core/settings.d.ts +7 -0
  66. package/dist/core/settings.js +35 -0
  67. package/dist/core/template-engine.d.ts +3 -0
  68. package/dist/core/template-engine.js +43 -0
  69. package/dist/core/template-resolver.d.ts +15 -0
  70. package/dist/core/template-resolver.js +46 -0
  71. package/dist/core/templates.d.ts +33 -0
  72. package/dist/core/templates.js +440 -0
  73. package/dist/core/terminology.d.ts +21 -0
  74. package/dist/core/terminology.js +143 -0
  75. package/dist/core/tracing.d.ts +21 -0
  76. package/dist/core/tracing.js +74 -0
  77. package/dist/core/types.d.ts +35 -0
  78. package/dist/core/types.js +5 -0
  79. package/dist/core/utils.d.ts +7 -0
  80. package/dist/core/utils.js +66 -0
  81. package/dist/core/validate.d.ts +10 -0
  82. package/dist/core/validate.js +226 -0
  83. package/dist/core/validator.d.ts +5 -0
  84. package/dist/core/validator.js +76 -0
  85. package/dist/core/version.d.ts +1 -0
  86. package/dist/core/version.js +30 -0
  87. package/dist/core/workflow-commands.d.ts +7 -0
  88. package/dist/core/workflow-commands.js +29 -0
  89. package/dist/i18n/en.json +45 -0
  90. package/dist/i18n/index.d.ts +5 -0
  91. package/dist/i18n/index.js +63 -0
  92. package/dist/i18n/tr.json +45 -0
  93. package/dist/providers/index.d.ts +2 -1
  94. package/dist/providers/index.js +20 -6
  95. package/dist/providers/mock-provider.d.ts +1 -1
  96. package/dist/providers/mock-provider.js +7 -6
  97. package/dist/providers/openai-provider.d.ts +1 -1
  98. package/dist/providers/openai-provider.js +1 -1
  99. package/dist/skills/engine.d.ts +10 -0
  100. package/dist/skills/engine.js +75 -0
  101. package/dist/skills/fix-skill.d.ts +2 -0
  102. package/dist/skills/fix-skill.js +38 -0
  103. package/dist/skills/generate-artifact-skill.d.ts +2 -0
  104. package/dist/skills/generate-artifact-skill.js +32 -0
  105. package/dist/skills/generate-pipeline-skill.d.ts +2 -0
  106. package/dist/skills/generate-pipeline-skill.js +45 -0
  107. package/dist/skills/normalize-skill.d.ts +2 -0
  108. package/dist/skills/normalize-skill.js +29 -0
  109. package/dist/skills/types.d.ts +28 -0
  110. package/dist/skills/types.js +2 -0
  111. package/dist/skills/validate-skill.d.ts +2 -0
  112. package/dist/skills/validate-skill.js +29 -0
  113. package/package.json +74 -45
  114. package/src/agents/agent-registry.ts +93 -0
  115. package/src/agents/anthropic/index.ts +86 -0
  116. package/src/agents/anthropic/manifest.json +7 -0
  117. package/src/agents/base.ts +77 -0
  118. package/src/agents/google/index.ts +79 -0
  119. package/src/agents/google/manifest.json +7 -0
  120. package/src/agents/mock/index.ts +32 -0
  121. package/src/agents/mock/manifest.json +7 -0
  122. package/src/agents/openai/index.ts +83 -0
  123. package/src/agents/openai/manifest.json +7 -0
  124. package/src/agents/system-prompts.ts +35 -0
  125. package/src/{agent-command-installer.ts → cli/agent-command-installer.ts} +164 -164
  126. package/src/{agents.ts → cli/agent-ids.ts} +58 -58
  127. package/src/{doctor.ts → cli/doctor.ts} +157 -137
  128. package/src/cli/fix-tui.ts +111 -0
  129. package/src/{cli.ts → cli/index.ts} +459 -410
  130. package/src/{init-tui.ts → cli/init-tui.ts} +208 -208
  131. package/src/{init.ts → cli/init.ts} +398 -398
  132. package/src/cli/normalize-interactive.ts +241 -0
  133. package/src/{preset-loader.ts → cli/preset-loader.ts} +237 -237
  134. package/src/{artifact-registry.ts → core/artifact-registry.ts} +69 -69
  135. package/src/{artifacts.ts → core/artifacts.ts} +1081 -1072
  136. package/src/core/clean.ts +88 -0
  137. package/src/{consistency.ts → core/consistency.ts} +374 -303
  138. package/src/{constants.ts → core/constants.ts} +72 -72
  139. package/src/{errors.ts → core/errors.ts} +7 -7
  140. package/src/core/fix.ts +253 -0
  141. package/src/{hook-executor.ts → core/hook-executor.ts} +196 -196
  142. package/src/{markdown.ts → core/markdown.ts} +93 -73
  143. package/src/{normalize.ts → core/normalize.ts} +145 -137
  144. package/src/{normalized-brief.ts → core/normalized-brief.ts} +227 -206
  145. package/src/{output-index.ts → core/output-index.ts} +59 -59
  146. package/src/{paths.ts → core/paths.ts} +75 -71
  147. package/src/{project-config.ts → core/project-config.ts} +78 -78
  148. package/src/{registry.ts → core/registry.ts} +119 -119
  149. package/src/{settings.ts → core/settings.ts} +35 -35
  150. package/src/core/template-engine.ts +45 -0
  151. package/src/{template-resolver.ts → core/template-resolver.ts} +54 -54
  152. package/src/{templates.ts → core/templates.ts} +452 -452
  153. package/src/core/terminology.ts +177 -0
  154. package/src/core/tracing.ts +110 -0
  155. package/src/{types.ts → core/types.ts} +46 -46
  156. package/src/{utils.ts → core/utils.ts} +64 -64
  157. package/src/{validate.ts → core/validate.ts} +252 -246
  158. package/src/{validator.ts → core/validator.ts} +92 -92
  159. package/src/{version.ts → core/version.ts} +24 -24
  160. package/src/{workflow-commands.ts → core/workflow-commands.ts} +32 -32
  161. package/src/i18n/en.json +45 -0
  162. package/src/i18n/index.ts +58 -0
  163. package/src/i18n/tr.json +45 -0
  164. package/src/providers/index.ts +29 -12
  165. package/src/providers/mock-provider.ts +200 -199
  166. package/src/providers/openai-provider.ts +88 -88
  167. package/src/skills/engine.ts +94 -0
  168. package/src/skills/fix-skill.ts +38 -0
  169. package/src/skills/generate-artifact-skill.ts +32 -0
  170. package/src/skills/generate-pipeline-skill.ts +49 -0
  171. package/src/skills/normalize-skill.ts +29 -0
  172. package/src/skills/types.ts +36 -0
  173. package/src/skills/validate-skill.ts +29 -0
@@ -1,208 +1,208 @@
1
- import path from "node:path";
2
- import os from "node:os";
3
- import { resolveAi, type SupportedAi } from "./agent-command-installer";
4
- import { UserError } from "./errors";
5
- import { fileExists } from "./utils";
6
-
7
- export type InitSelections = {
8
- ai?: SupportedAi;
9
- script: "sh" | "ps";
10
- lang: "tr" | "en";
11
- author: string;
12
- interactive: boolean;
13
- };
14
-
15
- type GatherInitUiOptions = {
16
- projectRoot: string;
17
- aiInput?: string;
18
- langInput?: string;
19
- authorInput?: string;
20
- };
21
-
22
- type ClackPrompts = typeof import("@clack/prompts");
23
-
24
- const dynamicImport = new Function("specifier", "return import(specifier)") as (
25
- specifier: string
26
- ) => Promise<unknown>;
27
-
28
- async function loadClack(): Promise<ClackPrompts> {
29
- return (await dynamicImport("@clack/prompts")) as ClackPrompts;
30
- }
31
-
32
- function isInteractiveTerminal(): boolean {
33
- return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
34
- }
35
-
36
- function color(text: string, code: string): string {
37
- return `${code}${text}\u001B[0m`;
38
- }
39
-
40
- function stripAnsi(input: string): string {
41
- return input.replace(/\u001B\[[0-9;]*m/g, "");
42
- }
43
-
44
- function centerLine(line: string, width: number): string {
45
- const visible = stripAnsi(line).length;
46
- const left = Math.max(0, Math.floor((width - visible) / 2));
47
- return `${" ".repeat(left)}${line}`;
48
- }
49
-
50
- function centerBlock(lines: string[], width: number): string {
51
- return lines.map((line) => centerLine(line, width)).join("\n");
52
- }
53
-
54
- function terminalWidth(): number {
55
- const columns = process.stdout.columns ?? 100;
56
- return Math.max(80, columns);
57
- }
58
-
59
- function renderLogo(): string {
60
- const cyan = "\u001B[38;5;45m";
61
- const blue = "\u001B[38;5;39m";
62
- const lines = [
63
- "██████╗ ██████╗ ██████╗ ██████╗ ██████╗ ",
64
- "██╔══██╗██╔══██╗██╔═══██╗██╔══██╗██╔═══██╗",
65
- "██████╔╝██████╔╝██║ ██║██║ ██║██║ ██║",
66
- "██╔═══╝ ██╔══██╗██║ ██║██║ ██║██║ ██║",
67
- "██║ ██║ ██║╚██████╔╝██████╔╝╚██████╔╝"
68
- ];
69
- return lines.map((line, idx) => color(line, idx % 2 === 0 ? cyan : blue)).join("\n");
70
- }
71
-
72
- function renderProjectBox(projectName: string, projectRoot: string): string {
73
- const content = [`Project ${projectName}`, `Directory ${projectRoot}`];
74
- const innerWidth = Math.max(...content.map((line) => line.length)) + 2;
75
- const top = `┌${"─".repeat(innerWidth)}┐`;
76
- const rows = content.map((line) => `│ ${line.padEnd(innerWidth - 1)}│`);
77
- const bottom = `└${"─".repeat(innerWidth)}┘`;
78
- return [top, ...rows, bottom].join("\n");
79
- }
80
-
81
- async function detectAi(projectRoot: string): Promise<SupportedAi | undefined> {
82
- if (await fileExists(path.join(projectRoot, ".agents"))) return "codex";
83
- if (await fileExists(path.join(projectRoot, ".gemini"))) return "gemini-cli";
84
- if (await fileExists(path.join(projectRoot, ".claude"))) return "claude-cli";
85
- return undefined;
86
- }
87
-
88
- function normalizeLang(lang?: string): "tr" | "en" {
89
- if ((lang ?? "").trim().toLowerCase().startsWith("tr")) return "tr";
90
- return "en";
91
- }
92
-
93
- function modelChoiceFromAi(ai?: SupportedAi): "codex" | "gemini" | "auto-detect" {
94
- if (ai === "codex") return "codex";
95
- if (ai === "gemini-cli") return "gemini";
96
- return "auto-detect";
97
- }
98
-
99
- function defaultAuthorName(authorInput?: string): string {
100
- const explicit = (authorInput ?? "").trim();
101
- if (explicit.length > 0) return explicit;
102
- try {
103
- const username = os.userInfo().username.trim();
104
- if (username.length > 0) return username;
105
- } catch {
106
- // ignore lookup errors and continue with fallback
107
- }
108
- return "Product Author";
109
- }
110
-
111
- export async function gatherInitSelections(options: GatherInitUiOptions): Promise<InitSelections> {
112
- const clack = await loadClack();
113
- const defaultLang = normalizeLang(options.langInput);
114
- const fallbackScript: "sh" | "ps" = process.platform === "win32" ? "ps" : "sh";
115
- const parsedAi = resolveAi(options.aiInput);
116
- const defaultAuthor = defaultAuthorName(options.authorInput);
117
-
118
- if (!isInteractiveTerminal()) {
119
- return {
120
- ai: parsedAi,
121
- script: fallbackScript,
122
- lang: defaultLang,
123
- author: defaultAuthor,
124
- interactive: false
125
- };
126
- }
127
-
128
- const detectedAi = await detectAi(options.projectRoot);
129
- const initialModel = modelChoiceFromAi(parsedAi ?? detectedAi);
130
- const projectName = path.basename(options.projectRoot) || ".";
131
- const width = terminalWidth();
132
- const subtitle = color("Prodo — Product Artifact Toolkit", "\u001B[1;37m");
133
- const signature = color("Crafted by Codex, guided by Shahmarasy intelligence", "\u001B[38;5;244m");
134
- const hero = [
135
- "",
136
- centerBlock(renderLogo().split("\n"), width),
137
- "",
138
- centerLine(subtitle, width),
139
- centerLine(signature, width),
140
- ""
141
- ].join("\n");
142
-
143
- clack.intro(hero);
144
- clack.note(renderProjectBox(projectName, options.projectRoot), "Project Setup");
145
-
146
- const model = await clack.select({
147
- message: "Select model",
148
- initialValue: initialModel,
149
- options: [
150
- { value: "codex", label: "codex", hint: "Native Codex flow" },
151
- { value: "gemini", label: "gemini", hint: "Gemini CLI command set" },
152
- { value: "auto-detect", label: "auto-detect", hint: "Detect from local agent directories" }
153
- ]
154
- });
155
- if (clack.isCancel(model)) {
156
- clack.cancel("Initialization cancelled.");
157
- throw new UserError("Initialization cancelled.");
158
- }
159
-
160
- const lang = await clack.select({
161
- message: "Select language",
162
- initialValue: defaultLang,
163
- options: [
164
- { value: "tr", label: "tr", hint: "Turkish" },
165
- { value: "en", label: "en", hint: "English" }
166
- ]
167
- });
168
- if (clack.isCancel(lang)) {
169
- clack.cancel("Initialization cancelled.");
170
- throw new UserError("Initialization cancelled.");
171
- }
172
-
173
- const author = await clack.text({
174
- message: "Author name",
175
- placeholder: "Shahmarasy",
176
- defaultValue: defaultAuthor
177
- });
178
- if (clack.isCancel(author)) {
179
- clack.cancel("Initialization cancelled.");
180
- throw new UserError("Initialization cancelled.");
181
- }
182
-
183
- let selectedAi: SupportedAi | undefined;
184
- if (model === "codex") selectedAi = "codex";
185
- else if (model === "gemini") selectedAi = "gemini-cli";
186
- else selectedAi = detectedAi;
187
-
188
- return {
189
- ai: selectedAi,
190
- script: fallbackScript,
191
- lang,
192
- author: String(author).trim() || defaultAuthor,
193
- interactive: true
194
- };
195
- }
196
-
197
- export function finishInitInteractive(summary: {
198
- projectRoot: string;
199
- settingsPath: string;
200
- ai?: SupportedAi;
201
- lang: "tr" | "en";
202
- author: string;
203
- }): Promise<void> {
204
- const aiText = summary.ai ?? "none";
205
- return loadClack().then((clack) => clack.outro(
206
- `Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nAuthor: ${summary.author}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`
207
- ));
208
- }
1
+ import path from "node:path";
2
+ import os from "node:os";
3
+ import { resolveAi, type SupportedAi } from "./agent-command-installer";
4
+ import { UserError } from "../core/errors";
5
+ import { fileExists } from "../core/utils";
6
+
7
+ export type InitSelections = {
8
+ ai?: SupportedAi;
9
+ script: "sh" | "ps";
10
+ lang: "tr" | "en";
11
+ author: string;
12
+ interactive: boolean;
13
+ };
14
+
15
+ type GatherInitUiOptions = {
16
+ projectRoot: string;
17
+ aiInput?: string;
18
+ langInput?: string;
19
+ authorInput?: string;
20
+ };
21
+
22
+ type ClackPrompts = typeof import("@clack/prompts");
23
+
24
+ const dynamicImport = new Function("specifier", "return import(specifier)") as (
25
+ specifier: string
26
+ ) => Promise<unknown>;
27
+
28
+ async function loadClack(): Promise<ClackPrompts> {
29
+ return (await dynamicImport("@clack/prompts")) as ClackPrompts;
30
+ }
31
+
32
+ function isInteractiveTerminal(): boolean {
33
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
34
+ }
35
+
36
+ function color(text: string, code: string): string {
37
+ return `${code}${text}\u001B[0m`;
38
+ }
39
+
40
+ function stripAnsi(input: string): string {
41
+ return input.replace(/\u001B\[[0-9;]*m/g, "");
42
+ }
43
+
44
+ function centerLine(line: string, width: number): string {
45
+ const visible = stripAnsi(line).length;
46
+ const left = Math.max(0, Math.floor((width - visible) / 2));
47
+ return `${" ".repeat(left)}${line}`;
48
+ }
49
+
50
+ function centerBlock(lines: string[], width: number): string {
51
+ return lines.map((line) => centerLine(line, width)).join("\n");
52
+ }
53
+
54
+ function terminalWidth(): number {
55
+ const columns = process.stdout.columns ?? 100;
56
+ return Math.max(80, columns);
57
+ }
58
+
59
+ function renderLogo(): string {
60
+ const cyan = "\u001B[38;5;45m";
61
+ const blue = "\u001B[38;5;39m";
62
+ const lines = [
63
+ "██████╗ ██████╗ ██████╗ ██████╗ ██████╗ ",
64
+ "██╔══██╗██╔══██╗██╔═══██╗██╔══██╗██╔═══██╗",
65
+ "██████╔╝██████╔╝██║ ██║██║ ██║██║ ██║",
66
+ "██╔═══╝ ██╔══██╗██║ ██║██║ ██║██║ ██║",
67
+ "██║ ██║ ██║╚██████╔╝██████╔╝╚██████╔╝"
68
+ ];
69
+ return lines.map((line, idx) => color(line, idx % 2 === 0 ? cyan : blue)).join("\n");
70
+ }
71
+
72
+ function renderProjectBox(projectName: string, projectRoot: string): string {
73
+ const content = [`Project ${projectName}`, `Directory ${projectRoot}`];
74
+ const innerWidth = Math.max(...content.map((line) => line.length)) + 2;
75
+ const top = `┌${"─".repeat(innerWidth)}┐`;
76
+ const rows = content.map((line) => `│ ${line.padEnd(innerWidth - 1)}│`);
77
+ const bottom = `└${"─".repeat(innerWidth)}┘`;
78
+ return [top, ...rows, bottom].join("\n");
79
+ }
80
+
81
+ async function detectAi(projectRoot: string): Promise<SupportedAi | undefined> {
82
+ if (await fileExists(path.join(projectRoot, ".agents"))) return "codex";
83
+ if (await fileExists(path.join(projectRoot, ".gemini"))) return "gemini-cli";
84
+ if (await fileExists(path.join(projectRoot, ".claude"))) return "claude-cli";
85
+ return undefined;
86
+ }
87
+
88
+ function normalizeLang(lang?: string): "tr" | "en" {
89
+ if ((lang ?? "").trim().toLowerCase().startsWith("tr")) return "tr";
90
+ return "en";
91
+ }
92
+
93
+ function modelChoiceFromAi(ai?: SupportedAi): "codex" | "gemini" | "auto-detect" {
94
+ if (ai === "codex") return "codex";
95
+ if (ai === "gemini-cli") return "gemini";
96
+ return "auto-detect";
97
+ }
98
+
99
+ function defaultAuthorName(authorInput?: string): string {
100
+ const explicit = (authorInput ?? "").trim();
101
+ if (explicit.length > 0) return explicit;
102
+ try {
103
+ const username = os.userInfo().username.trim();
104
+ if (username.length > 0) return username;
105
+ } catch {
106
+ // ignore lookup errors and continue with fallback
107
+ }
108
+ return "Product Author";
109
+ }
110
+
111
+ export async function gatherInitSelections(options: GatherInitUiOptions): Promise<InitSelections> {
112
+ const clack = await loadClack();
113
+ const defaultLang = normalizeLang(options.langInput);
114
+ const fallbackScript: "sh" | "ps" = process.platform === "win32" ? "ps" : "sh";
115
+ const parsedAi = resolveAi(options.aiInput);
116
+ const defaultAuthor = defaultAuthorName(options.authorInput);
117
+
118
+ if (!isInteractiveTerminal()) {
119
+ return {
120
+ ai: parsedAi,
121
+ script: fallbackScript,
122
+ lang: defaultLang,
123
+ author: defaultAuthor,
124
+ interactive: false
125
+ };
126
+ }
127
+
128
+ const detectedAi = await detectAi(options.projectRoot);
129
+ const initialModel = modelChoiceFromAi(parsedAi ?? detectedAi);
130
+ const projectName = path.basename(options.projectRoot) || ".";
131
+ const width = terminalWidth();
132
+ const subtitle = color("Prodo — Product Artifact Toolkit", "\u001B[1;37m");
133
+ const signature = color("Crafted by Codex, guided by Shahmarasy intelligence", "\u001B[38;5;244m");
134
+ const hero = [
135
+ "",
136
+ centerBlock(renderLogo().split("\n"), width),
137
+ "",
138
+ centerLine(subtitle, width),
139
+ centerLine(signature, width),
140
+ ""
141
+ ].join("\n");
142
+
143
+ clack.intro(hero);
144
+ clack.note(renderProjectBox(projectName, options.projectRoot), "Project Setup");
145
+
146
+ const model = await clack.select({
147
+ message: "Select model",
148
+ initialValue: initialModel,
149
+ options: [
150
+ { value: "codex", label: "codex", hint: "Native Codex flow" },
151
+ { value: "gemini", label: "gemini", hint: "Gemini CLI command set" },
152
+ { value: "auto-detect", label: "auto-detect", hint: "Detect from local agent directories" }
153
+ ]
154
+ });
155
+ if (clack.isCancel(model)) {
156
+ clack.cancel("Initialization cancelled.");
157
+ throw new UserError("Initialization cancelled.");
158
+ }
159
+
160
+ const lang = await clack.select({
161
+ message: "Select language",
162
+ initialValue: defaultLang,
163
+ options: [
164
+ { value: "tr", label: "tr", hint: "Turkish" },
165
+ { value: "en", label: "en", hint: "English" }
166
+ ]
167
+ });
168
+ if (clack.isCancel(lang)) {
169
+ clack.cancel("Initialization cancelled.");
170
+ throw new UserError("Initialization cancelled.");
171
+ }
172
+
173
+ const author = await clack.text({
174
+ message: "Author name",
175
+ placeholder: "Shahmarasy",
176
+ defaultValue: defaultAuthor
177
+ });
178
+ if (clack.isCancel(author)) {
179
+ clack.cancel("Initialization cancelled.");
180
+ throw new UserError("Initialization cancelled.");
181
+ }
182
+
183
+ let selectedAi: SupportedAi | undefined;
184
+ if (model === "codex") selectedAi = "codex";
185
+ else if (model === "gemini") selectedAi = "gemini-cli";
186
+ else selectedAi = detectedAi;
187
+
188
+ return {
189
+ ai: selectedAi,
190
+ script: fallbackScript,
191
+ lang,
192
+ author: String(author).trim() || defaultAuthor,
193
+ interactive: true
194
+ };
195
+ }
196
+
197
+ export function finishInitInteractive(summary: {
198
+ projectRoot: string;
199
+ settingsPath: string;
200
+ ai?: SupportedAi;
201
+ lang: "tr" | "en";
202
+ author: string;
203
+ }): Promise<void> {
204
+ const aiText = summary.ai ?? "none";
205
+ return loadClack().then((clack) => clack.outro(
206
+ `Scaffold complete.\nAI: ${aiText}\nLanguage: ${summary.lang}\nAuthor: ${summary.author}\nSettings: ${summary.settingsPath}\nNext: edit brief.md`
207
+ ));
208
+ }