@askrjs/cli 0.0.2 → 0.0.4

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 (310) hide show
  1. package/README.md +46 -7
  2. package/dist/add.d.ts +16 -0
  3. package/dist/add.js +558 -1
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +43 -16
  6. package/dist/create.d.ts +5 -0
  7. package/dist/create.js +104 -26
  8. package/dist/directory-swap-DWoHtx7C.js +35 -0
  9. package/dist/discovery-Difb7Y4G.js +323 -0
  10. package/dist/generate.d.ts +5 -0
  11. package/dist/generate.js +461 -0
  12. package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
  13. package/dist/openapi.d.ts +25 -0
  14. package/dist/openapi.js +49 -16
  15. package/dist/planner-VAj7qlxr.js +285 -0
  16. package/dist/range-YUs9eimn.js +125 -0
  17. package/dist/registry-CyrRHRG5.js +209 -0
  18. package/dist/skills/askr-dashboard-charts/SKILL.md +61 -44
  19. package/dist/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
  20. package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
  21. package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
  22. package/dist/skills.d.ts +18 -0
  23. package/dist/skills.js +1 -1
  24. package/dist/specification-DXnDOC-0.js +49 -0
  25. package/dist/ssg-config.d.ts +41 -0
  26. package/dist/ssg-config.js +1 -0
  27. package/dist/ssg.d.ts +61 -0
  28. package/dist/ssg.js +360 -24
  29. package/dist/templates/full-stack/AGENTS.md +0 -1
  30. package/dist/templates/full-stack/README.md +0 -1
  31. package/dist/templates/full-stack/index.html +0 -1
  32. package/dist/templates/full-stack/package.json +5 -3
  33. package/dist/templates/full-stack/server.ts +5 -9
  34. package/dist/templates/full-stack/src/action-authorizations.ts +2 -2
  35. package/dist/templates/full-stack/src/actions/create-message.ts +5 -5
  36. package/dist/templates/full-stack/src/i18n.ts +4 -4
  37. package/dist/templates/full-stack/src/main.tsx +4 -5
  38. package/dist/templates/full-stack/src/pages/home.tsx +5 -5
  39. package/dist/templates/full-stack/src/pages/layout.tsx +15 -5
  40. package/dist/templates/full-stack/src/pages/not-found.tsx +5 -2
  41. package/dist/templates/full-stack/src/routes.tsx +11 -12
  42. package/dist/templates/full-stack/src/schemas.ts +1 -2
  43. package/dist/templates/full-stack/src/server/action-registry.ts +5 -10
  44. package/dist/templates/full-stack/src/server/actions/create-message.ts +4 -4
  45. package/dist/templates/full-stack/src/server/app.ts +67 -57
  46. package/dist/templates/full-stack/src/server/dependencies.ts +10 -10
  47. package/dist/templates/full-stack/src/server/entry-server.ts +3 -3
  48. package/dist/templates/full-stack/src/telemetry.ts +1 -2
  49. package/dist/templates/full-stack/tests/actions/create-message.test.ts +7 -8
  50. package/dist/templates/full-stack/tsconfig.json +1 -2
  51. package/dist/templates/full-stack/vite.config.ts +5 -6
  52. package/dist/templates/spa/AGENTS.md +1 -1
  53. package/dist/templates/spa/package.json +3 -4
  54. package/dist/templates/spa/src/adapters/operations-client.ts +7 -2
  55. package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
  56. package/dist/templates/spa/src/pages/app/admin-home.tsx +21 -3
  57. package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
  58. package/dist/templates/spa/src/styles.css +1 -1
  59. package/dist/templates/spa/tsconfig.json +2 -1
  60. package/dist/templates/spa/vitest.config.ts +0 -4
  61. package/dist/templates/ssg/README.md +1 -1
  62. package/dist/templates/ssg/package.json +1 -1
  63. package/dist/templates/ssg/ssg.config.ts +7 -0
  64. package/dist/templates/ssg/tests/ssg-config.test.ts +5 -3
  65. package/dist/templates/ssg/tsconfig.json +2 -1
  66. package/dist/templates/ssg/vitest.config.ts +0 -4
  67. package/dist/templates/ssr/package.json +2 -2
  68. package/dist/templates/ssr/server.ts +4 -10
  69. package/dist/templates/ssr/src/entry-server.tsx +6 -4
  70. package/dist/templates/startkit/package.json +2 -2
  71. package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
  72. package/dist/templates/startkit/tsconfig.json +2 -1
  73. package/dist/update.d.ts +41 -0
  74. package/dist/update.js +282 -2
  75. package/dist/writer-D8qe_7ud.js +226 -0
  76. package/package.json +23 -22
  77. package/dist/add-DqhqRzBQ.js +0 -555
  78. package/dist/add-DqhqRzBQ.js.map +0 -1
  79. package/dist/cli.js.map +0 -1
  80. package/dist/create.js.map +0 -1
  81. package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
  82. package/dist/openapi.js.map +0 -1
  83. package/dist/skills-Bh0mEhIx.js.map +0 -1
  84. package/dist/ssg.js.map +0 -1
  85. package/dist/templates/full-stack/src/vite-server.d.ts +0 -6
  86. package/dist/templates/spa/src/styles.d.ts +0 -1
  87. package/dist/templates/ssg/src/vite-env.d.ts +0 -5
  88. package/dist/templates/ssr/src/vite-server.d.ts +0 -7
  89. package/dist/templates/startkit/src/vite-env.d.ts +0 -5
  90. package/dist/update-DyW1na5V.js +0 -1140
  91. package/dist/update-DyW1na5V.js.map +0 -1
  92. package/skills/askr-accessibility/SKILL.md +0 -68
  93. package/skills/askr-accessibility/agents/openai.yaml +0 -4
  94. package/skills/askr-agent-execution/SKILL.md +0 -85
  95. package/skills/askr-agent-execution/agents/openai.yaml +0 -4
  96. package/skills/askr-agent-workflows/SKILL.md +0 -57
  97. package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
  98. package/skills/askr-api-integration/SKILL.md +0 -79
  99. package/skills/askr-api-integration/agents/openai.yaml +0 -4
  100. package/skills/askr-app-builder/SKILL.md +0 -99
  101. package/skills/askr-app-builder/agents/openai.yaml +0 -4
  102. package/skills/askr-auth-access/SKILL.md +0 -74
  103. package/skills/askr-auth-access/agents/openai.yaml +0 -4
  104. package/skills/askr-cli-vite/SKILL.md +0 -76
  105. package/skills/askr-cli-vite/agents/openai.yaml +0 -4
  106. package/skills/askr-dashboard-charts/SKILL.md +0 -82
  107. package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
  108. package/skills/askr-design-system/SKILL.md +0 -86
  109. package/skills/askr-design-system/agents/openai.yaml +0 -4
  110. package/skills/askr-env-config/SKILL.md +0 -74
  111. package/skills/askr-env-config/agents/openai.yaml +0 -4
  112. package/skills/askr-error-loading-empty/SKILL.md +0 -89
  113. package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
  114. package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
  115. package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
  116. package/skills/askr-forms-tables-crud/SKILL.md +0 -98
  117. package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
  118. package/skills/askr-mental-model/SKILL.md +0 -109
  119. package/skills/askr-mental-model/agents/openai.yaml +0 -4
  120. package/skills/askr-migration-react/SKILL.md +0 -81
  121. package/skills/askr-migration-react/agents/openai.yaml +0 -4
  122. package/skills/askr-observability-debugging/SKILL.md +0 -83
  123. package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
  124. package/skills/askr-project-structure/SKILL.md +0 -79
  125. package/skills/askr-project-structure/agents/openai.yaml +0 -4
  126. package/skills/askr-query-mutation/SKILL.md +0 -115
  127. package/skills/askr-query-mutation/agents/openai.yaml +0 -4
  128. package/skills/askr-realtime-streaming/SKILL.md +0 -76
  129. package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
  130. package/skills/askr-resources-data/SKILL.md +0 -100
  131. package/skills/askr-resources-data/agents/openai.yaml +0 -4
  132. package/skills/askr-routing-layouts/SKILL.md +0 -107
  133. package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
  134. package/skills/askr-runtime-reactivity/SKILL.md +0 -92
  135. package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
  136. package/skills/askr-ssr-ssg/SKILL.md +0 -76
  137. package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
  138. package/skills/askr-testing-determinism/SKILL.md +0 -75
  139. package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
  140. package/skills/askr-theming/SKILL.md +0 -86
  141. package/skills/askr-theming/agents/openai.yaml +0 -4
  142. package/skills/askr-ui-composition/SKILL.md +0 -92
  143. package/skills/askr-ui-composition/agents/openai.yaml +0 -4
  144. package/templates/full-stack/AGENTS.md +0 -12
  145. package/templates/full-stack/README.md +0 -18
  146. package/templates/full-stack/gitignore.template +0 -4
  147. package/templates/full-stack/index.html +0 -14
  148. package/templates/full-stack/package.json +0 -37
  149. package/templates/full-stack/server.ts +0 -13
  150. package/templates/full-stack/src/action-authorizations.ts +0 -10
  151. package/templates/full-stack/src/actions/create-message.ts +0 -10
  152. package/templates/full-stack/src/i18n.ts +0 -8
  153. package/templates/full-stack/src/main.tsx +0 -12
  154. package/templates/full-stack/src/pages/home.tsx +0 -25
  155. package/templates/full-stack/src/pages/layout.tsx +0 -33
  156. package/templates/full-stack/src/pages/not-found.tsx +0 -4
  157. package/templates/full-stack/src/routes.tsx +0 -20
  158. package/templates/full-stack/src/schemas.ts +0 -11
  159. package/templates/full-stack/src/server/action-registry.ts +0 -12
  160. package/templates/full-stack/src/server/actions/create-message.ts +0 -14
  161. package/templates/full-stack/src/server/app.ts +0 -66
  162. package/templates/full-stack/src/server/dependencies.ts +0 -55
  163. package/templates/full-stack/src/server/entry-server.ts +0 -8
  164. package/templates/full-stack/src/telemetry.ts +0 -4
  165. package/templates/full-stack/src/vite-server.d.ts +0 -6
  166. package/templates/full-stack/tests/actions/create-message.test.ts +0 -13
  167. package/templates/full-stack/tsconfig.json +0 -16
  168. package/templates/full-stack/vite.config.ts +0 -11
  169. package/templates/spa/AGENTS.md +0 -60
  170. package/templates/spa/README.md +0 -96
  171. package/templates/spa/gitignore.template +0 -16
  172. package/templates/spa/index.html +0 -13
  173. package/templates/spa/package.json +0 -35
  174. package/templates/spa/src/adapters/operations-client.ts +0 -90
  175. package/templates/spa/src/components/shared/metric-card.tsx +0 -27
  176. package/templates/spa/src/components/shared/status-badge.tsx +0 -24
  177. package/templates/spa/src/features/operations/operations.query.ts +0 -9
  178. package/templates/spa/src/main.tsx +0 -10
  179. package/templates/spa/src/pages/_layout.tsx +0 -9
  180. package/templates/spa/src/pages/_routes.tsx +0 -27
  181. package/templates/spa/src/pages/app/_layout.tsx +0 -94
  182. package/templates/spa/src/pages/app/_routes.tsx +0 -10
  183. package/templates/spa/src/pages/app/admin-home.tsx +0 -152
  184. package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
  185. package/templates/spa/src/pages/app/settings.tsx +0 -91
  186. package/templates/spa/src/pages/auth/_layout.tsx +0 -38
  187. package/templates/spa/src/pages/auth/_routes.tsx +0 -6
  188. package/templates/spa/src/pages/auth/login.tsx +0 -63
  189. package/templates/spa/src/pages/not-found.tsx +0 -22
  190. package/templates/spa/src/pages/public/_layout.tsx +0 -47
  191. package/templates/spa/src/pages/public/_routes.tsx +0 -6
  192. package/templates/spa/src/pages/public/home.tsx +0 -143
  193. package/templates/spa/src/shared/format.ts +0 -12
  194. package/templates/spa/src/shared/navigation.ts +0 -15
  195. package/templates/spa/src/styles/components.css +0 -49
  196. package/templates/spa/src/styles/layout.css +0 -192
  197. package/templates/spa/src/styles/reset.css +0 -44
  198. package/templates/spa/src/styles/theme.css +0 -57
  199. package/templates/spa/src/styles/tokens.css +0 -20
  200. package/templates/spa/src/styles.css +0 -7
  201. package/templates/spa/src/styles.d.ts +0 -1
  202. package/templates/spa/tests/app.test.tsx +0 -37
  203. package/templates/spa/tests/components/shared.test.tsx +0 -12
  204. package/templates/spa/tests/resources.test.ts +0 -22
  205. package/templates/spa/tsconfig.json +0 -20
  206. package/templates/spa/tsconfig.node.json +0 -10
  207. package/templates/spa/vite.config.ts +0 -24
  208. package/templates/spa/vitest.config.ts +0 -17
  209. package/templates/ssg/AGENTS.md +0 -55
  210. package/templates/ssg/README.md +0 -39
  211. package/templates/ssg/gitignore.template +0 -17
  212. package/templates/ssg/index.html +0 -13
  213. package/templates/ssg/package.json +0 -35
  214. package/templates/ssg/src/app.tsx +0 -14
  215. package/templates/ssg/src/components/badge.tsx +0 -3
  216. package/templates/ssg/src/components/counter.tsx +0 -30
  217. package/templates/ssg/src/components/site-shell.tsx +0 -111
  218. package/templates/ssg/src/jsx.d.ts +0 -23
  219. package/templates/ssg/src/main.tsx +0 -8
  220. package/templates/ssg/src/pages/about.tsx +0 -82
  221. package/templates/ssg/src/pages/content.tsx +0 -63
  222. package/templates/ssg/src/pages/example.tsx +0 -97
  223. package/templates/ssg/src/pages/home.tsx +0 -51
  224. package/templates/ssg/src/resources/user.ts +0 -15
  225. package/templates/ssg/src/routes.tsx +0 -15
  226. package/templates/ssg/src/styles.css +0 -89
  227. package/templates/ssg/src/vite-env.d.ts +0 -5
  228. package/templates/ssg/ssg.config.ts +0 -34
  229. package/templates/ssg/tests/app.test.tsx +0 -19
  230. package/templates/ssg/tests/components/counter.test.tsx +0 -18
  231. package/templates/ssg/tests/resources.test.ts +0 -11
  232. package/templates/ssg/tests/ssg-config.test.ts +0 -11
  233. package/templates/ssg/tsconfig.json +0 -20
  234. package/templates/ssg/tsconfig.node.json +0 -10
  235. package/templates/ssg/vite.config.ts +0 -24
  236. package/templates/ssg/vitest.config.ts +0 -17
  237. package/templates/ssr/AGENTS.md +0 -28
  238. package/templates/ssr/README.md +0 -38
  239. package/templates/ssr/gitignore.template +0 -16
  240. package/templates/ssr/index.html +0 -13
  241. package/templates/ssr/package.json +0 -34
  242. package/templates/ssr/server.ts +0 -16
  243. package/templates/ssr/src/app.tsx +0 -21
  244. package/templates/ssr/src/components/counter.tsx +0 -26
  245. package/templates/ssr/src/entry-server.tsx +0 -10
  246. package/templates/ssr/src/main.tsx +0 -11
  247. package/templates/ssr/src/pages/about.tsx +0 -75
  248. package/templates/ssr/src/pages/example.tsx +0 -113
  249. package/templates/ssr/src/pages/home.tsx +0 -56
  250. package/templates/ssr/src/resources/user.ts +0 -15
  251. package/templates/ssr/src/routes.tsx +0 -13
  252. package/templates/ssr/src/styles.css +0 -148
  253. package/templates/ssr/src/vite-server.d.ts +0 -7
  254. package/templates/ssr/tests/app.test.tsx +0 -24
  255. package/templates/ssr/tests/components/counter.test.tsx +0 -13
  256. package/templates/ssr/tests/resources.test.ts +0 -11
  257. package/templates/ssr/tsconfig.json +0 -22
  258. package/templates/ssr/tsconfig.node.json +0 -10
  259. package/templates/ssr/tsconfig.server.json +0 -15
  260. package/templates/ssr/vite.config.ts +0 -25
  261. package/templates/ssr/vitest.config.ts +0 -13
  262. package/templates/startkit/AGENTS.md +0 -77
  263. package/templates/startkit/README.md +0 -192
  264. package/templates/startkit/gitignore.template +0 -16
  265. package/templates/startkit/index.html +0 -13
  266. package/templates/startkit/package.json +0 -35
  267. package/templates/startkit/src/components/app-header.tsx +0 -93
  268. package/templates/startkit/src/components/app-sidebar.tsx +0 -95
  269. package/templates/startkit/src/components/data-table.tsx +0 -80
  270. package/templates/startkit/src/components/empty-state.tsx +0 -13
  271. package/templates/startkit/src/components/page-header.tsx +0 -23
  272. package/templates/startkit/src/components/stat-card.tsx +0 -24
  273. package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
  274. package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
  275. package/templates/startkit/src/lib/format.ts +0 -31
  276. package/templates/startkit/src/lib/mock-data.ts +0 -441
  277. package/templates/startkit/src/lib/routes.ts +0 -116
  278. package/templates/startkit/src/main.tsx +0 -12
  279. package/templates/startkit/src/pages/_layout.tsx +0 -56
  280. package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
  281. package/templates/startkit/src/pages/auth/login.tsx +0 -129
  282. package/templates/startkit/src/pages/home.tsx +0 -83
  283. package/templates/startkit/src/pages/not-found.tsx +0 -24
  284. package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
  285. package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
  286. package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
  287. package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
  288. package/templates/startkit/src/router.tsx +0 -7
  289. package/templates/startkit/src/routes/auth-config.ts +0 -38
  290. package/templates/startkit/src/routes/auth.ts +0 -8
  291. package/templates/startkit/src/routes/index.ts +0 -28
  292. package/templates/startkit/src/routes/public.ts +0 -8
  293. package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
  294. package/templates/startkit/src/routes/workspace/index.ts +0 -14
  295. package/templates/startkit/src/styles/components.css +0 -396
  296. package/templates/startkit/src/styles/layout.css +0 -192
  297. package/templates/startkit/src/styles/reset.css +0 -38
  298. package/templates/startkit/src/styles/theme.css +0 -76
  299. package/templates/startkit/src/styles/tokens.css +0 -67
  300. package/templates/startkit/src/styles.css +0 -7
  301. package/templates/startkit/src/toast.ts +0 -55
  302. package/templates/startkit/src/utils/join-classes.ts +0 -4
  303. package/templates/startkit/src/vite-env.d.ts +0 -5
  304. package/templates/startkit/tests/app.test.tsx +0 -32
  305. package/templates/startkit/tests/preferences.test.ts +0 -43
  306. package/templates/startkit/tests/resources.test.ts +0 -82
  307. package/templates/startkit/tsconfig.json +0 -20
  308. package/templates/startkit/tsconfig.node.json +0 -10
  309. package/templates/startkit/vite.config.ts +0 -32
  310. package/templates/startkit/vitest.config.ts +0 -13
@@ -6,7 +6,7 @@
6
6
  "dev": "vp dev",
7
7
  "build": "vp build",
8
8
  "preview": "vp preview",
9
- "test": "vp test run",
9
+ "test": "vp test run -c ./vitest.config.ts",
10
10
  "test:watch": "vp test --watch",
11
11
  "typecheck": "tsc --noEmit",
12
12
  "lint": "vp lint .",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "@askrjs/vite": ">=0.0.6 <0.1.0",
27
- "@types/node": "^26.0.0",
27
+ "@types/node": "^20.19.0",
28
28
  "jsdom": "^29.1.1",
29
29
  "typescript": "^6.0.3",
30
30
  "vite-plus": "^0.2.4"
@@ -173,43 +173,32 @@ function wait(signal?: AbortSignal, delay = 220): Promise<void> {
173
173
  });
174
174
  }
175
175
 
176
- function readStorage(key: string): string | null {
177
- const fallback = storageFallback.get(key) ?? null;
178
-
179
- if (typeof window === 'undefined') {
180
- return fallback;
176
+ function browserStorage(): Storage | undefined {
177
+ const globalDescriptor = Object.getOwnPropertyDescriptor(
178
+ globalThis,
179
+ 'localStorage'
180
+ );
181
+ if (globalDescriptor?.get && globalDescriptor.enumerable === false) {
182
+ return undefined;
181
183
  }
182
-
184
+ if (typeof document === 'undefined') return undefined;
183
185
  try {
184
- const storage = window.localStorage as {
185
- getItem?: (storageKey: string) => string | null;
186
- };
187
- if (typeof storage.getItem !== 'function') {
188
- return fallback;
189
- }
190
-
191
- return storage.getItem(key) ?? fallback;
186
+ return document.defaultView?.localStorage;
192
187
  } catch {
193
- return fallback;
188
+ return undefined;
194
189
  }
195
190
  }
196
191
 
192
+ function readStorage(key: string): string | null {
193
+ const fallback = storageFallback.get(key) ?? null;
194
+ return browserStorage()?.getItem(key) ?? fallback;
195
+ }
196
+
197
197
  function writeStorage(key: string, value: string) {
198
198
  storageFallback.set(key, value);
199
199
 
200
- if (typeof window === 'undefined') {
201
- return;
202
- }
203
-
204
200
  try {
205
- const storage = window.localStorage as {
206
- setItem?: (storageKey: string, storageValue: string) => void;
207
- };
208
- if (typeof storage.setItem !== 'function') {
209
- return;
210
- }
211
-
212
- storage.setItem(key, value);
201
+ browserStorage()?.setItem(key, value);
213
202
  } catch {
214
203
  // Ignore storage write failures in non-browser or restricted test envs.
215
204
  }
@@ -218,19 +207,8 @@ function writeStorage(key: string, value: string) {
218
207
  function removeStorage(key: string) {
219
208
  storageFallback.delete(key);
220
209
 
221
- if (typeof window === 'undefined') {
222
- return;
223
- }
224
-
225
210
  try {
226
- const storage = window.localStorage as {
227
- removeItem?: (storageKey: string) => void;
228
- };
229
- if (typeof storage.removeItem !== 'function') {
230
- return;
231
- }
232
-
233
- storage.removeItem(key);
211
+ browserStorage()?.removeItem(key);
234
212
  } catch {
235
213
  // Ignore storage delete failures in non-browser or restricted test envs.
236
214
  }
@@ -13,7 +13,8 @@
13
13
  "isolatedModules": true,
14
14
  "noEmit": true,
15
15
  "jsx": "preserve",
16
- "jsxImportSource": "@askrjs/askr"
16
+ "jsxImportSource": "@askrjs/askr",
17
+ "types": ["@askrjs/themes"]
17
18
  },
18
19
  "include": ["src"],
19
20
  "references": [{ "path": "./tsconfig.node.json" }]
@@ -0,0 +1,41 @@
1
+ //#region src/update/types.d.ts
2
+ declare const DEPENDENCY_SECTIONS: readonly ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
3
+ type DependencySection = (typeof DEPENDENCY_SECTIONS)[number];
4
+ interface Packument {
5
+ "dist-tags"?: Record<string, unknown>;
6
+ versions?: Record<string, unknown>;
7
+ }
8
+ interface ManifestValueEdit {
9
+ manifestPath: string;
10
+ section: DependencySection;
11
+ package: string;
12
+ currentSpecification: string;
13
+ proposedSpecification: string;
14
+ }
15
+ //#endregion
16
+ //#region src/update/writer.d.ts
17
+ interface WriterOptions {
18
+ replace?: (temporaryPath: string, manifestPath: string) => Promise<void>;
19
+ }
20
+ declare function writeManifestEdits(edits: ManifestValueEdit[], options?: WriterOptions): Promise<number>;
21
+ //#endregion
22
+ //#region src/update/registry.d.ts
23
+ interface RegistryRequirements {
24
+ specifications?: ReadonlyMap<string, readonly string[]>;
25
+ }
26
+ interface PackumentResults {
27
+ packuments: Map<string, Packument>;
28
+ failures: Map<string, string>;
29
+ }
30
+ //#endregion
31
+ //#region src/bin/update.d.ts
32
+ type CliIo = Pick<Console, "error" | "log">;
33
+ interface UpdateRuntime {
34
+ registry?: (root: string, packageNames: string[], requirements?: RegistryRequirements) => Promise<PackumentResults>;
35
+ writer?: typeof writeManifestEdits;
36
+ }
37
+ declare const runUpdateCli: (args: string[], io?: CliIo, runtime?: UpdateRuntime) => Promise<number>;
38
+ declare const runUpgradeCli: (args: string[], io?: CliIo, runtime?: UpdateRuntime) => Promise<number>;
39
+ declare const runOutdatedCli: (args: string[], io?: CliIo, runtime?: UpdateRuntime) => Promise<number>;
40
+ //#endregion
41
+ export { runOutdatedCli, runUpdateCli, runUpgradeCli };
package/dist/update.js CHANGED
@@ -1,3 +1,283 @@
1
1
  #!/usr/bin/env node
2
- import { t as runUpdateCli } from "./update-DyW1na5V.js";
3
- export { runUpdateCli };
2
+ import { t as isDirectExecution } from "./is-direct-execution-Cdlr-ZUl.js";
3
+ import path from "node:path";
4
+ //#region src/bin/update.ts
5
+ function helpText(command) {
6
+ return [
7
+ `askr ${command} - ${command === "outdated" ? "List available dependency updates" : command === "update" ? "Apply safe dependency updates" : "Apply latest peer-compatible dependency upgrades"}`,
8
+ "",
9
+ "Usage:",
10
+ ` askr ${command} [packages...] [options]`,
11
+ "",
12
+ "Options:",
13
+ " --cwd <dir> Resolve a project from another directory",
14
+ " --workspace <glob> Select workspace names (repeatable)",
15
+ " --tag <tag> Use one registry dist-tag for selected packages",
16
+ " --json Emit one deterministic JSON object on stdout",
17
+ " --help, -h Show this help message",
18
+ "",
19
+ "Notes:",
20
+ " Package arguments are minimatch patterns and override persistent ignores.",
21
+ command === "outdated" ? " This command reports only and never writes files." : " The command changes package.json files only.",
22
+ " Lockfiles, installs, and lifecycle scripts are never touched."
23
+ ].join("\n");
24
+ }
25
+ function optionValue(args, index, option, errors) {
26
+ if (index + 1 >= args.length || args[index + 1].startsWith("-")) {
27
+ errors.push(`Missing value for ${option}`);
28
+ return null;
29
+ }
30
+ return args[index + 1];
31
+ }
32
+ function parseArgs(args) {
33
+ const parsed = {
34
+ cwd: process.cwd(),
35
+ help: false,
36
+ json: false,
37
+ packagePatterns: [],
38
+ workspacePatterns: [],
39
+ errors: []
40
+ };
41
+ let positionalOnly = false;
42
+ for (let index = 0; index < args.length; index += 1) {
43
+ const argument = args[index];
44
+ if (positionalOnly) parsed.packagePatterns.push(argument);
45
+ else if (argument === "--") positionalOnly = true;
46
+ else if (argument === "--help" || argument === "-h") parsed.help = true;
47
+ else if (argument === "--json") parsed.json = true;
48
+ else if (argument === "--cwd") {
49
+ const value = optionValue(args, index, "--cwd", parsed.errors);
50
+ if (value !== null) {
51
+ parsed.cwd = path.resolve(value);
52
+ index += 1;
53
+ }
54
+ } else if (argument.startsWith("--cwd=")) parsed.cwd = path.resolve(argument.slice(6));
55
+ else if (argument === "--workspace") {
56
+ const value = optionValue(args, index, "--workspace", parsed.errors);
57
+ if (value !== null) {
58
+ parsed.workspacePatterns.push(value);
59
+ index += 1;
60
+ }
61
+ } else if (argument.startsWith("--workspace=")) parsed.workspacePatterns.push(argument.slice(12));
62
+ else if (argument === "--tag") {
63
+ const value = optionValue(args, index, "--tag", parsed.errors);
64
+ if (value !== null) {
65
+ parsed.tag = value;
66
+ index += 1;
67
+ }
68
+ } else if (argument.startsWith("--tag=")) parsed.tag = argument.slice(6);
69
+ else if (argument.startsWith("-")) parsed.errors.push(`Unknown option: ${argument}`);
70
+ else parsed.packagePatterns.push(argument);
71
+ }
72
+ if (parsed.tag !== void 0 && (!parsed.tag || /\s/.test(parsed.tag))) parsed.errors.push("--tag must be a non-empty dist-tag without whitespace");
73
+ if (parsed.workspacePatterns.some((pattern) => !pattern)) parsed.errors.push("--workspace patterns must not be empty");
74
+ if (parsed.packagePatterns.some((pattern) => !pattern)) parsed.errors.push("Package patterns must not be empty");
75
+ return parsed;
76
+ }
77
+ function emptySummary() {
78
+ return {
79
+ packages: 0,
80
+ occurrences: 0,
81
+ changedOccurrences: 0,
82
+ current: 0,
83
+ safe: 0,
84
+ breaking: 0,
85
+ local: 0,
86
+ manual: 0,
87
+ error: 0
88
+ };
89
+ }
90
+ function serializableDecision(decision) {
91
+ return {
92
+ package: decision.package,
93
+ selectedTag: decision.selectedTag,
94
+ targetVersion: decision.targetVersion,
95
+ status: decision.status,
96
+ reason: decision.reason,
97
+ occurrences: decision.occurrences.map((occurrence) => ({
98
+ workspace: occurrence.workspace,
99
+ manifest: occurrence.relativeManifestPath,
100
+ section: occurrence.section,
101
+ currentSpecification: occurrence.currentSpecification,
102
+ proposedSpecification: occurrence.proposedSpecification,
103
+ allowedVersion: occurrence.allowedVersion,
104
+ status: occurrence.status,
105
+ reason: occurrence.reason
106
+ }))
107
+ };
108
+ }
109
+ function selectedWorkspaceJson(root, workspaces) {
110
+ return workspaces.map((workspace) => ({
111
+ name: workspace.name,
112
+ path: path.relative(root, workspace.directory).split(path.sep).join("/") || ".",
113
+ manifest: workspace.relativeManifestPath
114
+ }));
115
+ }
116
+ function emitJson(io, options) {
117
+ io.log(JSON.stringify({
118
+ root: options.root,
119
+ workspaces: options.workspaces,
120
+ summary: options.summary,
121
+ decisions: options.decisions.map(serializableDecision),
122
+ applied: { occurrences: options.applied },
123
+ errors: options.errors
124
+ }, null, 2));
125
+ }
126
+ function rangeText(occurrence, command) {
127
+ if (occurrence.proposedSpecification) return `${occurrence.currentSpecification} → ${occurrence.proposedSpecification}`;
128
+ if (occurrence.status === "breaking") return command === "upgrade" ? `${occurrence.currentSpecification} (${occurrence.reason})` : `${occurrence.currentSpecification} (available via askr upgrade)`;
129
+ return `${occurrence.currentSpecification} (${occurrence.reason})`;
130
+ }
131
+ function renderTable(rows) {
132
+ const headings = [
133
+ "Package",
134
+ "Allowed",
135
+ "Latest",
136
+ "Status",
137
+ "Range"
138
+ ];
139
+ const widths = headings.map((heading, column) => Math.max(heading.length, ...rows.map((row) => row[column].length)));
140
+ return [headings, ...rows].map((row) => row.map((value, column) => column === row.length - 1 ? value : value.padEnd(widths[column])).join(" "));
141
+ }
142
+ function emitHuman(io, decisions, summary, applied, command) {
143
+ const byWorkspace = /* @__PURE__ */ new Map();
144
+ for (const decision of decisions) for (const occurrence of decision.occurrences) {
145
+ if (occurrence.status === "current") continue;
146
+ const rows = byWorkspace.get(occurrence.workspace) ?? [];
147
+ const row = [
148
+ decision.package,
149
+ occurrence.allowedVersion ?? "-",
150
+ decision.targetVersion ?? "-",
151
+ occurrence.status,
152
+ rangeText(occurrence, command)
153
+ ];
154
+ if (!rows.some((existing) => existing.every((value, index) => value === row[index]))) rows.push(row);
155
+ byWorkspace.set(occurrence.workspace, rows);
156
+ }
157
+ if (byWorkspace.size === 0) io.log("All selected dependencies are current.");
158
+ else {
159
+ let first = true;
160
+ for (const [workspace, rows] of byWorkspace) {
161
+ if (!first) io.log("");
162
+ first = false;
163
+ io.log(workspace);
164
+ for (const line of renderTable(rows)) io.log(line);
165
+ }
166
+ }
167
+ const counts = [
168
+ "safe",
169
+ "breaking",
170
+ "current",
171
+ "manual",
172
+ "local",
173
+ "error"
174
+ ].filter((status) => summary[status] > 0).map((status) => `${summary[status]} ${status}`).join(", ");
175
+ io.log("");
176
+ io.log(`Scanned ${summary.packages} package${summary.packages === 1 ? "" : "s"}${counts ? `: ${counts}` : "."}`);
177
+ if (command !== "outdated") io.log(`Updated ${applied} manifest occurrence${applied === 1 ? "" : "s"}.`);
178
+ }
179
+ function collectEdits(decisions) {
180
+ return decisions.flatMap((decision) => decision.occurrences.flatMap((occurrence) => occurrence.proposedSpecification ? [{
181
+ manifestPath: occurrence.manifestPath,
182
+ section: occurrence.section,
183
+ package: decision.package,
184
+ currentSpecification: occurrence.currentSpecification,
185
+ proposedSpecification: occurrence.proposedSpecification
186
+ }] : []));
187
+ }
188
+ async function defaultRegistry(root, packageNames, requirements) {
189
+ const { fetchPackuments, loadNpmConfiguration } = await import("./registry-CyrRHRG5.js");
190
+ return fetchPackuments(packageNames, await loadNpmConfiguration(root), { requirements });
191
+ }
192
+ async function runDependencyCli(command, args, io = console, runtime = {}) {
193
+ const parsed = parseArgs(args);
194
+ if (parsed.help && parsed.errors.length === 0) {
195
+ io.log(helpText(command));
196
+ return 0;
197
+ }
198
+ if (parsed.errors.length > 0) {
199
+ for (const error of parsed.errors) io.error(`askr ${command}: ${error}`);
200
+ if (parsed.json) emitJson(io, {
201
+ root: null,
202
+ workspaces: [],
203
+ summary: emptySummary(),
204
+ decisions: [],
205
+ applied: 0,
206
+ errors: parsed.errors
207
+ });
208
+ return 1;
209
+ }
210
+ let root = null;
211
+ let selectedWorkspaces = [];
212
+ try {
213
+ const [{ discoverProject }, { planUpdates }] = await Promise.all([import("./discovery-Difb7Y4G.js"), import("./planner-VAj7qlxr.js")]);
214
+ const project = await discoverProject({
215
+ cwd: parsed.cwd,
216
+ packagePatterns: parsed.packagePatterns,
217
+ workspacePatterns: parsed.workspacePatterns
218
+ });
219
+ root = project.root;
220
+ selectedWorkspaces = project.selectedWorkspaces;
221
+ const lookupNames = project.occurrences.some((occurrence) => occurrence.kind === "fetch") ? project.contextOccurrences.filter((occurrence) => occurrence.registryManaged).map((occurrence) => occurrence.package) : [];
222
+ const registry = runtime.registry ?? defaultRegistry;
223
+ const specifications = /* @__PURE__ */ new Map();
224
+ for (const occurrence of project.contextOccurrences) {
225
+ const entries = specifications.get(occurrence.package) ?? [];
226
+ if (!entries.includes(occurrence.currentSpecification)) entries.push(occurrence.currentSpecification);
227
+ specifications.set(occurrence.package, entries);
228
+ }
229
+ const results = lookupNames.length > 0 ? await registry(project.root, lookupNames, { specifications }) : {
230
+ packuments: /* @__PURE__ */ new Map(),
231
+ failures: /* @__PURE__ */ new Map()
232
+ };
233
+ const plan = planUpdates({
234
+ occurrences: project.occurrences,
235
+ contextOccurrences: project.contextOccurrences,
236
+ packuments: results.packuments,
237
+ failures: results.failures,
238
+ tags: project.policy.tags,
239
+ cliTag: parsed.tag,
240
+ force: command === "upgrade"
241
+ });
242
+ let applied = 0;
243
+ const errors = [];
244
+ if (!plan.hasErrors && command !== "outdated") try {
245
+ applied = await (runtime.writer ?? (await import("./writer-D8qe_7ud.js")).writeManifestEdits)(collectEdits(plan.decisions));
246
+ } catch {
247
+ errors.push("Unable to replace package manifests; completed replacements were rolled back when possible.");
248
+ }
249
+ if (plan.hasErrors) errors.push("One or more registry lookups or package plans failed.");
250
+ if (parsed.json) emitJson(io, {
251
+ root: project.root,
252
+ workspaces: selectedWorkspaceJson(project.root, project.selectedWorkspaces),
253
+ summary: plan.summary,
254
+ decisions: plan.decisions,
255
+ applied,
256
+ errors
257
+ });
258
+ else emitHuman(io, plan.decisions, plan.summary, applied, command);
259
+ for (const error of errors) io.error(`askr ${command}: ${error}`);
260
+ return errors.length > 0 ? 1 : 0;
261
+ } catch (error) {
262
+ const message = error instanceof Error ? error.message : "Update failed.";
263
+ io.error(`askr ${command}: ${message}`);
264
+ if (parsed.json) emitJson(io, {
265
+ root,
266
+ workspaces: root ? selectedWorkspaceJson(root, selectedWorkspaces) : [],
267
+ summary: emptySummary(),
268
+ decisions: [],
269
+ applied: 0,
270
+ errors: [message]
271
+ });
272
+ return 1;
273
+ }
274
+ }
275
+ const runUpdateCli = (args, io = console, runtime = {}) => runDependencyCli("update", args, io, runtime);
276
+ const runUpgradeCli = (args, io = console, runtime = {}) => runDependencyCli("upgrade", args, io, runtime);
277
+ const runOutdatedCli = (args, io = console, runtime = {}) => runDependencyCli("outdated", args, io, runtime);
278
+ async function main() {
279
+ process.exit(await runUpdateCli(process.argv.slice(2)));
280
+ }
281
+ if (isDirectExecution(import.meta.url)) main();
282
+ //#endregion
283
+ export { runOutdatedCli, runUpdateCli, runUpgradeCli };
@@ -0,0 +1,226 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ //#region src/update/writer.ts
5
+ function groupEdits(edits) {
6
+ const grouped = /* @__PURE__ */ new Map();
7
+ for (const edit of edits) {
8
+ const entries = grouped.get(edit.manifestPath) ?? [];
9
+ entries.push(edit);
10
+ grouped.set(edit.manifestPath, entries);
11
+ }
12
+ for (const entries of grouped.values()) entries.sort((left, right) => left.section.localeCompare(right.section) || left.package.localeCompare(right.package));
13
+ return new Map([...grouped].sort(([left], [right]) => left.localeCompare(right)));
14
+ }
15
+ var JsonTreeParser = class {
16
+ source;
17
+ index = 0;
18
+ constructor(source) {
19
+ this.source = source;
20
+ if (source.charCodeAt(0) === 65279) this.index = 1;
21
+ }
22
+ parse() {
23
+ const node = this.parseValue();
24
+ this.skipWhitespace();
25
+ if (this.index !== this.source.length) throw new Error("Unexpected content after JSON value");
26
+ return node;
27
+ }
28
+ skipWhitespace() {
29
+ while (/[ \t\r\n]/.test(this.source[this.index] ?? "")) this.index += 1;
30
+ }
31
+ parseValue() {
32
+ this.skipWhitespace();
33
+ const token = this.source[this.index];
34
+ if (token === "{") return this.parseObject();
35
+ if (token === "[") return this.parseArray();
36
+ if (token === "\"") return this.parseString();
37
+ return this.parsePrimitive();
38
+ }
39
+ parseString() {
40
+ const start = this.index;
41
+ this.index += 1;
42
+ while (this.index < this.source.length) {
43
+ const token = this.source[this.index];
44
+ if (token === "\\") {
45
+ this.index += 2;
46
+ continue;
47
+ }
48
+ this.index += 1;
49
+ if (token === "\"") {
50
+ const raw = this.source.slice(start, this.index);
51
+ const value = JSON.parse(raw);
52
+ if (typeof value !== "string") throw new Error("Invalid JSON string");
53
+ return {
54
+ end: this.index,
55
+ kind: "string",
56
+ start,
57
+ value
58
+ };
59
+ }
60
+ }
61
+ throw new Error("Unterminated JSON string");
62
+ }
63
+ parseObject() {
64
+ const start = this.index;
65
+ const properties = /* @__PURE__ */ new Map();
66
+ this.index += 1;
67
+ this.skipWhitespace();
68
+ if (this.source[this.index] === "}") {
69
+ this.index += 1;
70
+ return {
71
+ end: this.index,
72
+ kind: "object",
73
+ properties,
74
+ start
75
+ };
76
+ }
77
+ while (this.index < this.source.length) {
78
+ this.skipWhitespace();
79
+ if (this.source[this.index] !== "\"") throw new Error("Expected a JSON object key");
80
+ const key = this.parseString().value;
81
+ this.skipWhitespace();
82
+ if (this.source[this.index] !== ":") throw new Error("Expected ':' after JSON object key");
83
+ this.index += 1;
84
+ properties.set(key, this.parseValue());
85
+ this.skipWhitespace();
86
+ if (this.source[this.index] === "}") {
87
+ this.index += 1;
88
+ return {
89
+ end: this.index,
90
+ kind: "object",
91
+ properties,
92
+ start
93
+ };
94
+ }
95
+ if (this.source[this.index] !== ",") throw new Error("Expected ',' in JSON object");
96
+ this.index += 1;
97
+ }
98
+ throw new Error("Unterminated JSON object");
99
+ }
100
+ parseArray() {
101
+ const start = this.index;
102
+ this.index += 1;
103
+ this.skipWhitespace();
104
+ if (this.source[this.index] === "]") {
105
+ this.index += 1;
106
+ return {
107
+ end: this.index,
108
+ kind: "array",
109
+ start
110
+ };
111
+ }
112
+ while (this.index < this.source.length) {
113
+ this.parseValue();
114
+ this.skipWhitespace();
115
+ if (this.source[this.index] === "]") {
116
+ this.index += 1;
117
+ return {
118
+ end: this.index,
119
+ kind: "array",
120
+ start
121
+ };
122
+ }
123
+ if (this.source[this.index] !== ",") throw new Error("Expected ',' in JSON array");
124
+ this.index += 1;
125
+ }
126
+ throw new Error("Unterminated JSON array");
127
+ }
128
+ parsePrimitive() {
129
+ const start = this.index;
130
+ while (this.index < this.source.length && !/[ \t\r\n,\]}]/.test(this.source[this.index])) this.index += 1;
131
+ if (start === this.index) throw new Error("Expected a JSON value");
132
+ JSON.parse(this.source.slice(start, this.index));
133
+ return {
134
+ end: this.index,
135
+ kind: "other",
136
+ start
137
+ };
138
+ }
139
+ };
140
+ function renderReplacement(source, edits) {
141
+ let manifest;
142
+ try {
143
+ manifest = new JsonTreeParser(source).parse();
144
+ } catch {
145
+ throw new Error("Manifest changed to invalid JSON before writing.");
146
+ }
147
+ if (manifest.kind !== "object") throw new Error("Manifest changed to invalid JSON before writing.");
148
+ const replacements = [];
149
+ const seen = /* @__PURE__ */ new Set();
150
+ for (const edit of edits) {
151
+ const key = `${edit.section}\u0000${edit.package}`;
152
+ if (seen.has(key)) throw new Error(`Duplicate manifest edit: ${edit.manifestPath}`);
153
+ seen.add(key);
154
+ const current = (manifest.properties?.get(edit.section))?.properties?.get(edit.package);
155
+ if (current?.kind !== "string" || current.value !== edit.currentSpecification) throw new Error(`Manifest changed before writing: ${edit.manifestPath}`);
156
+ replacements.push({
157
+ start: current.start,
158
+ end: current.end,
159
+ value: JSON.stringify(edit.proposedSpecification)
160
+ });
161
+ }
162
+ let result = source;
163
+ replacements.sort((left, right) => right.start - left.start);
164
+ for (const replacement of replacements) result = `${result.slice(0, replacement.start)}${replacement.value}${result.slice(replacement.end)}`;
165
+ return result;
166
+ }
167
+ async function cleanup(paths) {
168
+ await Promise.all(paths.map((filePath) => fs.rm(filePath, { force: true }).catch(() => void 0)));
169
+ }
170
+ async function rollback(replaced) {
171
+ let complete = true;
172
+ for (const staged of [...replaced].reverse()) {
173
+ const rollbackPath = path.join(path.dirname(staged.manifestPath), `.${path.basename(staged.manifestPath)}.askr-rollback-${randomUUID()}`);
174
+ try {
175
+ await fs.writeFile(rollbackPath, staged.original, {
176
+ flag: "wx",
177
+ mode: staged.mode
178
+ });
179
+ await fs.rename(rollbackPath, staged.manifestPath);
180
+ } catch {
181
+ complete = false;
182
+ await fs.rm(rollbackPath, { force: true }).catch(() => void 0);
183
+ }
184
+ }
185
+ return complete;
186
+ }
187
+ async function writeManifestEdits(edits, options = {}) {
188
+ if (edits.length === 0) return 0;
189
+ const staged = [];
190
+ const replace = options.replace ?? fs.rename;
191
+ try {
192
+ for (const [manifestPath, manifestEdits] of groupEdits(edits)) {
193
+ const [original, stat] = await Promise.all([fs.readFile(manifestPath), fs.stat(manifestPath)]);
194
+ const replacement = renderReplacement(original.toString("utf8"), manifestEdits);
195
+ const temporaryPath = path.join(path.dirname(manifestPath), `.${path.basename(manifestPath)}.askr-update-${randomUUID()}`);
196
+ await fs.writeFile(temporaryPath, replacement, {
197
+ flag: "wx",
198
+ mode: stat.mode
199
+ });
200
+ staged.push({
201
+ manifestPath,
202
+ original,
203
+ replacement,
204
+ temporaryPath,
205
+ mode: stat.mode
206
+ });
207
+ }
208
+ } catch (error) {
209
+ await cleanup(staged.map((entry) => entry.temporaryPath));
210
+ throw error;
211
+ }
212
+ const replaced = [];
213
+ try {
214
+ for (const manifest of staged) {
215
+ await replace(manifest.temporaryPath, manifest.manifestPath);
216
+ replaced.push(manifest);
217
+ }
218
+ } catch {
219
+ const rollbackComplete = await rollback(replaced);
220
+ await cleanup(staged.map((entry) => entry.temporaryPath));
221
+ throw new Error(rollbackComplete ? "Manifest replacement failed; completed replacements were rolled back." : "Manifest replacement failed and rollback was incomplete.");
222
+ }
223
+ return edits.length;
224
+ }
225
+ //#endregion
226
+ export { writeManifestEdits };