@askrjs/cli 0.0.3 → 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 (287) hide show
  1. package/README.md +37 -0
  2. package/dist/add.d.ts +16 -0
  3. package/dist/add.js +33 -29
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +0 -2
  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 +0 -2
  10. package/dist/generate.d.ts +5 -0
  11. package/dist/generate.js +77 -12
  12. package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
  13. package/dist/openapi.d.ts +25 -0
  14. package/dist/openapi.js +44 -12
  15. package/dist/planner-VAj7qlxr.js +0 -2
  16. package/dist/range-YUs9eimn.js +0 -2
  17. package/dist/registry-CyrRHRG5.js +0 -2
  18. package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
  19. package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
  20. package/dist/skills.d.ts +18 -0
  21. package/dist/skills.js +1 -1
  22. package/dist/specification-DXnDOC-0.js +0 -2
  23. package/dist/ssg-config.d.ts +41 -0
  24. package/dist/ssg-config.js +1 -0
  25. package/dist/ssg.d.ts +61 -0
  26. package/dist/ssg.js +360 -24
  27. package/dist/templates/full-stack/package.json +1 -1
  28. package/dist/templates/full-stack/src/server/action-registry.ts +0 -1
  29. package/dist/templates/full-stack/tsconfig.json +1 -1
  30. package/dist/templates/spa/package.json +2 -3
  31. package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
  32. package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
  33. package/dist/templates/spa/tsconfig.json +2 -1
  34. package/dist/templates/spa/vitest.config.ts +0 -4
  35. package/dist/templates/ssg/README.md +1 -1
  36. package/dist/templates/ssg/package.json +1 -1
  37. package/dist/templates/ssg/ssg.config.ts +7 -0
  38. package/dist/templates/ssg/tests/ssg-config.test.ts +2 -0
  39. package/dist/templates/ssg/tsconfig.json +2 -1
  40. package/dist/templates/ssg/vitest.config.ts +0 -4
  41. package/dist/templates/ssr/package.json +2 -2
  42. package/dist/templates/startkit/package.json +2 -2
  43. package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
  44. package/dist/templates/startkit/tsconfig.json +2 -1
  45. package/dist/update.d.ts +41 -0
  46. package/dist/update.js +0 -2
  47. package/dist/writer-D8qe_7ud.js +0 -2
  48. package/package.json +13 -8
  49. package/dist/add.js.map +0 -1
  50. package/dist/cli.js.map +0 -1
  51. package/dist/create.js.map +0 -1
  52. package/dist/discovery-Difb7Y4G.js.map +0 -1
  53. package/dist/generate.js.map +0 -1
  54. package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
  55. package/dist/openapi.js.map +0 -1
  56. package/dist/planner-VAj7qlxr.js.map +0 -1
  57. package/dist/range-YUs9eimn.js.map +0 -1
  58. package/dist/registry-CyrRHRG5.js.map +0 -1
  59. package/dist/skills-Bh0mEhIx.js.map +0 -1
  60. package/dist/specification-DXnDOC-0.js.map +0 -1
  61. package/dist/ssg.js.map +0 -1
  62. package/dist/templates/full-stack/src/vite-server.d.ts +0 -5
  63. package/dist/templates/spa/src/styles.d.ts +0 -1
  64. package/dist/templates/ssg/src/vite-env.d.ts +0 -5
  65. package/dist/templates/ssr/src/vite-server.d.ts +0 -7
  66. package/dist/templates/startkit/src/vite-env.d.ts +0 -5
  67. package/dist/update.js.map +0 -1
  68. package/dist/writer-D8qe_7ud.js.map +0 -1
  69. package/skills/askr-accessibility/SKILL.md +0 -68
  70. package/skills/askr-accessibility/agents/openai.yaml +0 -4
  71. package/skills/askr-agent-execution/SKILL.md +0 -85
  72. package/skills/askr-agent-execution/agents/openai.yaml +0 -4
  73. package/skills/askr-agent-workflows/SKILL.md +0 -57
  74. package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
  75. package/skills/askr-api-integration/SKILL.md +0 -79
  76. package/skills/askr-api-integration/agents/openai.yaml +0 -4
  77. package/skills/askr-app-builder/SKILL.md +0 -99
  78. package/skills/askr-app-builder/agents/openai.yaml +0 -4
  79. package/skills/askr-auth-access/SKILL.md +0 -74
  80. package/skills/askr-auth-access/agents/openai.yaml +0 -4
  81. package/skills/askr-cli-vite/SKILL.md +0 -76
  82. package/skills/askr-cli-vite/agents/openai.yaml +0 -4
  83. package/skills/askr-dashboard-charts/SKILL.md +0 -99
  84. package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
  85. package/skills/askr-design-system/SKILL.md +0 -86
  86. package/skills/askr-design-system/agents/openai.yaml +0 -4
  87. package/skills/askr-env-config/SKILL.md +0 -74
  88. package/skills/askr-env-config/agents/openai.yaml +0 -4
  89. package/skills/askr-error-loading-empty/SKILL.md +0 -89
  90. package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
  91. package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
  92. package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
  93. package/skills/askr-forms-tables-crud/SKILL.md +0 -98
  94. package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
  95. package/skills/askr-mental-model/SKILL.md +0 -109
  96. package/skills/askr-mental-model/agents/openai.yaml +0 -4
  97. package/skills/askr-migration-react/SKILL.md +0 -81
  98. package/skills/askr-migration-react/agents/openai.yaml +0 -4
  99. package/skills/askr-observability-debugging/SKILL.md +0 -83
  100. package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
  101. package/skills/askr-project-structure/SKILL.md +0 -79
  102. package/skills/askr-project-structure/agents/openai.yaml +0 -4
  103. package/skills/askr-query-mutation/SKILL.md +0 -115
  104. package/skills/askr-query-mutation/agents/openai.yaml +0 -4
  105. package/skills/askr-realtime-streaming/SKILL.md +0 -76
  106. package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
  107. package/skills/askr-resources-data/SKILL.md +0 -100
  108. package/skills/askr-resources-data/agents/openai.yaml +0 -4
  109. package/skills/askr-routing-layouts/SKILL.md +0 -107
  110. package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
  111. package/skills/askr-runtime-reactivity/SKILL.md +0 -92
  112. package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
  113. package/skills/askr-ssr-ssg/SKILL.md +0 -76
  114. package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
  115. package/skills/askr-testing-determinism/SKILL.md +0 -75
  116. package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
  117. package/skills/askr-theming/SKILL.md +0 -86
  118. package/skills/askr-theming/agents/openai.yaml +0 -4
  119. package/skills/askr-ui-composition/SKILL.md +0 -92
  120. package/skills/askr-ui-composition/agents/openai.yaml +0 -4
  121. package/templates/full-stack/AGENTS.md +0 -11
  122. package/templates/full-stack/README.md +0 -17
  123. package/templates/full-stack/gitignore.template +0 -4
  124. package/templates/full-stack/index.html +0 -13
  125. package/templates/full-stack/package.json +0 -39
  126. package/templates/full-stack/server.ts +0 -9
  127. package/templates/full-stack/src/action-authorizations.ts +0 -10
  128. package/templates/full-stack/src/actions/create-message.ts +0 -10
  129. package/templates/full-stack/src/i18n.ts +0 -8
  130. package/templates/full-stack/src/main.tsx +0 -11
  131. package/templates/full-stack/src/pages/home.tsx +0 -25
  132. package/templates/full-stack/src/pages/layout.tsx +0 -43
  133. package/templates/full-stack/src/pages/not-found.tsx +0 -7
  134. package/templates/full-stack/src/routes.tsx +0 -19
  135. package/templates/full-stack/src/schemas.ts +0 -10
  136. package/templates/full-stack/src/server/action-registry.ts +0 -8
  137. package/templates/full-stack/src/server/actions/create-message.ts +0 -14
  138. package/templates/full-stack/src/server/app.ts +0 -76
  139. package/templates/full-stack/src/server/dependencies.ts +0 -55
  140. package/templates/full-stack/src/server/entry-server.ts +0 -8
  141. package/templates/full-stack/src/telemetry.ts +0 -3
  142. package/templates/full-stack/src/vite-server.d.ts +0 -5
  143. package/templates/full-stack/tests/actions/create-message.test.ts +0 -12
  144. package/templates/full-stack/tsconfig.json +0 -15
  145. package/templates/full-stack/vite.config.ts +0 -10
  146. package/templates/spa/AGENTS.md +0 -60
  147. package/templates/spa/README.md +0 -96
  148. package/templates/spa/gitignore.template +0 -16
  149. package/templates/spa/index.html +0 -13
  150. package/templates/spa/package.json +0 -35
  151. package/templates/spa/src/adapters/operations-client.ts +0 -95
  152. package/templates/spa/src/components/shared/metric-card.tsx +0 -27
  153. package/templates/spa/src/components/shared/status-badge.tsx +0 -24
  154. package/templates/spa/src/features/operations/operations.query.ts +0 -9
  155. package/templates/spa/src/main.tsx +0 -10
  156. package/templates/spa/src/pages/_layout.tsx +0 -9
  157. package/templates/spa/src/pages/_routes.tsx +0 -27
  158. package/templates/spa/src/pages/app/_layout.tsx +0 -94
  159. package/templates/spa/src/pages/app/_routes.tsx +0 -10
  160. package/templates/spa/src/pages/app/admin-home.tsx +0 -170
  161. package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
  162. package/templates/spa/src/pages/app/settings.tsx +0 -91
  163. package/templates/spa/src/pages/auth/_layout.tsx +0 -38
  164. package/templates/spa/src/pages/auth/_routes.tsx +0 -6
  165. package/templates/spa/src/pages/auth/login.tsx +0 -63
  166. package/templates/spa/src/pages/not-found.tsx +0 -22
  167. package/templates/spa/src/pages/public/_layout.tsx +0 -47
  168. package/templates/spa/src/pages/public/_routes.tsx +0 -6
  169. package/templates/spa/src/pages/public/home.tsx +0 -143
  170. package/templates/spa/src/shared/format.ts +0 -12
  171. package/templates/spa/src/shared/navigation.ts +0 -15
  172. package/templates/spa/src/styles/components.css +0 -49
  173. package/templates/spa/src/styles/layout.css +0 -192
  174. package/templates/spa/src/styles/reset.css +0 -44
  175. package/templates/spa/src/styles/theme.css +0 -57
  176. package/templates/spa/src/styles/tokens.css +0 -20
  177. package/templates/spa/src/styles.css +0 -7
  178. package/templates/spa/src/styles.d.ts +0 -1
  179. package/templates/spa/tests/app.test.tsx +0 -37
  180. package/templates/spa/tests/components/shared.test.tsx +0 -12
  181. package/templates/spa/tests/resources.test.ts +0 -22
  182. package/templates/spa/tsconfig.json +0 -20
  183. package/templates/spa/tsconfig.node.json +0 -10
  184. package/templates/spa/vite.config.ts +0 -24
  185. package/templates/spa/vitest.config.ts +0 -17
  186. package/templates/ssg/AGENTS.md +0 -55
  187. package/templates/ssg/README.md +0 -39
  188. package/templates/ssg/gitignore.template +0 -17
  189. package/templates/ssg/index.html +0 -13
  190. package/templates/ssg/package.json +0 -35
  191. package/templates/ssg/src/app.tsx +0 -14
  192. package/templates/ssg/src/components/badge.tsx +0 -3
  193. package/templates/ssg/src/components/counter.tsx +0 -30
  194. package/templates/ssg/src/components/site-shell.tsx +0 -111
  195. package/templates/ssg/src/jsx.d.ts +0 -23
  196. package/templates/ssg/src/main.tsx +0 -8
  197. package/templates/ssg/src/pages/about.tsx +0 -82
  198. package/templates/ssg/src/pages/content.tsx +0 -63
  199. package/templates/ssg/src/pages/example.tsx +0 -97
  200. package/templates/ssg/src/pages/home.tsx +0 -51
  201. package/templates/ssg/src/resources/user.ts +0 -15
  202. package/templates/ssg/src/routes.tsx +0 -15
  203. package/templates/ssg/src/styles.css +0 -89
  204. package/templates/ssg/src/vite-env.d.ts +0 -5
  205. package/templates/ssg/ssg.config.ts +0 -34
  206. package/templates/ssg/tests/app.test.tsx +0 -19
  207. package/templates/ssg/tests/components/counter.test.tsx +0 -18
  208. package/templates/ssg/tests/resources.test.ts +0 -11
  209. package/templates/ssg/tests/ssg-config.test.ts +0 -11
  210. package/templates/ssg/tsconfig.json +0 -20
  211. package/templates/ssg/tsconfig.node.json +0 -10
  212. package/templates/ssg/vite.config.ts +0 -24
  213. package/templates/ssg/vitest.config.ts +0 -17
  214. package/templates/ssr/AGENTS.md +0 -28
  215. package/templates/ssr/README.md +0 -38
  216. package/templates/ssr/gitignore.template +0 -16
  217. package/templates/ssr/index.html +0 -13
  218. package/templates/ssr/package.json +0 -34
  219. package/templates/ssr/server.ts +0 -10
  220. package/templates/ssr/src/app.tsx +0 -21
  221. package/templates/ssr/src/components/counter.tsx +0 -26
  222. package/templates/ssr/src/entry-server.tsx +0 -12
  223. package/templates/ssr/src/main.tsx +0 -11
  224. package/templates/ssr/src/pages/about.tsx +0 -75
  225. package/templates/ssr/src/pages/example.tsx +0 -113
  226. package/templates/ssr/src/pages/home.tsx +0 -56
  227. package/templates/ssr/src/resources/user.ts +0 -15
  228. package/templates/ssr/src/routes.tsx +0 -13
  229. package/templates/ssr/src/styles.css +0 -148
  230. package/templates/ssr/src/vite-server.d.ts +0 -7
  231. package/templates/ssr/tests/app.test.tsx +0 -24
  232. package/templates/ssr/tests/components/counter.test.tsx +0 -13
  233. package/templates/ssr/tests/resources.test.ts +0 -11
  234. package/templates/ssr/tsconfig.json +0 -22
  235. package/templates/ssr/tsconfig.node.json +0 -10
  236. package/templates/ssr/tsconfig.server.json +0 -15
  237. package/templates/ssr/vite.config.ts +0 -25
  238. package/templates/ssr/vitest.config.ts +0 -13
  239. package/templates/startkit/AGENTS.md +0 -77
  240. package/templates/startkit/README.md +0 -192
  241. package/templates/startkit/gitignore.template +0 -16
  242. package/templates/startkit/index.html +0 -13
  243. package/templates/startkit/package.json +0 -35
  244. package/templates/startkit/src/components/app-header.tsx +0 -93
  245. package/templates/startkit/src/components/app-sidebar.tsx +0 -95
  246. package/templates/startkit/src/components/data-table.tsx +0 -80
  247. package/templates/startkit/src/components/empty-state.tsx +0 -13
  248. package/templates/startkit/src/components/page-header.tsx +0 -23
  249. package/templates/startkit/src/components/stat-card.tsx +0 -24
  250. package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
  251. package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
  252. package/templates/startkit/src/lib/format.ts +0 -31
  253. package/templates/startkit/src/lib/mock-data.ts +0 -441
  254. package/templates/startkit/src/lib/routes.ts +0 -116
  255. package/templates/startkit/src/main.tsx +0 -12
  256. package/templates/startkit/src/pages/_layout.tsx +0 -56
  257. package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
  258. package/templates/startkit/src/pages/auth/login.tsx +0 -129
  259. package/templates/startkit/src/pages/home.tsx +0 -83
  260. package/templates/startkit/src/pages/not-found.tsx +0 -24
  261. package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
  262. package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
  263. package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
  264. package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
  265. package/templates/startkit/src/router.tsx +0 -7
  266. package/templates/startkit/src/routes/auth-config.ts +0 -38
  267. package/templates/startkit/src/routes/auth.ts +0 -8
  268. package/templates/startkit/src/routes/index.ts +0 -28
  269. package/templates/startkit/src/routes/public.ts +0 -8
  270. package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
  271. package/templates/startkit/src/routes/workspace/index.ts +0 -14
  272. package/templates/startkit/src/styles/components.css +0 -396
  273. package/templates/startkit/src/styles/layout.css +0 -192
  274. package/templates/startkit/src/styles/reset.css +0 -38
  275. package/templates/startkit/src/styles/theme.css +0 -76
  276. package/templates/startkit/src/styles/tokens.css +0 -67
  277. package/templates/startkit/src/styles.css +0 -7
  278. package/templates/startkit/src/toast.ts +0 -55
  279. package/templates/startkit/src/utils/join-classes.ts +0 -4
  280. package/templates/startkit/src/vite-env.d.ts +0 -5
  281. package/templates/startkit/tests/app.test.tsx +0 -32
  282. package/templates/startkit/tests/preferences.test.ts +0 -43
  283. package/templates/startkit/tests/resources.test.ts +0 -82
  284. package/templates/startkit/tsconfig.json +0 -20
  285. package/templates/startkit/tsconfig.node.json +0 -10
  286. package/templates/startkit/vite.config.ts +0 -32
  287. package/templates/startkit/vitest.config.ts +0 -13
package/dist/generate.js CHANGED
@@ -1,5 +1,5 @@
1
- import { mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
2
- import { basename, dirname, join, resolve } from "node:path";
1
+ import { mkdir, mkdtemp, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
2
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
3
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
4
  import { load } from "js-yaml";
5
5
  //#region src/generate/generator.ts
@@ -34,6 +34,17 @@ function schemaType(schema, at, direction = "response") {
34
34
  const name = decodeURIComponent(String(schema.$ref).split("/").at(-1));
35
35
  return pascal(name);
36
36
  }
37
+ if (Array.isArray(schema.type)) {
38
+ const includesNull = schema.type.includes("null");
39
+ const rendered = [...new Set(schema.type.filter((value) => value !== "null"))].map((variant) => schemaType({
40
+ ...schema,
41
+ type: variant,
42
+ nullable: false
43
+ }, at, direction));
44
+ if (includesNull) rendered.push("null");
45
+ if (rendered.length === 0) fail("Schema type array must not be empty", at);
46
+ return [...new Set(rendered)].join(" | ");
47
+ }
37
48
  if (schema.const !== void 0) return JSON.stringify(schema.const);
38
49
  if (schema.enum) return schema.enum.map((value) => JSON.stringify(value)).join(" | ") || "never";
39
50
  if (schema.oneOf || schema.anyOf) return (schema.oneOf ?? schema.anyOf).map((item, i) => schemaType(item, `${at}/${schema.oneOf ? "oneOf" : "anyOf"}/${i}`, direction)).join(" | ");
@@ -230,18 +241,31 @@ function generateFiles(document) {
230
241
  if (seen.has(id)) fail("Duplicate operationId", `${at}/operationId`, id);
231
242
  seen.add(id);
232
243
  if (operation.callbacks) fail("Callbacks are unsupported", `${at}/callbacks`, id);
233
- const parameters = [...document.paths[path].parameters ?? [], ...operation.parameters ?? []];
244
+ const parametersByIdentity = /* @__PURE__ */ new Map();
245
+ for (const parameter of [...document.paths[path].parameters ?? [], ...operation.parameters ?? []]) {
246
+ if (parameter.$ref) fail("Parameter references must be bundled", `${at}/parameters`, id);
247
+ if (typeof parameter.name !== "string" || typeof parameter.in !== "string") fail("Parameters require string name and in fields", `${at}/parameters`, id);
248
+ parametersByIdentity.set(`${parameter.in}\0${parameter.name}`, parameter);
249
+ }
250
+ const parameters = [...parametersByIdentity.values()];
234
251
  const byLocation = {
235
252
  path: [],
236
253
  query: [],
237
254
  header: []
238
255
  };
239
256
  for (const parameter of parameters) {
240
- if (parameter.$ref) fail("Parameter references must be bundled", `${at}/parameters`, id);
241
257
  if (parameter.in === "cookie") fail("Cookie parameters are unsupported", `${at}/parameters`, id);
242
258
  if (!byLocation[parameter.in]) fail(`Unsupported parameter location ${parameter.in}`, `${at}/parameters`, id);
243
259
  byLocation[parameter.in].push(parameter);
244
260
  }
261
+ const templateParameters = new Set([...path.matchAll(/\{([^{}]+)\}/g)].map((match) => match[1]));
262
+ const declaredPathParameters = new Set(byLocation.path.map((parameter) => parameter.name));
263
+ for (const name of templateParameters) {
264
+ const parameter = byLocation.path.find((candidate) => candidate.name === name);
265
+ if (!parameter) fail(`Path template parameter ${name} is not declared`, `${at}/parameters`, id);
266
+ if (!parameter || parameter.required !== true) fail(`Path parameter ${name} must be required`, `${at}/parameters`, id);
267
+ }
268
+ for (const name of declaredPathParameters) if (!templateParameters.has(name)) fail(`Path parameter ${name} is not present in the path template`, `${at}/parameters`, id);
245
269
  const prefix = pascal(id);
246
270
  const renderParameters = (location) => {
247
271
  const list = byLocation[location].sort((a, b) => a.name.localeCompare(b.name));
@@ -319,6 +343,8 @@ async function existingFiles(directory) {
319
343
  }
320
344
  async function writeGenerated(directory, files, check) {
321
345
  const output = resolve(directory);
346
+ const outputStat = await stat(output).catch(() => null);
347
+ if (outputStat && !outputStat.isDirectory()) throw new GenerationError(`Generated output must be a directory: ${output}`);
322
348
  const entries = await existingFiles(output);
323
349
  if (check) {
324
350
  if (!entries.length) throw new GenerationError(`Generated directory is missing: ${output}`);
@@ -357,6 +383,11 @@ async function writeGenerated(directory, files, check) {
357
383
  }
358
384
  }
359
385
  async function generate(input, output, check = false) {
386
+ if (!/^https?:\/\//.test(input)) {
387
+ const resolvedInput = resolve(input);
388
+ const inputWithinOutput = relative(resolve(output), resolvedInput);
389
+ if (!inputWithinOutput.startsWith("..") && !isAbsolute(inputWithinOutput)) throw new GenerationError("Generated output must not contain its OpenAPI input document");
390
+ }
360
391
  const files = generateFiles(await loadOpenApi(input));
361
392
  await mkdir(dirname(resolve(output)), { recursive: true });
362
393
  await writeGenerated(output, files, check);
@@ -364,33 +395,67 @@ async function generate(input, output, check = false) {
364
395
  //#endregion
365
396
  //#region src/bin/generate.ts
366
397
  async function runGenerateCli(args, io = console) {
398
+ const wantsJson = args.includes("--json");
367
399
  let output;
368
400
  let check = false;
401
+ let json = false;
402
+ let help = false;
369
403
  const inputs = [];
370
404
  for (let i = 0; i < args.length; i++) {
371
405
  const arg = args[i];
372
406
  if (arg === "--check") check = true;
373
- else if (arg === "-o" || arg === "--output") output = args[++i];
374
- else if (arg.startsWith("--output=")) output = arg.slice(9);
407
+ else if (arg === "--json") json = true;
408
+ else if (arg === "--help" || arg === "-h") help = true;
409
+ else if (arg === "-o" || arg === "--output") {
410
+ const value = args[i + 1];
411
+ if (!value || value.startsWith("-")) {
412
+ const message = `${arg} requires a path`;
413
+ io.error(wantsJson ? JSON.stringify({
414
+ status: "error",
415
+ error: message
416
+ }) : message);
417
+ return 1;
418
+ }
419
+ output = value;
420
+ i += 1;
421
+ } else if (arg.startsWith("--output=")) output = arg.slice(9);
375
422
  else if (arg.startsWith("-")) {
376
- io.error(`Unknown option: ${arg}`);
423
+ const message = `Unknown option: ${arg}`;
424
+ io.error(wantsJson ? JSON.stringify({
425
+ status: "error",
426
+ error: message
427
+ }) : message);
377
428
  return 1;
378
429
  } else inputs.push(arg);
379
430
  }
431
+ const usage = "Usage: askr generate <input> -o <output-directory> [--check] [--json]";
432
+ if (help) {
433
+ io.log(usage);
434
+ return 0;
435
+ }
380
436
  if (inputs.length !== 1 || !output) {
381
- io.error("Usage: askr generate <input> -o <output-directory> [--check]");
437
+ io.error(json ? JSON.stringify({
438
+ status: "error",
439
+ error: usage
440
+ }) : usage);
382
441
  return 1;
383
442
  }
384
443
  try {
385
444
  await generate(inputs[0], output, check);
386
- io.log(check ? "Generated client is current." : `Generated client in ${output}.`);
445
+ io.log(json ? JSON.stringify({
446
+ status: "ok",
447
+ action: check ? "checked" : "generated",
448
+ output
449
+ }) : check ? "Generated client is current." : `Generated client in ${output}.`);
387
450
  return 0;
388
451
  } catch (error) {
389
- io.error(error instanceof Error ? error.message : String(error));
452
+ const message = error instanceof Error ? error.message : String(error);
453
+ io.error(json ? JSON.stringify({
454
+ status: "error",
455
+ error: message
456
+ }) : message);
390
457
  return 1;
391
458
  }
392
459
  }
393
460
  //#endregion
394
461
  export { runGenerateCli };
395
-
396
- //# sourceMappingURL=generate.js.map
@@ -16,5 +16,3 @@ function isDirectExecution(moduleUrl, argvPath = process.argv[1]) {
16
16
  }
17
17
  //#endregion
18
18
  export { isDirectExecution as t };
19
-
20
- //# sourceMappingURL=is-direct-execution-Cdlr-ZUl.js.map
@@ -0,0 +1,25 @@
1
+ //#region src/bin/openapi.d.ts
2
+ type CliIo = Pick<Console, "error" | "log">;
3
+ interface ParsedArgs {
4
+ entry: string;
5
+ output: string;
6
+ check: boolean;
7
+ help: boolean;
8
+ json: boolean;
9
+ }
10
+ interface OpenApiDeps {
11
+ cwd(): string;
12
+ importModule(filePath: string): Promise<unknown>;
13
+ readFile(filePath: string): Promise<string>;
14
+ mkdir(directory: string): Promise<void>;
15
+ writeFile(filePath: string, contents: string): Promise<void>;
16
+ rename(from: string, to: string): Promise<void>;
17
+ rm(filePath: string): Promise<void>;
18
+ temporarySuffix(): string;
19
+ }
20
+ declare function parseOpenApiArgs(args: readonly string[]): ParsedArgs;
21
+ declare function serializeOpenApi(document: unknown): string;
22
+ declare function validateOpenApiDocument(document: unknown): asserts document is Record<string, unknown>;
23
+ declare function runOpenApiCli(args?: string[], io?: CliIo, overrides?: Partial<OpenApiDeps>): Promise<number>;
24
+ //#endregion
25
+ export { parseOpenApiArgs, runOpenApiCli, serializeOpenApi, validateOpenApiDocument };
package/dist/openapi.js CHANGED
@@ -15,6 +15,7 @@ Options:
15
15
  --entry <path> TypeScript API module (default: ./src/api.ts)
16
16
  --output <path> YAML artifact (default: ./openapi.yml)
17
17
  --check Fail when the artifact is missing or byte-stale; never write
18
+ --json Print machine-readable command results
18
19
  --help, -h Show help
19
20
  `;
20
21
  const defaultDeps = {
@@ -32,17 +33,19 @@ function parseOpenApiArgs(args) {
32
33
  entry: "./src/api.ts",
33
34
  output: "./openapi.yml",
34
35
  check: false,
35
- help: false
36
+ help: false,
37
+ json: false
36
38
  };
37
39
  for (let index = 0; index < args.length; index += 1) {
38
40
  const value = args[index];
39
41
  if (value === "--entry" || value === "--output") {
40
42
  const next = args[index + 1];
41
- if (!next) throw new Error(`${value} requires a path`);
43
+ if (!next || next.startsWith("-")) throw new Error(`${value} requires a path`);
42
44
  if (value === "--entry") parsed.entry = next;
43
45
  else parsed.output = next;
44
46
  index += 1;
45
47
  } else if (value === "--check") parsed.check = true;
48
+ else if (value === "--json") parsed.json = true;
46
49
  else if (value === "--help" || value === "-h") parsed.help = true;
47
50
  else throw new Error(`Unknown option: ${value}`);
48
51
  }
@@ -62,9 +65,18 @@ function serializeOpenApi(document) {
62
65
  noRefs: true
63
66
  }).replace(/\n+$/, "")}\n`;
64
67
  }
65
- async function generate(entry, deps) {
66
- const document = exporterFrom(await deps.importModule(entry)).toOpenApiDocument();
68
+ function validateOpenApiDocument(document) {
67
69
  if (!document || typeof document !== "object" || Array.isArray(document)) throw new Error("toOpenApiDocument() must return an OpenAPI document object");
70
+ const candidate = document;
71
+ if (typeof candidate.openapi !== "string" || !/^3\.(?:0|1)\.\d+(?:[-+].+)?$/.test(candidate.openapi)) throw new Error("OpenAPI document must declare a supported openapi 3.0.x or 3.1.x version");
72
+ if (!candidate.info || typeof candidate.info !== "object" || Array.isArray(candidate.info)) throw new Error("OpenAPI document must contain an info object");
73
+ const info = candidate.info;
74
+ if (typeof info.title !== "string" || !info.title.trim() || typeof info.version !== "string" || !info.version.trim()) throw new Error("OpenAPI info must contain non-empty title and version strings");
75
+ if (!candidate.paths || typeof candidate.paths !== "object" || Array.isArray(candidate.paths)) throw new Error("OpenAPI document must contain a paths object");
76
+ }
77
+ async function generate(entry, deps) {
78
+ const document = await exporterFrom(await deps.importModule(entry)).toOpenApiDocument();
79
+ validateOpenApiDocument(document);
68
80
  return serializeOpenApi(document);
69
81
  }
70
82
  async function atomicWrite(output, contents, deps) {
@@ -83,6 +95,7 @@ async function runOpenApiCli(args = process.argv.slice(2), io = console, overrid
83
95
  ...defaultDeps,
84
96
  ...overrides
85
97
  };
98
+ const wantsJson = args.includes("--json");
86
99
  try {
87
100
  const parsed = parseOpenApiArgs(args);
88
101
  if (parsed.help) {
@@ -91,6 +104,7 @@ async function runOpenApiCli(args = process.argv.slice(2), io = console, overrid
91
104
  }
92
105
  const entry = path.resolve(deps.cwd(), parsed.entry);
93
106
  const output = path.resolve(deps.cwd(), parsed.output);
107
+ if (entry === output) throw new Error("OpenAPI output must not overwrite its source entry");
94
108
  const expected = await generate(entry, deps);
95
109
  if (parsed.check) {
96
110
  let actual;
@@ -98,23 +112,43 @@ async function runOpenApiCli(args = process.argv.slice(2), io = console, overrid
98
112
  actual = await deps.readFile(output);
99
113
  } catch (error) {
100
114
  if (error.code === "ENOENT") {
101
- io.error(`OpenAPI artifact is missing: ${output}`);
115
+ io.error(parsed.json ? JSON.stringify({
116
+ status: "error",
117
+ reason: "missing",
118
+ output
119
+ }) : `OpenAPI artifact is missing: ${output}`);
102
120
  return 1;
103
121
  }
104
122
  throw error;
105
123
  }
106
124
  if (actual !== expected) {
107
- io.error(`OpenAPI artifact is stale: ${output}`);
125
+ io.error(parsed.json ? JSON.stringify({
126
+ status: "error",
127
+ reason: "stale",
128
+ output
129
+ }) : `OpenAPI artifact is stale: ${output}`);
108
130
  return 1;
109
131
  }
110
- io.log(`OpenAPI artifact is current: ${output}`);
132
+ io.log(parsed.json ? JSON.stringify({
133
+ status: "ok",
134
+ action: "checked",
135
+ output
136
+ }) : `OpenAPI artifact is current: ${output}`);
111
137
  return 0;
112
138
  }
113
139
  await atomicWrite(output, expected, deps);
114
- io.log(`Generated OpenAPI artifact: ${output}`);
140
+ io.log(parsed.json ? JSON.stringify({
141
+ status: "ok",
142
+ action: "generated",
143
+ output
144
+ }) : `Generated OpenAPI artifact: ${output}`);
115
145
  return 0;
116
146
  } catch (error) {
117
- io.error(error instanceof Error ? error.message : String(error));
147
+ const message = error instanceof Error ? error.message : String(error);
148
+ io.error(wantsJson ? JSON.stringify({
149
+ status: "error",
150
+ error: message
151
+ }) : message);
118
152
  return 1;
119
153
  }
120
154
  }
@@ -123,6 +157,4 @@ async function main() {
123
157
  }
124
158
  if (isDirectExecution(import.meta.url)) main();
125
159
  //#endregion
126
- export { parseOpenApiArgs, runOpenApiCli, serializeOpenApi };
127
-
128
- //# sourceMappingURL=openapi.js.map
160
+ export { parseOpenApiArgs, runOpenApiCli, serializeOpenApi, validateOpenApiDocument };
@@ -283,5 +283,3 @@ function planUpdates(options) {
283
283
  }
284
284
  //#endregion
285
285
  export { planUpdates };
286
-
287
- //# sourceMappingURL=planner-VAj7qlxr.js.map
@@ -123,5 +123,3 @@ function rewriteRange(shape, target, forcedBreaking) {
123
123
  }
124
124
  //#endregion
125
125
  export { isBreakingChange as n, rewriteRange as r, analyzeRange as t };
126
-
127
- //# sourceMappingURL=range-YUs9eimn.js.map
@@ -207,5 +207,3 @@ async function fetchPackuments(packageNames, configuration, options = {}) {
207
207
  }
208
208
  //#endregion
209
209
  export { fetchPackuments, loadNpmConfiguration };
210
-
211
- //# sourceMappingURL=registry-CyrRHRG5.js.map
@@ -28,7 +28,8 @@ Use this when the app renders outside the browser or produces static output. The
28
28
  2. Register routes at module load before boot or render.
29
29
  3. Keep render paths deterministic and environment-safe.
30
30
  4. Use route `entries` or the template's static config for parameterized SSG paths.
31
- 5. Build and preview after changes that cross the render boundary.
31
+ 5. Set the canonical `siteUrl` and explicitly exclude non-indexable routes in `sitemap.routes`.
32
+ 6. Build and preview after changes that cross the render boundary.
32
33
 
33
34
  ## Copy This Shape
34
35
 
@@ -61,6 +62,7 @@ npx @askrjs/cli ssg --config ./ssg.config.ts --output ./dist/static
61
62
  - SSR or SSG build output is deterministic for the same inputs.
62
63
  - Hydration has no structural mismatch warnings.
63
64
  - Generated static routes cover expected params.
65
+ - `sitemap.xml` contains every intended canonical route and excludes runtime-only or non-indexable routes.
64
66
  - Browser preview still navigates correctly after hydration.
65
67
 
66
68
  ## Done When
@@ -1,6 +1,8 @@
1
1
  import { t as isDirectExecution } from "./is-direct-execution-Cdlr-ZUl.js";
2
+ import { n as publishStagedDirectory, t as createSiblingStage } from "./directory-swap-DWoHtx7C.js";
2
3
  import fs from "node:fs/promises";
3
4
  import path from "node:path";
5
+ import { constants } from "node:fs";
4
6
  import { fileURLToPath } from "node:url";
5
7
  //#region src/bin/skill-review.ts
6
8
  const TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -312,29 +314,41 @@ const REVIEW_PROMPTS = [
312
314
  async function pathExists$1(filePath) {
313
315
  return Boolean(await fs.stat(filePath).catch(() => null));
314
316
  }
317
+ const MAX_REVIEW_FILES = 1e4;
318
+ const MAX_REVIEW_FILE_BYTES = 2 * 1024 * 1024;
319
+ const MAX_REVIEW_TOTAL_BYTES = 20 * 1024 * 1024;
315
320
  function shouldReadFile(filePath) {
316
321
  return TEXT_FILE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
317
322
  }
318
- async function collectReviewFiles(targetPath, files) {
323
+ async function collectReviewFiles(targetPath, state) {
319
324
  const stat = await fs.lstat(targetPath);
320
325
  if (stat.isSymbolicLink()) return;
321
326
  if (stat.isDirectory()) {
322
327
  const entries = await fs.readdir(targetPath, { withFileTypes: true });
323
328
  for (const entry of entries) {
324
329
  if (entry.isDirectory() && IGNORED_DIRECTORIES.has(entry.name)) continue;
325
- await collectReviewFiles(path.join(targetPath, entry.name), files);
330
+ await collectReviewFiles(path.join(targetPath, entry.name), state);
326
331
  }
327
332
  return;
328
333
  }
329
- if (stat.isFile() && shouldReadFile(targetPath)) files.push(targetPath);
334
+ if (stat.isFile() && shouldReadFile(targetPath)) {
335
+ if (stat.size > MAX_REVIEW_FILE_BYTES) throw new Error(`Review file exceeds ${MAX_REVIEW_FILE_BYTES} bytes: ${targetPath}`);
336
+ if (state.files.length >= MAX_REVIEW_FILES) throw new Error(`Review target exceeds ${MAX_REVIEW_FILES} text files`);
337
+ state.totalBytes += stat.size;
338
+ if (state.totalBytes > MAX_REVIEW_TOTAL_BYTES) throw new Error(`Review target exceeds ${MAX_REVIEW_TOTAL_BYTES} text bytes`);
339
+ state.files.push(targetPath);
340
+ }
330
341
  }
331
342
  async function loadReviewFiles(targetPath) {
332
343
  const resolvedTarget = path.resolve(targetPath);
333
344
  if (!await pathExists$1(resolvedTarget)) throw new Error(`Review target not found: ${resolvedTarget}`);
334
345
  const baseDirectory = (await fs.stat(resolvedTarget)).isDirectory() ? resolvedTarget : path.dirname(resolvedTarget);
335
- const absoluteFiles = [];
336
- await collectReviewFiles(resolvedTarget, absoluteFiles);
337
- const files = await Promise.all(absoluteFiles.map(async (filePath) => ({
346
+ const collection = {
347
+ files: [],
348
+ totalBytes: 0
349
+ };
350
+ await collectReviewFiles(resolvedTarget, collection);
351
+ const files = await Promise.all(collection.files.map(async (filePath) => ({
338
352
  path: path.relative(baseDirectory, filePath) || path.basename(filePath),
339
353
  content: await fs.readFile(filePath, "utf8")
340
354
  })));
@@ -496,17 +510,23 @@ function parseArgs(args) {
496
510
  cwd: process.cwd(),
497
511
  force: false,
498
512
  help: false,
499
- json: false
513
+ json: false,
514
+ errors: []
500
515
  };
501
516
  for (let i = 0; i < args.length; i += 1) {
502
517
  const arg = args[i];
503
518
  if (arg === "--help" || arg === "-h") parsed.help = true;
504
519
  else if (arg === "--json") parsed.json = true;
505
520
  else if (arg === "--force") parsed.force = true;
506
- else if (arg === "--cwd" && i + 1 < args.length) {
507
- parsed.cwd = args[i + 1];
508
- i += 1;
509
- } else positional.push(arg);
521
+ else if (arg === "--cwd") {
522
+ const value = args[i + 1];
523
+ if (!value || value.startsWith("-")) parsed.errors.push("Missing value for --cwd");
524
+ else {
525
+ parsed.cwd = value;
526
+ i += 1;
527
+ }
528
+ } else if (arg.startsWith("-")) parsed.errors.push(`Unknown option: ${arg}`);
529
+ else positional.push(arg);
510
530
  }
511
531
  return {
512
532
  ...parsed,
@@ -572,16 +592,36 @@ async function copyBundledSkills(targetSkillsDir, bundledNames) {
572
592
  await copyDir(src, dest);
573
593
  }
574
594
  }
595
+ async function stageSkillsDirectory(targetSkillsDir) {
596
+ const stage = await createSiblingStage(targetSkillsDir, "askr-skills");
597
+ if (await pathExists(targetSkillsDir)) await fs.cp(targetSkillsDir, stage, {
598
+ recursive: true,
599
+ mode: constants.COPYFILE_FICLONE
600
+ });
601
+ return stage;
602
+ }
603
+ async function replaceBundledSkills(targetSkillsDir, bundledNames) {
604
+ const stage = await stageSkillsDirectory(targetSkillsDir);
605
+ try {
606
+ await removeManagedSkillArtifacts(stage, bundledNames);
607
+ await copyBundledSkills(stage, bundledNames);
608
+ await publishStagedDirectory(stage, targetSkillsDir);
609
+ } catch (error) {
610
+ await fs.rm(stage, {
611
+ recursive: true,
612
+ force: true
613
+ });
614
+ throw error;
615
+ }
616
+ }
575
617
  async function installBundledSkills(options = {}) {
576
618
  const targetRoot = path.resolve(options.cwd ?? process.cwd());
577
619
  const targetSkillsDir = path.join(targetRoot, PROJECT_SKILLS_DIR);
578
620
  const bundledNames = await listBundledSkills();
621
+ const targetStat = await fs.stat(targetSkillsDir).catch(() => null);
622
+ if (targetStat && !targetStat.isDirectory()) throw new Error(`Skills target exists and is not a directory: ${targetSkillsDir}`);
579
623
  if ((await fs.readdir(targetSkillsDir).catch(() => [])).length > 0 && !options.force) throw new Error(`Refusing to install into non-empty ${targetSkillsDir}.`);
580
- if (options.force) {
581
- await fs.mkdir(targetSkillsDir, { recursive: true });
582
- await removeManagedSkillArtifacts(targetSkillsDir, bundledNames);
583
- }
584
- await copyBundledSkills(targetSkillsDir, bundledNames);
624
+ await replaceBundledSkills(targetSkillsDir, bundledNames);
585
625
  return {
586
626
  bundledNames,
587
627
  targetSkillsDir
@@ -591,9 +631,9 @@ async function syncBundledSkills(options = {}) {
591
631
  const targetRoot = path.resolve(options.cwd ?? process.cwd());
592
632
  const targetSkillsDir = path.join(targetRoot, PROJECT_SKILLS_DIR);
593
633
  const bundledNames = await listBundledSkills();
594
- await fs.mkdir(targetSkillsDir, { recursive: true });
595
- await removeManagedSkillArtifacts(targetSkillsDir, bundledNames);
596
- await copyBundledSkills(targetSkillsDir, bundledNames);
634
+ const targetStat = await fs.stat(targetSkillsDir).catch(() => null);
635
+ if (targetStat && !targetStat.isDirectory()) throw new Error(`Skills target exists and is not a directory: ${targetSkillsDir}`);
636
+ await replaceBundledSkills(targetSkillsDir, bundledNames);
597
637
  return {
598
638
  bundledNames,
599
639
  targetSkillsDir
@@ -615,9 +655,14 @@ async function installSkills(parsed, io) {
615
655
  }
616
656
  }
617
657
  async function syncSkills(parsed, io) {
618
- const { bundledNames, targetSkillsDir } = await syncBundledSkills({ cwd: parsed.cwd });
619
- io.log(`Synced ${bundledNames.length} Askr skills to ${targetSkillsDir}`);
620
- return 0;
658
+ try {
659
+ const { bundledNames, targetSkillsDir } = await syncBundledSkills({ cwd: parsed.cwd });
660
+ io.log(`Synced ${bundledNames.length} Askr skills to ${targetSkillsDir}`);
661
+ return 0;
662
+ } catch (error) {
663
+ io.error(error instanceof Error ? error.message : String(error));
664
+ return 1;
665
+ }
621
666
  }
622
667
  async function reviewSkills(parsed, io) {
623
668
  if (parsed.help && parsed.command === "review") {
@@ -646,6 +691,10 @@ async function reviewSkills(parsed, io) {
646
691
  }
647
692
  async function runSkillsCli(args = process.argv.slice(2), io = console) {
648
693
  const parsed = parseArgs(args);
694
+ if (parsed.errors.length > 0) {
695
+ for (const error of parsed.errors) io.error(error);
696
+ return 1;
697
+ }
649
698
  if (parsed.command === "review" && parsed.help) {
650
699
  io.log(reviewHelpText());
651
700
  return 0;
@@ -660,12 +709,28 @@ async function runSkillsCli(args = process.argv.slice(2), io = console) {
660
709
  return 1;
661
710
  }
662
711
  if (parsed.command === "list") {
712
+ if (parsed.positionals.length !== 1) {
713
+ io.error("Usage: askr skills list");
714
+ return 1;
715
+ }
663
716
  const names = await listBundledSkills();
664
717
  for (const name of names) io.log(name);
665
718
  return 0;
666
719
  }
667
- if (parsed.command === "install") return installSkills(parsed, io);
668
- if (parsed.command === "sync") return syncSkills(parsed, io);
720
+ if (parsed.command === "install") {
721
+ if (parsed.positionals.length !== 1) {
722
+ io.error("Usage: askr skills install [--cwd <dir>] [--force]");
723
+ return 1;
724
+ }
725
+ return installSkills(parsed, io);
726
+ }
727
+ if (parsed.command === "sync") {
728
+ if (parsed.positionals.length !== 1) {
729
+ io.error("Usage: askr skills sync [--cwd <dir>]");
730
+ return 1;
731
+ }
732
+ return syncSkills(parsed, io);
733
+ }
669
734
  if (parsed.command === "review") return reviewSkills(parsed, io);
670
735
  io.error(`Unknown skills command: ${parsed.command}`);
671
736
  io.error("Run `askr skills --help` to see available commands.");
@@ -678,5 +743,3 @@ async function main() {
678
743
  if (isDirectExecution(import.meta.url)) main();
679
744
  //#endregion
680
745
  export { runSkillsCli as n, syncBundledSkills as r, installBundledSkills as t };
681
-
682
- //# sourceMappingURL=skills-Bh0mEhIx.js.map
@@ -0,0 +1,18 @@
1
+ //#region src/bin/skills.d.ts
2
+ type CliIo = Pick<Console, "error" | "log">;
3
+ declare function installBundledSkills(options?: {
4
+ cwd?: string;
5
+ force?: boolean;
6
+ }): Promise<{
7
+ bundledNames: string[];
8
+ targetSkillsDir: string;
9
+ }>;
10
+ declare function syncBundledSkills(options?: {
11
+ cwd?: string;
12
+ }): Promise<{
13
+ bundledNames: string[];
14
+ targetSkillsDir: string;
15
+ }>;
16
+ declare function runSkillsCli(args?: string[], io?: CliIo): Promise<number>;
17
+ //#endregion
18
+ export { installBundledSkills, runSkillsCli, syncBundledSkills };
package/dist/skills.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { n as runSkillsCli, r as syncBundledSkills, t as installBundledSkills } from "./skills-Bh0mEhIx.js";
2
+ import { n as runSkillsCli, r as syncBundledSkills, t as installBundledSkills } from "./skills-B7CbWur9.js";
3
3
  export { installBundledSkills, runSkillsCli, syncBundledSkills };
@@ -47,5 +47,3 @@ function parseDependencySpecification(specification) {
47
47
  }
48
48
  //#endregion
49
49
  export { parseDependencySpecification as t };
50
-
51
- //# sourceMappingURL=specification-DXnDOC-0.js.map
@@ -0,0 +1,41 @@
1
+ //#region src/ssg/sitemap.d.ts
2
+ type SitemapChangeFrequency = "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
3
+ interface SitemapRouteConfig {
4
+ /** Canonical URL. Relative values resolve against siteUrl. */
5
+ url?: string;
6
+ /** W3C date/datetime or Date describing the last meaningful page update. */
7
+ lastModified?: string | Date;
8
+ changeFrequency?: SitemapChangeFrequency;
9
+ /** Relative crawl priority from 0 through 1. */
10
+ priority?: number;
11
+ /** hreflang to canonical URL mapping, including optional x-default. */
12
+ alternates?: Readonly<Record<string, string>>;
13
+ }
14
+ interface SitemapRouteContext {
15
+ path: string;
16
+ filePath: string;
17
+ status: string;
18
+ }
19
+ interface SitemapConfig {
20
+ /** Site-wide values inherited by included routes. */
21
+ defaults?: Omit<SitemapRouteConfig, "url" | "alternates">;
22
+ /** Exact concrete route overrides. Set a route to false to exclude it. */
23
+ routes?: Readonly<Record<string, SitemapRouteConfig | false>>;
24
+ /** Compute or override sitemap data. Returning false excludes the route. */
25
+ resolve?: (route: SitemapRouteContext) => SitemapRouteConfig | false | null | undefined | Promise<SitemapRouteConfig | false | null | undefined>;
26
+ /** Output path relative to the SSG output directory. */
27
+ output?: string;
28
+ /** Maintain a Sitemap directive in robots.txt. Defaults to true. */
29
+ robots?: boolean | {
30
+ output?: string;
31
+ };
32
+ /** Optional lower limits for deterministic partitioning and tests. */
33
+ limits?: {
34
+ urlsPerFile?: number;
35
+ bytesPerFile?: number;
36
+ };
37
+ /** Maximum concurrent async route metadata resolvers. Defaults to 16. */
38
+ resolverConcurrency?: number;
39
+ }
40
+ //#endregion
41
+ export type { SitemapChangeFrequency, SitemapConfig, SitemapRouteConfig, SitemapRouteContext };
@@ -0,0 +1 @@
1
+ export {};