agentic-dev 0.2.9 → 0.2.11

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 (291) hide show
  1. package/README.md +23 -8
  2. package/bin/agentic-dev.mjs +692 -55
  3. package/lib/scaffold.mjs +109 -6
  4. package/package.json +1 -1
  5. package/client/admin/.dockerignore +0 -3
  6. package/client/admin/.env.example +0 -1
  7. package/client/admin/Dockerfile +0 -16
  8. package/client/admin/Dockerfile.dev +0 -18
  9. package/client/admin/README.md +0 -20
  10. package/client/admin/index.html +0 -12
  11. package/client/admin/package.json +0 -41
  12. package/client/admin/postcss.config.js +0 -6
  13. package/client/admin/scripts/ui-parity-admin-adapter.mjs +0 -65
  14. package/client/admin/src/api/alerts.ts +0 -33
  15. package/client/admin/src/api/client.ts +0 -71
  16. package/client/admin/src/api/orders.ts +0 -33
  17. package/client/admin/src/api/support.ts +0 -11
  18. package/client/admin/src/app/App.tsx +0 -23
  19. package/client/admin/src/auth/AuthProvider.tsx +0 -122
  20. package/client/admin/src/auth/ProtectedRoute.tsx +0 -22
  21. package/client/admin/src/auth/auth-client.ts +0 -38
  22. package/client/admin/src/auth/types.ts +0 -18
  23. package/client/admin/src/components/AdminNotificationsDrawer.tsx +0 -162
  24. package/client/admin/src/components/AdminShell.tsx +0 -76
  25. package/client/admin/src/components/ui/button.tsx +0 -34
  26. package/client/admin/src/components/ui/input.tsx +0 -21
  27. package/client/admin/src/lib/cn.ts +0 -6
  28. package/client/admin/src/lib/specRouteCatalog.json +0 -30
  29. package/client/admin/src/lib/specScreens.json +0 -22
  30. package/client/admin/src/main.tsx +0 -17
  31. package/client/admin/src/pages/AdminDashboardPage.tsx +0 -171
  32. package/client/admin/src/pages/AdminLoginPage.tsx +0 -75
  33. package/client/admin/src/pages/AdminQueuePage.tsx +0 -107
  34. package/client/admin/src/pages/AdminSupportPage.tsx +0 -61
  35. package/client/admin/src/styles/globals.css +0 -17
  36. package/client/admin/src/theme-vars.ts +0 -18
  37. package/client/admin/src/theme.ts +0 -25
  38. package/client/admin/src/vite-env.d.ts +0 -1
  39. package/client/admin/tailwind.config.js +0 -8
  40. package/client/admin/tsconfig.json +0 -25
  41. package/client/admin/vite.config.ts +0 -12
  42. package/client/landing/.dockerignore +0 -3
  43. package/client/landing/.env.example +0 -1
  44. package/client/landing/Dockerfile +0 -16
  45. package/client/landing/Dockerfile.dev +0 -18
  46. package/client/landing/README.md +0 -18
  47. package/client/landing/index.html +0 -12
  48. package/client/landing/package.json +0 -41
  49. package/client/landing/postcss.config.js +0 -6
  50. package/client/landing/scripts/ui-parity-landing-adapter.mjs +0 -65
  51. package/client/landing/src/App.tsx +0 -21
  52. package/client/landing/src/api/catalog.ts +0 -30
  53. package/client/landing/src/api/client.ts +0 -30
  54. package/client/landing/src/auth/AuthProvider.tsx +0 -122
  55. package/client/landing/src/auth/ProtectedRoute.tsx +0 -22
  56. package/client/landing/src/auth/auth-client.ts +0 -38
  57. package/client/landing/src/auth/types.ts +0 -18
  58. package/client/landing/src/components/LandingShell.tsx +0 -34
  59. package/client/landing/src/lib/specRouteCatalog.json +0 -23
  60. package/client/landing/src/lib/specScreens.json +0 -17
  61. package/client/landing/src/main.tsx +0 -17
  62. package/client/landing/src/pages/LandingHomePage.tsx +0 -215
  63. package/client/landing/src/pages/LandingLoginPage.tsx +0 -90
  64. package/client/landing/src/pages/LandingWorkspacePage.tsx +0 -126
  65. package/client/landing/src/styles/globals.css +0 -17
  66. package/client/landing/src/theme-vars.ts +0 -16
  67. package/client/landing/src/theme.ts +0 -21
  68. package/client/landing/src/vite-env.d.ts +0 -1
  69. package/client/landing/tailwind.config.js +0 -8
  70. package/client/landing/tsconfig.json +0 -25
  71. package/client/landing/vite.config.ts +0 -12
  72. package/client/mobile/.dockerignore +0 -2
  73. package/client/mobile/.env.example +0 -1
  74. package/client/mobile/Dockerfile +0 -16
  75. package/client/mobile/Dockerfile.dev +0 -18
  76. package/client/mobile/README.md +0 -19
  77. package/client/mobile/index.html +0 -12
  78. package/client/mobile/package.json +0 -42
  79. package/client/mobile/postcss.config.js +0 -6
  80. package/client/mobile/scripts/ui-parity-mobile-adapter.mjs +0 -67
  81. package/client/mobile/src/App.tsx +0 -1
  82. package/client/mobile/src/api/client.ts +0 -62
  83. package/client/mobile/src/api/fulfillment.ts +0 -55
  84. package/client/mobile/src/api/shipping.ts +0 -56
  85. package/client/mobile/src/app/App.tsx +0 -23
  86. package/client/mobile/src/auth/AuthProvider.tsx +0 -122
  87. package/client/mobile/src/auth/ProtectedRoute.tsx +0 -27
  88. package/client/mobile/src/auth/auth-client.ts +0 -38
  89. package/client/mobile/src/auth/types.ts +0 -18
  90. package/client/mobile/src/components/InShell.tsx +0 -74
  91. package/client/mobile/src/components/ui/button.tsx +0 -35
  92. package/client/mobile/src/components/ui/card.tsx +0 -15
  93. package/client/mobile/src/components/ui/input.tsx +0 -21
  94. package/client/mobile/src/lib/cn.ts +0 -6
  95. package/client/mobile/src/lib/specRouteCatalog.json +0 -26
  96. package/client/mobile/src/lib/specScreens.json +0 -22
  97. package/client/mobile/src/lib/useSpeechRecognitionInput.ts +0 -271
  98. package/client/mobile/src/main.tsx +0 -17
  99. package/client/mobile/src/pages/DashboardPage.tsx +0 -172
  100. package/client/mobile/src/pages/FulfillmentPage.tsx +0 -138
  101. package/client/mobile/src/pages/LoginPage.tsx +0 -74
  102. package/client/mobile/src/pages/ShippingPage.tsx +0 -338
  103. package/client/mobile/src/styles/globals.css +0 -23
  104. package/client/mobile/src/theme-vars.ts +0 -16
  105. package/client/mobile/src/theme.ts +0 -21
  106. package/client/mobile/src/vite-env.d.ts +0 -1
  107. package/client/mobile/tailwind.config.js +0 -8
  108. package/client/mobile/tsconfig.json +0 -25
  109. package/client/mobile/vite.config.ts +0 -12
  110. package/client/web/.dockerignore +0 -3
  111. package/client/web/.env.example +0 -1
  112. package/client/web/Dockerfile +0 -16
  113. package/client/web/Dockerfile.dev +0 -18
  114. package/client/web/README.md +0 -47
  115. package/client/web/index.html +0 -12
  116. package/client/web/package.json +0 -42
  117. package/client/web/postcss.config.js +0 -6
  118. package/client/web/scripts/ui-parity-web-adapter.mjs +0 -66
  119. package/client/web/src/api/client.ts +0 -30
  120. package/client/web/src/api/orders.ts +0 -42
  121. package/client/web/src/app/App.tsx +0 -21
  122. package/client/web/src/auth/AuthProvider.tsx +0 -122
  123. package/client/web/src/auth/ProtectedRoute.tsx +0 -22
  124. package/client/web/src/auth/auth-client.ts +0 -38
  125. package/client/web/src/auth/types.ts +0 -18
  126. package/client/web/src/components/AppShell.tsx +0 -59
  127. package/client/web/src/components/ui/button.tsx +0 -35
  128. package/client/web/src/components/ui/card.tsx +0 -7
  129. package/client/web/src/components/ui/input.tsx +0 -21
  130. package/client/web/src/lib/cn.ts +0 -6
  131. package/client/web/src/lib/specRouteCatalog.json +0 -23
  132. package/client/web/src/lib/specScreens.json +0 -17
  133. package/client/web/src/main.tsx +0 -17
  134. package/client/web/src/pages/DashboardPage.tsx +0 -158
  135. package/client/web/src/pages/LoginPage.tsx +0 -72
  136. package/client/web/src/pages/OrdersPage.tsx +0 -123
  137. package/client/web/src/styles/globals.css +0 -17
  138. package/client/web/src/theme-vars.ts +0 -18
  139. package/client/web/src/theme.ts +0 -25
  140. package/client/web/src/vite-env.d.ts +0 -1
  141. package/client/web/tailwind.config.js +0 -8
  142. package/client/web/tsconfig.json +0 -25
  143. package/client/web/vite.config.ts +0 -12
  144. package/server/.dockerignore +0 -4
  145. package/server/.env.example +0 -19
  146. package/server/Dockerfile +0 -22
  147. package/server/Dockerfile.dev +0 -19
  148. package/server/README.md +0 -33
  149. package/server/__init__.py +0 -0
  150. package/server/api/__init__.py +0 -1
  151. package/server/api/http/__init__.py +0 -4
  152. package/server/api/http/app.py +0 -53
  153. package/server/api/http/router.py +0 -24
  154. package/server/config.py +0 -52
  155. package/server/contexts/__init__.py +0 -12
  156. package/server/contexts/alerts/__init__.py +0 -1
  157. package/server/contexts/alerts/application/__init__.py +0 -13
  158. package/server/contexts/alerts/application/services.py +0 -41
  159. package/server/contexts/alerts/contracts/__init__.py +0 -3
  160. package/server/contexts/alerts/contracts/http/__init__.py +0 -3
  161. package/server/contexts/alerts/contracts/http/router.py +0 -37
  162. package/server/contexts/alerts/domain/__init__.py +0 -15
  163. package/server/contexts/alerts/domain/models.py +0 -29
  164. package/server/contexts/alerts/infrastructure/__init__.py +0 -11
  165. package/server/contexts/alerts/infrastructure/repository.py +0 -41
  166. package/server/contexts/auth/__init__.py +0 -1
  167. package/server/contexts/auth/application/__init__.py +0 -3
  168. package/server/contexts/auth/application/ports.py +0 -10
  169. package/server/contexts/auth/application/services.py +0 -64
  170. package/server/contexts/auth/contracts/__init__.py +0 -4
  171. package/server/contexts/auth/contracts/http/__init__.py +0 -4
  172. package/server/contexts/auth/contracts/http/dependencies.py +0 -37
  173. package/server/contexts/auth/contracts/http/router.py +0 -19
  174. package/server/contexts/auth/domain/__init__.py +0 -3
  175. package/server/contexts/auth/domain/models.py +0 -24
  176. package/server/contexts/auth/infrastructure/__init__.py +0 -4
  177. package/server/contexts/auth/infrastructure/adapters/memory.py +0 -19
  178. package/server/contexts/auth/infrastructure/adapters/mongodb.py +0 -24
  179. package/server/contexts/auth/infrastructure/adapters/sqlalchemy.py +0 -74
  180. package/server/contexts/auth/infrastructure/repository.py +0 -28
  181. package/server/contexts/catalog/__init__.py +0 -1
  182. package/server/contexts/catalog/application/__init__.py +0 -28
  183. package/server/contexts/catalog/application/ports.py +0 -15
  184. package/server/contexts/catalog/application/services.py +0 -154
  185. package/server/contexts/catalog/contracts/__init__.py +0 -3
  186. package/server/contexts/catalog/contracts/http/__init__.py +0 -3
  187. package/server/contexts/catalog/contracts/http/router.py +0 -60
  188. package/server/contexts/catalog/domain/__init__.py +0 -45
  189. package/server/contexts/catalog/domain/models.py +0 -113
  190. package/server/contexts/catalog/infrastructure/__init__.py +0 -4
  191. package/server/contexts/catalog/infrastructure/adapters/memory.py +0 -62
  192. package/server/contexts/catalog/infrastructure/repository.py +0 -8
  193. package/server/contexts/fulfillment/__init__.py +0 -1
  194. package/server/contexts/fulfillment/application/__init__.py +0 -13
  195. package/server/contexts/fulfillment/application/ports.py +0 -20
  196. package/server/contexts/fulfillment/application/services.py +0 -85
  197. package/server/contexts/fulfillment/contracts/__init__.py +0 -3
  198. package/server/contexts/fulfillment/contracts/http/__init__.py +0 -3
  199. package/server/contexts/fulfillment/contracts/http/router.py +0 -40
  200. package/server/contexts/fulfillment/domain/__init__.py +0 -25
  201. package/server/contexts/fulfillment/domain/models.py +0 -73
  202. package/server/contexts/fulfillment/infrastructure/__init__.py +0 -13
  203. package/server/contexts/fulfillment/infrastructure/adapters/memory.py +0 -43
  204. package/server/contexts/fulfillment/infrastructure/repository.py +0 -97
  205. package/server/contexts/health/__init__.py +0 -1
  206. package/server/contexts/health/application/__init__.py +0 -3
  207. package/server/contexts/health/application/services.py +0 -2
  208. package/server/contexts/health/contracts/__init__.py +0 -3
  209. package/server/contexts/health/contracts/http/__init__.py +0 -3
  210. package/server/contexts/health/contracts/http/router.py +0 -10
  211. package/server/contexts/inventory/__init__.py +0 -1
  212. package/server/contexts/inventory/application/__init__.py +0 -28
  213. package/server/contexts/inventory/application/ports.py +0 -11
  214. package/server/contexts/inventory/application/services.py +0 -214
  215. package/server/contexts/inventory/contracts/__init__.py +0 -3
  216. package/server/contexts/inventory/contracts/http/__init__.py +0 -3
  217. package/server/contexts/inventory/contracts/http/router.py +0 -82
  218. package/server/contexts/inventory/domain/__init__.py +0 -33
  219. package/server/contexts/inventory/domain/models.py +0 -93
  220. package/server/contexts/inventory/infrastructure/__init__.py +0 -4
  221. package/server/contexts/inventory/infrastructure/adapters/memory.py +0 -24
  222. package/server/contexts/inventory/infrastructure/repository.py +0 -8
  223. package/server/contexts/orders/__init__.py +0 -1
  224. package/server/contexts/orders/application/__init__.py +0 -19
  225. package/server/contexts/orders/application/services.py +0 -127
  226. package/server/contexts/orders/contracts/__init__.py +0 -3
  227. package/server/contexts/orders/contracts/http/__init__.py +0 -3
  228. package/server/contexts/orders/contracts/http/router.py +0 -82
  229. package/server/contexts/orders/domain/__init__.py +0 -29
  230. package/server/contexts/orders/domain/models.py +0 -95
  231. package/server/contexts/orders/infrastructure/__init__.py +0 -7
  232. package/server/contexts/orders/infrastructure/repository.py +0 -104
  233. package/server/contexts/shipping/__init__.py +0 -1
  234. package/server/contexts/shipping/application/__init__.py +0 -13
  235. package/server/contexts/shipping/application/services.py +0 -92
  236. package/server/contexts/shipping/contracts/__init__.py +0 -3
  237. package/server/contexts/shipping/contracts/http/__init__.py +0 -3
  238. package/server/contexts/shipping/contracts/http/router.py +0 -40
  239. package/server/contexts/shipping/domain/__init__.py +0 -19
  240. package/server/contexts/shipping/domain/models.py +0 -48
  241. package/server/contexts/shipping/infrastructure/__init__.py +0 -9
  242. package/server/contexts/shipping/infrastructure/repository.py +0 -50
  243. package/server/contexts/support/__init__.py +0 -1
  244. package/server/contexts/support/application/__init__.py +0 -13
  245. package/server/contexts/support/application/services.py +0 -29
  246. package/server/contexts/support/contracts/__init__.py +0 -3
  247. package/server/contexts/support/contracts/http/__init__.py +0 -3
  248. package/server/contexts/support/contracts/http/router.py +0 -40
  249. package/server/contexts/support/domain/__init__.py +0 -13
  250. package/server/contexts/support/domain/models.py +0 -27
  251. package/server/contexts/support/infrastructure/__init__.py +0 -11
  252. package/server/contexts/support/infrastructure/repository.py +0 -70
  253. package/server/contexts/user/__init__.py +0 -1
  254. package/server/contexts/user/application/__init__.py +0 -3
  255. package/server/contexts/user/application/ports.py +0 -11
  256. package/server/contexts/user/application/services.py +0 -44
  257. package/server/contexts/user/contracts/__init__.py +0 -3
  258. package/server/contexts/user/contracts/http/__init__.py +0 -3
  259. package/server/contexts/user/contracts/http/router.py +0 -26
  260. package/server/contexts/user/domain/__init__.py +0 -3
  261. package/server/contexts/user/domain/models.py +0 -22
  262. package/server/contexts/user/infrastructure/__init__.py +0 -3
  263. package/server/contexts/user/infrastructure/adapters/memory.py +0 -27
  264. package/server/contexts/user/infrastructure/adapters/mongodb.py +0 -41
  265. package/server/contexts/user/infrastructure/adapters/sqlalchemy.py +0 -94
  266. package/server/contexts/user/infrastructure/factory.py +0 -28
  267. package/server/data/README.md +0 -24
  268. package/server/data/bootstrap/alerts.json +0 -38
  269. package/server/data/bootstrap/auth_accounts.json +0 -18
  270. package/server/data/bootstrap/catalog_products.json +0 -179
  271. package/server/data/bootstrap/fulfillment_events.json +0 -5
  272. package/server/data/bootstrap/fulfillment_notes.json +0 -5
  273. package/server/data/bootstrap/fulfillment_tasks.json +0 -50
  274. package/server/data/bootstrap/inventory_levels.json +0 -80
  275. package/server/data/bootstrap/orders.json +0 -62
  276. package/server/data/bootstrap/shipping_shipments.json +0 -50
  277. package/server/data/bootstrap/support_faqs.json +0 -26
  278. package/server/data/bootstrap/users.json +0 -20
  279. package/server/data/bootstrap_loader.py +0 -15
  280. package/server/docker-entrypoint.sh +0 -56
  281. package/server/main.py +0 -3
  282. package/server/pyproject.toml +0 -36
  283. package/server/shared/__init__.py +0 -1
  284. package/server/shared/application/__init__.py +0 -3
  285. package/server/shared/application/health.py +0 -2
  286. package/server/shared/infrastructure/__init__.py +0 -10
  287. package/server/shared/infrastructure/runtime.py +0 -6
  288. package/server/shared/infrastructure/security.py +0 -33
  289. package/server/tests/e2e/test_domain_feature_flows.py +0 -483
  290. package/server/tests/test_health.py +0 -49
  291. package/server/uv.lock +0 -1169
package/lib/scaffold.mjs CHANGED
@@ -43,7 +43,8 @@ function copyDirectoryContents(sourceRoot, destinationRoot) {
43
43
  }
44
44
 
45
45
  function fetchPage(url) {
46
- const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || process.env.AGENTIC_GITHUB_TOKEN;
46
+ const token =
47
+ process.env.GH_TOKEN || process.env.GITHUB_TOKEN || process.env.AGENTIC_GITHUB_TOKEN;
47
48
  return fetch(url, {
48
49
  headers: {
49
50
  Accept: "application/vnd.github+json",
@@ -58,8 +59,13 @@ export function parseArgs(argv) {
58
59
  const options = {
59
60
  command: "init",
60
61
  targetDir: "",
62
+ projectName: "",
61
63
  template: "",
62
64
  owner: DEFAULT_TEMPLATE_OWNER,
65
+ appMode: "",
66
+ aiProviders: [],
67
+ githubAuthMode: "",
68
+ githubPat: "",
63
69
  force: false,
64
70
  yes: false,
65
71
  skipBootstrap: false,
@@ -76,9 +82,30 @@ export function parseArgs(argv) {
76
82
  case "-t":
77
83
  options.template = args.shift() ?? "";
78
84
  break;
85
+ case "--project-name":
86
+ options.projectName = args.shift() ?? "";
87
+ break;
79
88
  case "--owner":
80
89
  options.owner = args.shift() ?? DEFAULT_TEMPLATE_OWNER;
81
90
  break;
91
+ case "--app-mode":
92
+ options.appMode = args.shift() ?? "";
93
+ break;
94
+ case "--providers":
95
+ case "--provider": {
96
+ const value = args.shift() ?? "";
97
+ options.aiProviders = value
98
+ .split(",")
99
+ .map((entry) => entry.trim())
100
+ .filter(Boolean);
101
+ break;
102
+ }
103
+ case "--github-auth":
104
+ options.githubAuthMode = args.shift() ?? "";
105
+ break;
106
+ case "--github-pat":
107
+ options.githubPat = args.shift() ?? "";
108
+ break;
82
109
  case "--force":
83
110
  options.force = true;
84
111
  break;
@@ -115,10 +142,16 @@ export function usage() {
115
142
  " npx agentic-dev",
116
143
  " npx agentic-dev init my-app",
117
144
  " npx agentic-dev init my-app --template template-web --yes",
145
+ " npx agentic-dev init my-app --template template-web --project-name my-app --providers codex,claude",
118
146
  "",
119
147
  "Options:",
120
148
  " --template, -t Template repo name or suffix to use",
149
+ " --project-name Project name written into scaffold metadata",
121
150
  " --owner GitHub owner for template-* repos (default: say828)",
151
+ " --app-mode App mode: fullstack, frontend, backend",
152
+ " --providers Comma-separated AI providers: codex, claude, ollama",
153
+ " --github-auth GitHub auth mode: public, env, pat",
154
+ " --github-pat GitHub PAT for this run only",
122
155
  " --force Allow scaffolding into a non-empty directory",
123
156
  " --yes, -y Skip interactive prompts",
124
157
  " --skip-bootstrap Copy the template but skip install/bootstrap",
@@ -177,6 +210,22 @@ export async function fetchTemplateRepos({ owner = DEFAULT_TEMPLATE_OWNER } = {}
177
210
  return repos;
178
211
  }
179
212
 
213
+ function updateJsonFile(filePath, updater) {
214
+ if (!fs.existsSync(filePath)) {
215
+ return;
216
+ }
217
+
218
+ let current = {};
219
+ try {
220
+ current = JSON.parse(fs.readFileSync(filePath, "utf-8"));
221
+ } catch (error) {
222
+ return;
223
+ }
224
+
225
+ const next = updater(current);
226
+ fs.writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\n`);
227
+ }
228
+
180
229
  export function resolveTemplateRepo(input, repos) {
181
230
  const normalized = (input || "").trim();
182
231
  if (!normalized) {
@@ -323,7 +372,51 @@ function validateTemplateRepoContents(destinationRoot, templateRepo) {
323
372
  }
324
373
  }
325
374
 
326
- function runInstallSteps(destinationRoot, bootstrapTarget) {
375
+ function writeSetupConfig(destinationRoot, setupSelections = {}) {
376
+ const outputDir = path.join(destinationRoot, ".agentic-dev");
377
+ fs.mkdirSync(outputDir, { recursive: true });
378
+ const outputPath = path.join(outputDir, "setup.json");
379
+
380
+ const setupConfig = {
381
+ project_name: setupSelections.projectName || path.basename(destinationRoot),
382
+ template_repo: setupSelections.templateRepo || "",
383
+ template_owner: setupSelections.owner || DEFAULT_TEMPLATE_OWNER,
384
+ app_mode: setupSelections.appMode || "fullstack",
385
+ ai_providers: Array.isArray(setupSelections.aiProviders) ? setupSelections.aiProviders : [],
386
+ github_auth_mode: setupSelections.githubAuthMode || "public",
387
+ github_pat_supplied: Boolean(setupSelections.githubPat),
388
+ skip_bootstrap: Boolean(setupSelections.skipBootstrap),
389
+ };
390
+
391
+ fs.writeFileSync(outputPath, `${JSON.stringify(setupConfig, null, 2)}\n`);
392
+ }
393
+
394
+ function applyProviderSelections(destinationRoot, providers = []) {
395
+ if (providers.length === 0) {
396
+ return;
397
+ }
398
+
399
+ if (!providers.includes("claude")) {
400
+ fs.rmSync(path.join(destinationRoot, ".claude"), { recursive: true, force: true });
401
+ }
402
+
403
+ if (!providers.includes("codex")) {
404
+ fs.rmSync(path.join(destinationRoot, ".codex"), { recursive: true, force: true });
405
+ }
406
+ }
407
+
408
+ function applyProjectMetadata(destinationRoot, setupSelections = {}) {
409
+ if (!setupSelections.projectName) {
410
+ return;
411
+ }
412
+
413
+ updateJsonFile(path.join(destinationRoot, ".claude", "workspace-config.json"), (current) => ({
414
+ ...current,
415
+ nickname: setupSelections.projectName,
416
+ }));
417
+ }
418
+
419
+ function runInstallSteps(destinationRoot, bootstrapTarget, { installBrowser = true } = {}) {
327
420
  maybeCreateEnvFile(destinationRoot);
328
421
 
329
422
  const pnpmCommand = ensurePnpm();
@@ -334,7 +427,7 @@ function runInstallSteps(destinationRoot, bootstrapTarget) {
334
427
 
335
428
  const executedSteps = ["pnpm install"];
336
429
 
337
- if (bootstrapTarget) {
430
+ if (bootstrapTarget && installBrowser) {
338
431
  runCommand(
339
432
  pnpmCommand[0],
340
433
  [
@@ -395,14 +488,24 @@ export function scaffoldFromTemplateRepo({ destinationRoot, templateRepo }) {
395
488
  export function installTemplateRepo({
396
489
  destinationRoot,
397
490
  templateRepo,
491
+ setupSelections = {},
398
492
  skipBootstrap = false,
399
493
  }) {
400
494
  scaffoldFromTemplateRepo({ destinationRoot, templateRepo });
495
+ applyProviderSelections(destinationRoot, setupSelections.aiProviders);
496
+ applyProjectMetadata(destinationRoot, setupSelections);
497
+ writeSetupConfig(destinationRoot, {
498
+ ...setupSelections,
499
+ templateRepo: templateRepo.name,
500
+ skipBootstrap,
501
+ });
401
502
  validateTemplateRepoContents(destinationRoot, templateRepo);
402
503
  const bootstrapTarget = resolveBootstrapTarget(destinationRoot);
504
+ const effectiveSkipBootstrap = skipBootstrap || setupSelections.appMode === "backend";
505
+ const installBrowser = setupSelections.appMode !== "backend";
403
506
 
404
- const executedSteps = runInstallSteps(destinationRoot, bootstrapTarget);
405
- if (!skipBootstrap) {
507
+ const executedSteps = runInstallSteps(destinationRoot, bootstrapTarget, { installBrowser });
508
+ if (!effectiveSkipBootstrap) {
406
509
  executedSteps.push(...runBootstrapStep(destinationRoot, bootstrapTarget));
407
510
  }
408
511
  const bootstrapHint = bootstrapTarget
@@ -412,6 +515,6 @@ export function installTemplateRepo({
412
515
  destinationRoot,
413
516
  templateRepo: templateRepo.name,
414
517
  executedSteps,
415
- nextSteps: skipBootstrap ? [bootstrapHint] : [],
518
+ nextSteps: effectiveSkipBootstrap ? [bootstrapHint] : [],
416
519
  };
417
520
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-dev",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Scaffold a public say828/template-* repo and run install/bootstrap automatically.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.32.0",
@@ -1,3 +0,0 @@
1
- node_modules
2
- dist
3
- .env
@@ -1 +0,0 @@
1
- VITE_API_BASE_URL=http://127.0.0.1:8000/api/v1
@@ -1,16 +0,0 @@
1
- FROM node:20-slim
2
-
3
- WORKDIR /app
4
-
5
- COPY pnpm-lock.yaml pnpm-workspace.yaml ./
6
- COPY client/admin/package.json ./client/admin/package.json
7
-
8
- RUN npm install -g pnpm@10.32.0 && pnpm install --filter @do4ai/client-admin-template...
9
-
10
- COPY . .
11
-
12
- WORKDIR /app/client/admin
13
-
14
- EXPOSE 4000
15
-
16
- CMD ["pnpm", "dev", "--host", "0.0.0.0", "--port", "4000"]
@@ -1,18 +0,0 @@
1
- FROM node:20-slim
2
-
3
- WORKDIR /app
4
-
5
- RUN npm install -g pnpm@10.32.0
6
-
7
- COPY pnpm-lock.yaml pnpm-workspace.yaml ./
8
- COPY client/admin/package.json ./client/admin/package.json
9
-
10
- RUN pnpm install --frozen-lockfile --filter @do4ai/client-admin-template...
11
-
12
- COPY client/admin ./client/admin
13
-
14
- WORKDIR /app/client/admin
15
-
16
- EXPOSE 4000
17
-
18
- CMD ["sh", "-lc", "pnpm exec vite --host 0.0.0.0 --port ${PORT:-4000}"]
@@ -1,20 +0,0 @@
1
- # admin
2
-
3
- 운영 콘솔형 관리자 UI 보일러플레이트다.
4
-
5
- 포함 패턴:
6
-
7
- - 좌측 sidebar + 상단 topbar
8
- - route 이동 대신 열리는 알림 drawer
9
- - 목록형 운영 테이블
10
- - modal/drawer를 제품 shell에서 직접 제어하는 구조
11
- - CSS variable 기반 parity-friendly token surface
12
-
13
- 시작:
14
-
15
- ```bash
16
- npm install
17
- npm run dev
18
- ```
19
-
20
- 기본 DEV 포트는 `4000`이다.
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>client-admin template</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/src/main.tsx"></script>
11
- </body>
12
- </html>
@@ -1,41 +0,0 @@
1
- {
2
- "name": "@do4ai/client-admin-template",
3
- "private": true,
4
- "version": "0.1.0",
5
- "type": "module",
6
- "packageManager": "pnpm@10.32.0",
7
- "scripts": {
8
- "dev": "vite --host 0.0.0.0 --port 4000",
9
- "build": "tsc -b && vite build",
10
- "preview": "vite preview --host 0.0.0.0 --port 4400",
11
- "ui:parity:init": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/init_frontend_parity.sh ../.. admin",
12
- "ui:parity:bootstrap": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh ../.. admin",
13
- "ui:parity:scaffold": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh scaffold ../.. admin",
14
- "ui:parity:materialize-references": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh materialize_references ../.. admin",
15
- "ui:parity:route-gap": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh route_gap ../.. admin",
16
- "ui:parity:proof": "bash ../../sdd/99_toolchain/01_automation/agentic-dev/run_frontend_target.sh proof ../.. admin"
17
- },
18
- "dependencies": {
19
- "class-variance-authority": "^0.7.1",
20
- "clsx": "^2.1.1",
21
- "lucide-react": "^0.576.0",
22
- "react": "^18.3.1",
23
- "react-dom": "^18.3.1",
24
- "react-router-dom": "^6.30.1",
25
- "tailwind-merge": "^3.5.0"
26
- },
27
- "devDependencies": {
28
- "@playwright/test": "^1.58.2",
29
- "@types/react": "^18.3.18",
30
- "@types/react-dom": "^18.3.5",
31
- "@vitejs/plugin-react": "^4.7.0",
32
- "autoprefixer": "^10.4.21",
33
- "pixelmatch": "^7.1.0",
34
- "pngjs": "^7.0.0",
35
- "postcss": "^8.5.3",
36
- "tailwindcss": "^3.4.17",
37
- "typescript": "^5.8.3",
38
- "vite": "^5.4.19",
39
- "yaml": "^2.8.1"
40
- }
41
- }
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- };
@@ -1,65 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- const scriptDir = path.dirname(fileURLToPath(import.meta.url));
6
- const screens = JSON.parse(
7
- fs.readFileSync(path.resolve(scriptDir, "../src/lib/specScreens.json"), "utf8"),
8
- );
9
- const routes = JSON.parse(
10
- fs.readFileSync(path.resolve(scriptDir, "../src/lib/specRouteCatalog.json"), "utf8"),
11
- );
12
-
13
- const routeMap = new Map(routes.map((entry) => [entry.id, entry.route]));
14
-
15
- export default {
16
- service: "templates-admin",
17
- targetBaseUrl: "http://127.0.0.1:4400",
18
- viewport: {
19
- width: 1440,
20
- height: 1024,
21
- },
22
- screens: screens.map((screen) => ({
23
- id: screen.id,
24
- title: screen.title,
25
- route: routeMap.get(screen.id) ?? "/",
26
- referenceImage: `sdd/03_verify/10_test/ui_parity/reference/${screen.id}.png`,
27
- readySelector: "body",
28
- readyTimeoutMs: 10000,
29
- tags: ["template", "admin"],
30
- })),
31
- async preparePage(page, { route }) {
32
- await page.route("**/auth/me", async (routeRequest) => {
33
- await routeRequest.fulfill({
34
- status: 200,
35
- contentType: "application/json",
36
- body: JSON.stringify({
37
- id: "tmpl-admin",
38
- name: "Template Admin",
39
- email: "admin@example.com",
40
- role: "admin",
41
- }),
42
- });
43
- });
44
- await page.addInitScript(() => {
45
- window.localStorage.setItem(
46
- "admin.auth.token",
47
- JSON.stringify({
48
- access_token: "template-access-token",
49
- token_type: "bearer",
50
- }),
51
- );
52
- });
53
- if (route === "/login") {
54
- await page.addInitScript(() => {
55
- window.localStorage.removeItem("admin.auth.token");
56
- });
57
- }
58
- },
59
- async waitForReady(page) {
60
- await page.waitForLoadState("networkidle");
61
- },
62
- async resolveMaskRects() {
63
- return [];
64
- },
65
- };
@@ -1,33 +0,0 @@
1
- import { apiGet, apiPost } from "@/api/client";
2
-
3
- export interface AlertItem {
4
- id: string;
5
- source: string;
6
- title: string;
7
- message: string;
8
- tone: string;
9
- created_at: string;
10
- read: boolean;
11
- }
12
-
13
- export interface AlertsPayload {
14
- unread_count: number;
15
- items: AlertItem[];
16
- }
17
-
18
- export interface AlertsReadAllResult {
19
- updated_count: number;
20
- unread_count: number;
21
- }
22
-
23
- export function fetchAlerts(accessToken: string) {
24
- return apiGet<AlertsPayload>("/alerts", { accessToken });
25
- }
26
-
27
- export function markAlertRead(alertId: string, accessToken: string) {
28
- return apiPost<AlertItem>(`/alerts/${alertId}/read`, { accessToken });
29
- }
30
-
31
- export function markAllAlertsRead(accessToken: string) {
32
- return apiPost<AlertsReadAllResult>("/alerts/read-all", { accessToken });
33
- }
@@ -1,71 +0,0 @@
1
- const API_BASE_URL =
2
- (import.meta.env.VITE_API_BASE_URL as string | undefined)?.replace(/\/$/, "") ??
3
- "";
4
-
5
- interface RequestOptions {
6
- accessToken?: string;
7
- }
8
-
9
- interface WriteOptions extends RequestOptions {
10
- body?: unknown;
11
- }
12
-
13
- async function readJson<T>(response: Response): Promise<T> {
14
- if (!response.ok) {
15
- let message = "Request failed";
16
- try {
17
- const data = (await response.json()) as { detail?: string };
18
- if (typeof data.detail === "string" && data.detail.length > 0) {
19
- message = data.detail;
20
- }
21
- } catch {
22
- message = response.statusText || message;
23
- }
24
- throw new Error(message);
25
- }
26
-
27
- return (await response.json()) as T;
28
- }
29
-
30
- export async function apiGet<T>(
31
- path: string,
32
- options?: RequestOptions,
33
- ): Promise<T> {
34
- const response = await fetch(`${API_BASE_URL}${path}`, {
35
- headers: options?.accessToken
36
- ? { Authorization: `Bearer ${options.accessToken}` }
37
- : undefined,
38
- });
39
-
40
- return readJson<T>(response);
41
- }
42
-
43
- async function writeJson<T>(
44
- method: "POST" | "PATCH",
45
- path: string,
46
- options?: WriteOptions,
47
- ): Promise<T> {
48
- const headers: Record<string, string> = {
49
- "Content-Type": "application/json",
50
- };
51
-
52
- if (options?.accessToken) {
53
- headers.Authorization = `Bearer ${options.accessToken}`;
54
- }
55
-
56
- const response = await fetch(`${API_BASE_URL}${path}`, {
57
- method,
58
- headers,
59
- body: JSON.stringify(options?.body ?? {}),
60
- });
61
-
62
- return readJson<T>(response);
63
- }
64
-
65
- export function apiPost<T>(path: string, options?: WriteOptions): Promise<T> {
66
- return writeJson("POST", path, options);
67
- }
68
-
69
- export function apiPatch<T>(path: string, options?: WriteOptions): Promise<T> {
70
- return writeJson("PATCH", path, options);
71
- }
@@ -1,33 +0,0 @@
1
- import { apiGet } from "@/api/client";
2
-
3
- export interface DashboardCard {
4
- label: string;
5
- value: string;
6
- tone?: string | null;
7
- }
8
-
9
- export interface StageStatus {
10
- label: string;
11
- value: string;
12
- }
13
-
14
- export interface AdminOverviewResponse {
15
- cards: DashboardCard[];
16
- stage_statuses: StageStatus[];
17
- }
18
-
19
- export interface AdminQueueItem {
20
- order_id: string;
21
- product_name: string;
22
- customer_name: string;
23
- status: string;
24
- sla: string;
25
- }
26
-
27
- export function fetchAdminOverview(accessToken: string) {
28
- return apiGet<AdminOverviewResponse>("/orders/admin/overview", { accessToken });
29
- }
30
-
31
- export function fetchAdminQueue(accessToken: string) {
32
- return apiGet<AdminQueueItem[]>("/orders/admin/queue", { accessToken });
33
- }
@@ -1,11 +0,0 @@
1
- import { apiGet } from "@/api/client";
2
-
3
- export interface SupportFaq {
4
- id: string;
5
- question: string;
6
- visibility: string;
7
- }
8
-
9
- export function fetchSupportFaqs(accessToken: string) {
10
- return apiGet<SupportFaq[]>("/support/faqs", { accessToken });
11
- }
@@ -1,23 +0,0 @@
1
- import { Route, Routes } from "react-router-dom";
2
-
3
- import { ProtectedRoute } from "@/auth/ProtectedRoute";
4
- import { AdminShell } from "@/components/AdminShell";
5
- import { AdminDashboardPage } from "@/pages/AdminDashboardPage";
6
- import { AdminLoginPage } from "@/pages/AdminLoginPage";
7
- import { AdminQueuePage } from "@/pages/AdminQueuePage";
8
- import { AdminSupportPage } from "@/pages/AdminSupportPage";
9
-
10
- export function App() {
11
- return (
12
- <Routes>
13
- <Route path="/login" element={<AdminLoginPage />} />
14
- <Route element={<ProtectedRoute />}>
15
- <Route element={<AdminShell />}>
16
- <Route path="/" element={<AdminDashboardPage />} />
17
- <Route path="/queue" element={<AdminQueuePage />} />
18
- <Route path="/support" element={<AdminSupportPage />} />
19
- </Route>
20
- </Route>
21
- </Routes>
22
- );
23
- }
@@ -1,122 +0,0 @@
1
- import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
2
-
3
- import { getMe, login as loginRequest } from "@/auth/auth-client";
4
- import type { AuthToken, AuthUser, LoginCommand } from "@/auth/types";
5
-
6
- const STORAGE_KEY = "admin.auth.token";
7
-
8
- interface AuthContextValue {
9
- user: AuthUser | null;
10
- token: AuthToken | null;
11
- initializing: boolean;
12
- authenticating: boolean;
13
- login: (command: LoginCommand) => Promise<void>;
14
- logout: () => void;
15
- }
16
-
17
- const AuthContext = createContext<AuthContextValue | undefined>(undefined);
18
-
19
- function readStoredToken(): AuthToken | null {
20
- const raw = window.localStorage.getItem(STORAGE_KEY);
21
- if (!raw) {
22
- return null;
23
- }
24
-
25
- try {
26
- return JSON.parse(raw) as AuthToken;
27
- } catch {
28
- window.localStorage.removeItem(STORAGE_KEY);
29
- return null;
30
- }
31
- }
32
-
33
- function storeToken(token: AuthToken | null) {
34
- if (token) {
35
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(token));
36
- return;
37
- }
38
-
39
- window.localStorage.removeItem(STORAGE_KEY);
40
- }
41
-
42
- export function AuthProvider({ children }: { children: ReactNode }) {
43
- const [token, setToken] = useState<AuthToken | null>(() => readStoredToken());
44
- const [user, setUser] = useState<AuthUser | null>(null);
45
- const [initializing, setInitializing] = useState(true);
46
- const [authenticating, setAuthenticating] = useState(false);
47
-
48
- useEffect(() => {
49
- let cancelled = false;
50
-
51
- async function bootstrap() {
52
- if (!token) {
53
- setUser(null);
54
- setInitializing(false);
55
- return;
56
- }
57
-
58
- try {
59
- const currentUser = await getMe(token.access_token);
60
- if (!cancelled) {
61
- setUser(currentUser);
62
- }
63
- } catch {
64
- if (!cancelled) {
65
- setToken(null);
66
- setUser(null);
67
- storeToken(null);
68
- }
69
- } finally {
70
- if (!cancelled) {
71
- setInitializing(false);
72
- }
73
- }
74
- }
75
-
76
- void bootstrap();
77
-
78
- return () => {
79
- cancelled = true;
80
- };
81
- }, [token]);
82
-
83
- const value = useMemo<AuthContextValue>(
84
- () => ({
85
- user,
86
- token,
87
- initializing,
88
- authenticating,
89
- async login(command) {
90
- setAuthenticating(true);
91
- try {
92
- const nextToken = await loginRequest(command);
93
- storeToken(nextToken);
94
- setToken(nextToken);
95
- const currentUser = await getMe(nextToken.access_token);
96
- setUser(currentUser);
97
- } finally {
98
- setAuthenticating(false);
99
- setInitializing(false);
100
- }
101
- },
102
- logout() {
103
- storeToken(null);
104
- setToken(null);
105
- setUser(null);
106
- setInitializing(false);
107
- },
108
- }),
109
- [authenticating, initializing, token, user],
110
- );
111
-
112
- return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
113
- }
114
-
115
- export function useAuth() {
116
- const context = useContext(AuthContext);
117
- if (!context) {
118
- throw new Error("useAuth must be used within an AuthProvider");
119
- }
120
-
121
- return context;
122
- }