@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.
- package/README.md +37 -0
- package/dist/add.d.ts +16 -0
- package/dist/add.js +33 -29
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +0 -2
- package/dist/create.d.ts +5 -0
- package/dist/create.js +104 -26
- package/dist/directory-swap-DWoHtx7C.js +35 -0
- package/dist/discovery-Difb7Y4G.js +0 -2
- package/dist/generate.d.ts +5 -0
- package/dist/generate.js +77 -12
- package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
- package/dist/openapi.d.ts +25 -0
- package/dist/openapi.js +44 -12
- package/dist/planner-VAj7qlxr.js +0 -2
- package/dist/range-YUs9eimn.js +0 -2
- package/dist/registry-CyrRHRG5.js +0 -2
- package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
- package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
- package/dist/skills.d.ts +18 -0
- package/dist/skills.js +1 -1
- package/dist/specification-DXnDOC-0.js +0 -2
- package/dist/ssg-config.d.ts +41 -0
- package/dist/ssg-config.js +1 -0
- package/dist/ssg.d.ts +61 -0
- package/dist/ssg.js +360 -24
- package/dist/templates/full-stack/package.json +1 -1
- package/dist/templates/full-stack/src/server/action-registry.ts +0 -1
- package/dist/templates/full-stack/tsconfig.json +1 -1
- package/dist/templates/spa/package.json +2 -3
- package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
- package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
- package/dist/templates/spa/tsconfig.json +2 -1
- package/dist/templates/spa/vitest.config.ts +0 -4
- package/dist/templates/ssg/README.md +1 -1
- package/dist/templates/ssg/package.json +1 -1
- package/dist/templates/ssg/ssg.config.ts +7 -0
- package/dist/templates/ssg/tests/ssg-config.test.ts +2 -0
- package/dist/templates/ssg/tsconfig.json +2 -1
- package/dist/templates/ssg/vitest.config.ts +0 -4
- package/dist/templates/ssr/package.json +2 -2
- package/dist/templates/startkit/package.json +2 -2
- package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
- package/dist/templates/startkit/tsconfig.json +2 -1
- package/dist/update.d.ts +41 -0
- package/dist/update.js +0 -2
- package/dist/writer-D8qe_7ud.js +0 -2
- package/package.json +13 -8
- package/dist/add.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/create.js.map +0 -1
- package/dist/discovery-Difb7Y4G.js.map +0 -1
- package/dist/generate.js.map +0 -1
- package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
- package/dist/openapi.js.map +0 -1
- package/dist/planner-VAj7qlxr.js.map +0 -1
- package/dist/range-YUs9eimn.js.map +0 -1
- package/dist/registry-CyrRHRG5.js.map +0 -1
- package/dist/skills-Bh0mEhIx.js.map +0 -1
- package/dist/specification-DXnDOC-0.js.map +0 -1
- package/dist/ssg.js.map +0 -1
- package/dist/templates/full-stack/src/vite-server.d.ts +0 -5
- package/dist/templates/spa/src/styles.d.ts +0 -1
- package/dist/templates/ssg/src/vite-env.d.ts +0 -5
- package/dist/templates/ssr/src/vite-server.d.ts +0 -7
- package/dist/templates/startkit/src/vite-env.d.ts +0 -5
- package/dist/update.js.map +0 -1
- package/dist/writer-D8qe_7ud.js.map +0 -1
- package/skills/askr-accessibility/SKILL.md +0 -68
- package/skills/askr-accessibility/agents/openai.yaml +0 -4
- package/skills/askr-agent-execution/SKILL.md +0 -85
- package/skills/askr-agent-execution/agents/openai.yaml +0 -4
- package/skills/askr-agent-workflows/SKILL.md +0 -57
- package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
- package/skills/askr-api-integration/SKILL.md +0 -79
- package/skills/askr-api-integration/agents/openai.yaml +0 -4
- package/skills/askr-app-builder/SKILL.md +0 -99
- package/skills/askr-app-builder/agents/openai.yaml +0 -4
- package/skills/askr-auth-access/SKILL.md +0 -74
- package/skills/askr-auth-access/agents/openai.yaml +0 -4
- package/skills/askr-cli-vite/SKILL.md +0 -76
- package/skills/askr-cli-vite/agents/openai.yaml +0 -4
- package/skills/askr-dashboard-charts/SKILL.md +0 -99
- package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
- package/skills/askr-design-system/SKILL.md +0 -86
- package/skills/askr-design-system/agents/openai.yaml +0 -4
- package/skills/askr-env-config/SKILL.md +0 -74
- package/skills/askr-env-config/agents/openai.yaml +0 -4
- package/skills/askr-error-loading-empty/SKILL.md +0 -89
- package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
- package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
- package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
- package/skills/askr-forms-tables-crud/SKILL.md +0 -98
- package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
- package/skills/askr-mental-model/SKILL.md +0 -109
- package/skills/askr-mental-model/agents/openai.yaml +0 -4
- package/skills/askr-migration-react/SKILL.md +0 -81
- package/skills/askr-migration-react/agents/openai.yaml +0 -4
- package/skills/askr-observability-debugging/SKILL.md +0 -83
- package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
- package/skills/askr-project-structure/SKILL.md +0 -79
- package/skills/askr-project-structure/agents/openai.yaml +0 -4
- package/skills/askr-query-mutation/SKILL.md +0 -115
- package/skills/askr-query-mutation/agents/openai.yaml +0 -4
- package/skills/askr-realtime-streaming/SKILL.md +0 -76
- package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
- package/skills/askr-resources-data/SKILL.md +0 -100
- package/skills/askr-resources-data/agents/openai.yaml +0 -4
- package/skills/askr-routing-layouts/SKILL.md +0 -107
- package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
- package/skills/askr-runtime-reactivity/SKILL.md +0 -92
- package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
- package/skills/askr-ssr-ssg/SKILL.md +0 -76
- package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
- package/skills/askr-testing-determinism/SKILL.md +0 -75
- package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
- package/skills/askr-theming/SKILL.md +0 -86
- package/skills/askr-theming/agents/openai.yaml +0 -4
- package/skills/askr-ui-composition/SKILL.md +0 -92
- package/skills/askr-ui-composition/agents/openai.yaml +0 -4
- package/templates/full-stack/AGENTS.md +0 -11
- package/templates/full-stack/README.md +0 -17
- package/templates/full-stack/gitignore.template +0 -4
- package/templates/full-stack/index.html +0 -13
- package/templates/full-stack/package.json +0 -39
- package/templates/full-stack/server.ts +0 -9
- package/templates/full-stack/src/action-authorizations.ts +0 -10
- package/templates/full-stack/src/actions/create-message.ts +0 -10
- package/templates/full-stack/src/i18n.ts +0 -8
- package/templates/full-stack/src/main.tsx +0 -11
- package/templates/full-stack/src/pages/home.tsx +0 -25
- package/templates/full-stack/src/pages/layout.tsx +0 -43
- package/templates/full-stack/src/pages/not-found.tsx +0 -7
- package/templates/full-stack/src/routes.tsx +0 -19
- package/templates/full-stack/src/schemas.ts +0 -10
- package/templates/full-stack/src/server/action-registry.ts +0 -8
- package/templates/full-stack/src/server/actions/create-message.ts +0 -14
- package/templates/full-stack/src/server/app.ts +0 -76
- package/templates/full-stack/src/server/dependencies.ts +0 -55
- package/templates/full-stack/src/server/entry-server.ts +0 -8
- package/templates/full-stack/src/telemetry.ts +0 -3
- package/templates/full-stack/src/vite-server.d.ts +0 -5
- package/templates/full-stack/tests/actions/create-message.test.ts +0 -12
- package/templates/full-stack/tsconfig.json +0 -15
- package/templates/full-stack/vite.config.ts +0 -10
- package/templates/spa/AGENTS.md +0 -60
- package/templates/spa/README.md +0 -96
- package/templates/spa/gitignore.template +0 -16
- package/templates/spa/index.html +0 -13
- package/templates/spa/package.json +0 -35
- package/templates/spa/src/adapters/operations-client.ts +0 -95
- package/templates/spa/src/components/shared/metric-card.tsx +0 -27
- package/templates/spa/src/components/shared/status-badge.tsx +0 -24
- package/templates/spa/src/features/operations/operations.query.ts +0 -9
- package/templates/spa/src/main.tsx +0 -10
- package/templates/spa/src/pages/_layout.tsx +0 -9
- package/templates/spa/src/pages/_routes.tsx +0 -27
- package/templates/spa/src/pages/app/_layout.tsx +0 -94
- package/templates/spa/src/pages/app/_routes.tsx +0 -10
- package/templates/spa/src/pages/app/admin-home.tsx +0 -170
- package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
- package/templates/spa/src/pages/app/settings.tsx +0 -91
- package/templates/spa/src/pages/auth/_layout.tsx +0 -38
- package/templates/spa/src/pages/auth/_routes.tsx +0 -6
- package/templates/spa/src/pages/auth/login.tsx +0 -63
- package/templates/spa/src/pages/not-found.tsx +0 -22
- package/templates/spa/src/pages/public/_layout.tsx +0 -47
- package/templates/spa/src/pages/public/_routes.tsx +0 -6
- package/templates/spa/src/pages/public/home.tsx +0 -143
- package/templates/spa/src/shared/format.ts +0 -12
- package/templates/spa/src/shared/navigation.ts +0 -15
- package/templates/spa/src/styles/components.css +0 -49
- package/templates/spa/src/styles/layout.css +0 -192
- package/templates/spa/src/styles/reset.css +0 -44
- package/templates/spa/src/styles/theme.css +0 -57
- package/templates/spa/src/styles/tokens.css +0 -20
- package/templates/spa/src/styles.css +0 -7
- package/templates/spa/src/styles.d.ts +0 -1
- package/templates/spa/tests/app.test.tsx +0 -37
- package/templates/spa/tests/components/shared.test.tsx +0 -12
- package/templates/spa/tests/resources.test.ts +0 -22
- package/templates/spa/tsconfig.json +0 -20
- package/templates/spa/tsconfig.node.json +0 -10
- package/templates/spa/vite.config.ts +0 -24
- package/templates/spa/vitest.config.ts +0 -17
- package/templates/ssg/AGENTS.md +0 -55
- package/templates/ssg/README.md +0 -39
- package/templates/ssg/gitignore.template +0 -17
- package/templates/ssg/index.html +0 -13
- package/templates/ssg/package.json +0 -35
- package/templates/ssg/src/app.tsx +0 -14
- package/templates/ssg/src/components/badge.tsx +0 -3
- package/templates/ssg/src/components/counter.tsx +0 -30
- package/templates/ssg/src/components/site-shell.tsx +0 -111
- package/templates/ssg/src/jsx.d.ts +0 -23
- package/templates/ssg/src/main.tsx +0 -8
- package/templates/ssg/src/pages/about.tsx +0 -82
- package/templates/ssg/src/pages/content.tsx +0 -63
- package/templates/ssg/src/pages/example.tsx +0 -97
- package/templates/ssg/src/pages/home.tsx +0 -51
- package/templates/ssg/src/resources/user.ts +0 -15
- package/templates/ssg/src/routes.tsx +0 -15
- package/templates/ssg/src/styles.css +0 -89
- package/templates/ssg/src/vite-env.d.ts +0 -5
- package/templates/ssg/ssg.config.ts +0 -34
- package/templates/ssg/tests/app.test.tsx +0 -19
- package/templates/ssg/tests/components/counter.test.tsx +0 -18
- package/templates/ssg/tests/resources.test.ts +0 -11
- package/templates/ssg/tests/ssg-config.test.ts +0 -11
- package/templates/ssg/tsconfig.json +0 -20
- package/templates/ssg/tsconfig.node.json +0 -10
- package/templates/ssg/vite.config.ts +0 -24
- package/templates/ssg/vitest.config.ts +0 -17
- package/templates/ssr/AGENTS.md +0 -28
- package/templates/ssr/README.md +0 -38
- package/templates/ssr/gitignore.template +0 -16
- package/templates/ssr/index.html +0 -13
- package/templates/ssr/package.json +0 -34
- package/templates/ssr/server.ts +0 -10
- package/templates/ssr/src/app.tsx +0 -21
- package/templates/ssr/src/components/counter.tsx +0 -26
- package/templates/ssr/src/entry-server.tsx +0 -12
- package/templates/ssr/src/main.tsx +0 -11
- package/templates/ssr/src/pages/about.tsx +0 -75
- package/templates/ssr/src/pages/example.tsx +0 -113
- package/templates/ssr/src/pages/home.tsx +0 -56
- package/templates/ssr/src/resources/user.ts +0 -15
- package/templates/ssr/src/routes.tsx +0 -13
- package/templates/ssr/src/styles.css +0 -148
- package/templates/ssr/src/vite-server.d.ts +0 -7
- package/templates/ssr/tests/app.test.tsx +0 -24
- package/templates/ssr/tests/components/counter.test.tsx +0 -13
- package/templates/ssr/tests/resources.test.ts +0 -11
- package/templates/ssr/tsconfig.json +0 -22
- package/templates/ssr/tsconfig.node.json +0 -10
- package/templates/ssr/tsconfig.server.json +0 -15
- package/templates/ssr/vite.config.ts +0 -25
- package/templates/ssr/vitest.config.ts +0 -13
- package/templates/startkit/AGENTS.md +0 -77
- package/templates/startkit/README.md +0 -192
- package/templates/startkit/gitignore.template +0 -16
- package/templates/startkit/index.html +0 -13
- package/templates/startkit/package.json +0 -35
- package/templates/startkit/src/components/app-header.tsx +0 -93
- package/templates/startkit/src/components/app-sidebar.tsx +0 -95
- package/templates/startkit/src/components/data-table.tsx +0 -80
- package/templates/startkit/src/components/empty-state.tsx +0 -13
- package/templates/startkit/src/components/page-header.tsx +0 -23
- package/templates/startkit/src/components/stat-card.tsx +0 -24
- package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
- package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
- package/templates/startkit/src/lib/format.ts +0 -31
- package/templates/startkit/src/lib/mock-data.ts +0 -441
- package/templates/startkit/src/lib/routes.ts +0 -116
- package/templates/startkit/src/main.tsx +0 -12
- package/templates/startkit/src/pages/_layout.tsx +0 -56
- package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
- package/templates/startkit/src/pages/auth/login.tsx +0 -129
- package/templates/startkit/src/pages/home.tsx +0 -83
- package/templates/startkit/src/pages/not-found.tsx +0 -24
- package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
- package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
- package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
- package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
- package/templates/startkit/src/router.tsx +0 -7
- package/templates/startkit/src/routes/auth-config.ts +0 -38
- package/templates/startkit/src/routes/auth.ts +0 -8
- package/templates/startkit/src/routes/index.ts +0 -28
- package/templates/startkit/src/routes/public.ts +0 -8
- package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
- package/templates/startkit/src/routes/workspace/index.ts +0 -14
- package/templates/startkit/src/styles/components.css +0 -396
- package/templates/startkit/src/styles/layout.css +0 -192
- package/templates/startkit/src/styles/reset.css +0 -38
- package/templates/startkit/src/styles/theme.css +0 -76
- package/templates/startkit/src/styles/tokens.css +0 -67
- package/templates/startkit/src/styles.css +0 -7
- package/templates/startkit/src/toast.ts +0 -55
- package/templates/startkit/src/utils/join-classes.ts +0 -4
- package/templates/startkit/src/vite-env.d.ts +0 -5
- package/templates/startkit/tests/app.test.tsx +0 -32
- package/templates/startkit/tests/preferences.test.ts +0 -43
- package/templates/startkit/tests/resources.test.ts +0 -82
- package/templates/startkit/tsconfig.json +0 -20
- package/templates/startkit/tsconfig.node.json +0 -10
- package/templates/startkit/vite.config.ts +0 -32
- package/templates/startkit/vitest.config.ts +0 -13
package/README.md
CHANGED
|
@@ -50,6 +50,43 @@ unless you opt out with `--no-skills`.
|
|
|
50
50
|
The installed command is `askr`. Subcommands are intentionally not published
|
|
51
51
|
as compatibility binaries.
|
|
52
52
|
|
|
53
|
+
## Static sitemap generation
|
|
54
|
+
|
|
55
|
+
`askr ssg` writes `sitemap.xml` from the concrete routes generated during the
|
|
56
|
+
build. Set the canonical deploy URL in the TypeScript config:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
export const staticConfig = {
|
|
60
|
+
registry,
|
|
61
|
+
outputDir: "./dist",
|
|
62
|
+
siteUrl: "https://example.com",
|
|
63
|
+
sitemap: {
|
|
64
|
+
defaults: { changeFrequency: "weekly" },
|
|
65
|
+
routes: {
|
|
66
|
+
"/404": false,
|
|
67
|
+
"/docs": { priority: 0.8, lastModified: "2026-07-18" },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The sitemap config types are available from `@askrjs/cli/ssg` for projects that
|
|
74
|
+
want an explicit annotation.
|
|
75
|
+
|
|
76
|
+
Successful and incrementally skipped concrete routes are included by default.
|
|
77
|
+
Failed routes and wildcard templates are excluded. Route settings support a
|
|
78
|
+
canonical URL override, `lastModified`, `changeFrequency`, `priority`, and
|
|
79
|
+
`hreflang` alternates. Use `resolve(route)` for data-driven metadata or return
|
|
80
|
+
`false` to exclude a route. Set `sitemap: false` for an intentional opt-out.
|
|
81
|
+
|
|
82
|
+
The CLI validates real calendar dates, bounds asynchronous metadata resolution,
|
|
83
|
+
and enforces the sitemap protocol limits of 50,000 URLs and 50 MB per file.
|
|
84
|
+
Larger sites receive deterministic sitemap chunks plus a sitemap index. It also
|
|
85
|
+
creates or updates `robots.txt` while preserving unrelated directives and tracks
|
|
86
|
+
owned files so stale chunks and previous output paths are removed. Full and
|
|
87
|
+
incremental builds publish through a sibling staging directory, so route output,
|
|
88
|
+
metadata, assets, and sitemap artifacts change together or not at all.
|
|
89
|
+
|
|
53
90
|
## OpenAPI artifacts
|
|
54
91
|
|
|
55
92
|
`askr openapi` loads a TypeScript module whose default export exposes
|
package/dist/add.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/file-changes.d.ts
|
|
2
|
+
interface FileChange {
|
|
3
|
+
readonly filePath: string;
|
|
4
|
+
readonly content: string;
|
|
5
|
+
}
|
|
6
|
+
interface FileChangeWriterOptions {
|
|
7
|
+
readonly replace?: (temporaryPath: string, filePath: string) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
declare function writeFileChanges(changes: readonly FileChange[], options?: FileChangeWriterOptions): Promise<void>;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/bin/add.d.ts
|
|
12
|
+
type CliIo = Pick<Console, "error" | "log">;
|
|
13
|
+
type WriteChanges = typeof writeFileChanges;
|
|
14
|
+
declare function runAddCli(args?: string[], io?: CliIo, writeChanges?: WriteChanges): Promise<number>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { runAddCli };
|
package/dist/add.js
CHANGED
|
@@ -142,32 +142,34 @@ function parseArgs(args) {
|
|
|
142
142
|
const arg = args[index];
|
|
143
143
|
if (arg === "--help" || arg === "-h") parsed.help = true;
|
|
144
144
|
else if (arg === "--force") parsed.force = true;
|
|
145
|
-
else if (arg === "--branch") if (index + 1 >= args.length) parsed.errors.push("Missing value for --branch");
|
|
145
|
+
else if (arg === "--branch") if (index + 1 >= args.length || args[index + 1].startsWith("-")) parsed.errors.push("Missing value for --branch");
|
|
146
146
|
else {
|
|
147
147
|
parsed.branch = args[index + 1];
|
|
148
148
|
index += 1;
|
|
149
149
|
}
|
|
150
|
-
else if (arg === "--cwd") if (index + 1 >= args.length) parsed.errors.push("Missing value for --cwd");
|
|
150
|
+
else if (arg === "--cwd") if (index + 1 >= args.length || args[index + 1].startsWith("-")) parsed.errors.push("Missing value for --cwd");
|
|
151
151
|
else {
|
|
152
152
|
parsed.cwd = args[index + 1];
|
|
153
153
|
index += 1;
|
|
154
154
|
}
|
|
155
|
-
else if (arg === "--title") if (index + 1 >= args.length) parsed.errors.push("Missing value for --title");
|
|
155
|
+
else if (arg === "--title") if (index + 1 >= args.length || args[index + 1].startsWith("-")) parsed.errors.push("Missing value for --title");
|
|
156
156
|
else {
|
|
157
157
|
parsed.title = args[index + 1].trim();
|
|
158
158
|
index += 1;
|
|
159
159
|
}
|
|
160
|
-
else if (arg === "--route") if (index + 1 >= args.length) parsed.errors.push("Missing value for --route");
|
|
160
|
+
else if (arg === "--route") if (index + 1 >= args.length || args[index + 1].startsWith("-")) parsed.errors.push("Missing value for --route");
|
|
161
161
|
else {
|
|
162
162
|
parsed.routePath = args[index + 1].trim();
|
|
163
163
|
index += 1;
|
|
164
164
|
}
|
|
165
|
+
else if (arg.startsWith("-")) parsed.errors.push(`Unknown option: ${arg}`);
|
|
165
166
|
else positional.push(arg);
|
|
166
167
|
}
|
|
167
168
|
return {
|
|
168
169
|
...parsed,
|
|
169
170
|
command: positional[0] || "",
|
|
170
|
-
name: positional[1] || ""
|
|
171
|
+
name: positional[1] || "",
|
|
172
|
+
positionals: positional
|
|
171
173
|
};
|
|
172
174
|
}
|
|
173
175
|
async function pathExists(filePath) {
|
|
@@ -322,16 +324,12 @@ function toImportSpecifier(fromFile, toFile) {
|
|
|
322
324
|
}
|
|
323
325
|
function createUpdatedRouteFile(routeFileContent, options) {
|
|
324
326
|
const normalized = routeFileContent.replace(/\r\n/g, "\n");
|
|
325
|
-
const lines = normalized.split("\n");
|
|
326
|
-
const lastImportIndex = lines.reduce((currentIndex, line, index) => line.startsWith("import ") ? index : currentIndex, -1);
|
|
327
|
-
if (lastImportIndex === -1) throw new Error("Unsupported route file: could not find import block.");
|
|
328
327
|
const importLine = `import ${options.componentName} from '${options.importSpecifier}';`;
|
|
329
328
|
if (normalized.includes(importLine) || normalized.includes(`route('${options.routePath}',`) || normalized.includes(`route("${options.routePath}",`)) throw new Error(`Route '${options.routePath}' is already registered.`);
|
|
330
|
-
|
|
331
|
-
const
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
return `${lines.join("\n")}\n`;
|
|
329
|
+
const importMarker = "// askr:imports";
|
|
330
|
+
const routeMarker = " // askr:routes";
|
|
331
|
+
if (normalized.split(importMarker).length !== 2 || normalized.split(routeMarker).length !== 2) throw new Error("Unsupported route file: expected exactly one // askr:imports and // askr:routes marker.");
|
|
332
|
+
return `${normalized.replace(importMarker, `${importMarker}\n${importLine}`).replace(routeMarker, `${routeMarker}\n route('${options.routePath}', ${options.componentName});`).replace(/\n+$/, "")}\n`;
|
|
335
333
|
}
|
|
336
334
|
function renderPageFile(options) {
|
|
337
335
|
return [
|
|
@@ -378,7 +376,7 @@ function renderPageFile(options) {
|
|
|
378
376
|
""
|
|
379
377
|
].join("\n");
|
|
380
378
|
}
|
|
381
|
-
async function addPage(parsed, io) {
|
|
379
|
+
async function addPage(parsed, io, writeChanges) {
|
|
382
380
|
if (!parsed.name) {
|
|
383
381
|
io.error("Page name is required.");
|
|
384
382
|
return 1;
|
|
@@ -429,14 +427,18 @@ async function addPage(parsed, io) {
|
|
|
429
427
|
return 1;
|
|
430
428
|
}
|
|
431
429
|
try {
|
|
432
|
-
await
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
430
|
+
await writeChanges([{
|
|
431
|
+
filePath: pageFile,
|
|
432
|
+
content: renderPageFile({
|
|
433
|
+
badge: branchConfig.badge,
|
|
434
|
+
componentName,
|
|
435
|
+
routePath,
|
|
436
|
+
title
|
|
437
|
+
})
|
|
438
|
+
}, {
|
|
439
|
+
filePath: routesFile,
|
|
440
|
+
content: updatedRoutes
|
|
441
|
+
}]);
|
|
440
442
|
} catch (error) {
|
|
441
443
|
io.error("Failed to write generated page artifacts.");
|
|
442
444
|
io.error(error instanceof Error ? error.message : String(error));
|
|
@@ -448,7 +450,7 @@ async function addPage(parsed, io) {
|
|
|
448
450
|
io.log(` Router: ${path.relative(projectRoot, routesFile).replace(/\\/g, "/")}`);
|
|
449
451
|
return 0;
|
|
450
452
|
}
|
|
451
|
-
async function addAction(parsed, io) {
|
|
453
|
+
async function addAction(parsed, io, writeChanges) {
|
|
452
454
|
if (!parsed.name) {
|
|
453
455
|
io.error("Action name is required.");
|
|
454
456
|
return 1;
|
|
@@ -489,7 +491,7 @@ async function addAction(parsed, io) {
|
|
|
489
491
|
filePath: descriptorFile,
|
|
490
492
|
content: descriptor
|
|
491
493
|
});
|
|
492
|
-
await
|
|
494
|
+
await writeChanges([
|
|
493
495
|
{
|
|
494
496
|
filePath: descriptorFile,
|
|
495
497
|
content: descriptor
|
|
@@ -529,7 +531,7 @@ async function addAction(parsed, io) {
|
|
|
529
531
|
io.log(` Test: ${path.relative(projectRoot, testFile).replace(/\\/g, "/")}`);
|
|
530
532
|
return 0;
|
|
531
533
|
}
|
|
532
|
-
async function runAddCli(args = process.argv.slice(2), io = console) {
|
|
534
|
+
async function runAddCli(args = process.argv.slice(2), io = console, writeChanges = writeFileChanges) {
|
|
533
535
|
const parsed = parseArgs(args);
|
|
534
536
|
if (parsed.errors.length > 0) {
|
|
535
537
|
for (const message of parsed.errors) io.error(message);
|
|
@@ -539,8 +541,12 @@ async function runAddCli(args = process.argv.slice(2), io = console) {
|
|
|
539
541
|
io.log(helpText());
|
|
540
542
|
return 0;
|
|
541
543
|
}
|
|
542
|
-
if (parsed.
|
|
543
|
-
|
|
544
|
+
if (parsed.positionals.length !== 2 || !parsed.name) {
|
|
545
|
+
io.error("A command and exactly one generator name are required.");
|
|
546
|
+
return 1;
|
|
547
|
+
}
|
|
548
|
+
if (parsed.command === "page") return addPage(parsed, io, writeChanges);
|
|
549
|
+
if (parsed.command === "action") return addAction(parsed, io, writeChanges);
|
|
544
550
|
io.error(`Unknown add command: ${parsed.command}`);
|
|
545
551
|
io.error("Run `askr add --help` to see available commands.");
|
|
546
552
|
return 1;
|
|
@@ -552,5 +558,3 @@ async function main() {
|
|
|
552
558
|
if (isDirectExecution(import.meta.url)) main();
|
|
553
559
|
//#endregion
|
|
554
560
|
export { runAddCli };
|
|
555
|
-
|
|
556
|
-
//# sourceMappingURL=add.js.map
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
CHANGED
package/dist/create.d.ts
ADDED
package/dist/create.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as isDirectExecution } from "./is-direct-execution-Cdlr-ZUl.js";
|
|
3
|
-
import { t as installBundledSkills } from "./skills-
|
|
3
|
+
import { t as installBundledSkills } from "./skills-B7CbWur9.js";
|
|
4
|
+
import { n as publishStagedDirectory, t as createSiblingStage } from "./directory-swap-DWoHtx7C.js";
|
|
4
5
|
import fs from "node:fs/promises";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
7
8
|
import { spawnSync } from "node:child_process";
|
|
9
|
+
import { isUtf8 } from "node:buffer";
|
|
8
10
|
import readline from "node:readline";
|
|
9
11
|
//#region src/bin/create.ts
|
|
10
12
|
const TEMPLATE_LABELS = {
|
|
@@ -396,8 +398,8 @@ const TEMPLATE_INSPECT_PATHS = {
|
|
|
396
398
|
ssr: [
|
|
397
399
|
"AGENTS.md",
|
|
398
400
|
"src/main.tsx",
|
|
399
|
-
"src/server
|
|
400
|
-
"src/
|
|
401
|
+
"src/entry-server.tsx",
|
|
402
|
+
"src/routes.tsx",
|
|
401
403
|
"server.ts"
|
|
402
404
|
],
|
|
403
405
|
ssg: [
|
|
@@ -432,7 +434,7 @@ const TEMPLATE_GOLDEN_EXAMPLES = {
|
|
|
432
434
|
],
|
|
433
435
|
ssr: [
|
|
434
436
|
"src/main.tsx",
|
|
435
|
-
"src/
|
|
437
|
+
"src/routes.tsx",
|
|
436
438
|
"server.ts"
|
|
437
439
|
],
|
|
438
440
|
ssg: [
|
|
@@ -462,7 +464,7 @@ function helpText() {
|
|
|
462
464
|
"askr create - Project scaffolding for Askr",
|
|
463
465
|
"",
|
|
464
466
|
"Usage:",
|
|
465
|
-
" askr create [template] <name> [--prompt <text>] [--no-install] [--no-skills]",
|
|
467
|
+
" askr create [template] <name> [--dir <path>] [--prompt <text>] [--no-install] [--no-skills]",
|
|
466
468
|
" askr create --prompt <text> [name] [--no-install] [--no-skills]",
|
|
467
469
|
"",
|
|
468
470
|
"Templates:",
|
|
@@ -470,6 +472,7 @@ function helpText() {
|
|
|
470
472
|
"",
|
|
471
473
|
"Options:",
|
|
472
474
|
" --prompt <text> Infer the best template from a product prompt and emit a builder blueprint",
|
|
475
|
+
" --dir <path> Explicit output directory (defaults to ./<name>)",
|
|
473
476
|
" --no-install Skip dependency installation",
|
|
474
477
|
" --no-skills Skip bundled Askr skill installation into skills/",
|
|
475
478
|
" --help, -h Show help",
|
|
@@ -495,6 +498,8 @@ async function prompt(question) {
|
|
|
495
498
|
}
|
|
496
499
|
function detectPm() {
|
|
497
500
|
const ua = process.env.npm_config_user_agent || "";
|
|
501
|
+
if (ua.startsWith("pnpm")) return "pnpm";
|
|
502
|
+
if (ua.startsWith("bun")) return "bun";
|
|
498
503
|
if (ua.startsWith("yarn")) return "yarn";
|
|
499
504
|
if (ua.startsWith("npm")) return "npm";
|
|
500
505
|
return "npm";
|
|
@@ -522,7 +527,12 @@ async function copyDir(src, dest, replacements) {
|
|
|
522
527
|
await copyDir(srcPath, destPath, replacements);
|
|
523
528
|
continue;
|
|
524
529
|
}
|
|
525
|
-
const
|
|
530
|
+
const buffer = await fs.readFile(srcPath);
|
|
531
|
+
if (!isUtf8(buffer)) {
|
|
532
|
+
await fs.writeFile(destPath, buffer);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
const replaced = buffer.toString("utf8").replace(/\{\{\s*appName\s*\}\}/g, replacements.appName).replace(/\{\{appName\}\}/g, replacements.appName);
|
|
526
536
|
await fs.writeFile(destPath, replaced, "utf8");
|
|
527
537
|
}
|
|
528
538
|
}
|
|
@@ -548,17 +558,24 @@ function parseArgs(args) {
|
|
|
548
558
|
let help = false;
|
|
549
559
|
let promptText = "";
|
|
550
560
|
let skills = true;
|
|
561
|
+
let targetDir = "";
|
|
551
562
|
const errors = [];
|
|
552
563
|
for (let i = 0; i < args.length; i += 1) {
|
|
553
564
|
const arg = args[i];
|
|
554
565
|
if (arg === "--no-install") install = false;
|
|
555
566
|
else if (arg === "--no-skills") skills = false;
|
|
556
|
-
else if (arg === "--prompt") if (i + 1 >= args.length) errors.push("Missing value for --prompt");
|
|
567
|
+
else if (arg === "--prompt") if (i + 1 >= args.length || args[i + 1].startsWith("-")) errors.push("Missing value for --prompt");
|
|
557
568
|
else {
|
|
558
569
|
promptText = normalizePromptText(args[i + 1]);
|
|
559
570
|
i += 1;
|
|
560
571
|
}
|
|
572
|
+
else if (arg === "--dir") if (i + 1 >= args.length || args[i + 1].startsWith("-")) errors.push("Missing value for --dir");
|
|
573
|
+
else {
|
|
574
|
+
targetDir = args[i + 1];
|
|
575
|
+
i += 1;
|
|
576
|
+
}
|
|
561
577
|
else if (arg === "--help" || arg === "-h") help = true;
|
|
578
|
+
else if (arg.startsWith("-")) errors.push(`Unknown option: ${arg}`);
|
|
562
579
|
else positional.push(arg);
|
|
563
580
|
}
|
|
564
581
|
return {
|
|
@@ -567,9 +584,15 @@ function parseArgs(args) {
|
|
|
567
584
|
help,
|
|
568
585
|
promptText,
|
|
569
586
|
skills,
|
|
570
|
-
errors
|
|
587
|
+
errors,
|
|
588
|
+
targetDir
|
|
571
589
|
};
|
|
572
590
|
}
|
|
591
|
+
function validateAppName(name) {
|
|
592
|
+
if (name.length > 214) return "App name must be 214 characters or fewer";
|
|
593
|
+
if (!/^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/.test(name)) return "App name must be a lowercase npm package name without path separators";
|
|
594
|
+
if (/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])$/.test(name)) return `App name is reserved on Windows: ${name}`;
|
|
595
|
+
}
|
|
573
596
|
function normalizePromptText(promptText) {
|
|
574
597
|
return promptText.trim().replace(/\s+/g, " ");
|
|
575
598
|
}
|
|
@@ -810,7 +833,17 @@ async function runCreateCli(args = process.argv.slice(2), io = console) {
|
|
|
810
833
|
io.error("App name is required");
|
|
811
834
|
return 1;
|
|
812
835
|
}
|
|
813
|
-
const
|
|
836
|
+
const nameError = validateAppName(name);
|
|
837
|
+
if (nameError) {
|
|
838
|
+
io.error(nameError);
|
|
839
|
+
return 1;
|
|
840
|
+
}
|
|
841
|
+
const expectedPositionals = explicitTemplate ? 2 : 1;
|
|
842
|
+
if (parsed.positional.length > expectedPositionals) {
|
|
843
|
+
io.error("Too many positional arguments");
|
|
844
|
+
return 1;
|
|
845
|
+
}
|
|
846
|
+
const target = path.resolve(process.cwd(), parsed.targetDir || name);
|
|
814
847
|
const templateDir = await findTemplateDir(templateType);
|
|
815
848
|
try {
|
|
816
849
|
await fs.access(templateDir);
|
|
@@ -819,7 +852,12 @@ async function runCreateCli(args = process.argv.slice(2), io = console) {
|
|
|
819
852
|
return 1;
|
|
820
853
|
}
|
|
821
854
|
try {
|
|
822
|
-
|
|
855
|
+
const stat = await fs.stat(target).catch(() => null);
|
|
856
|
+
if (stat) {
|
|
857
|
+
if (!stat.isDirectory()) {
|
|
858
|
+
io.error(`Target exists and is not a directory: ${target}`);
|
|
859
|
+
return 1;
|
|
860
|
+
}
|
|
823
861
|
if ((await fs.readdir(target).catch(() => [])).length > 0) {
|
|
824
862
|
io.error(`Directory ${target} already exists and is not empty.`);
|
|
825
863
|
return 1;
|
|
@@ -844,28 +882,48 @@ async function runCreateCli(args = process.argv.slice(2), io = console) {
|
|
|
844
882
|
}
|
|
845
883
|
io.log(`Creating ${TEMPLATE_LABELS[templateType]} project: ${name}...`);
|
|
846
884
|
io.log("");
|
|
885
|
+
let stagingTarget;
|
|
886
|
+
try {
|
|
887
|
+
stagingTarget = await createSiblingStage(target, "askr-create");
|
|
888
|
+
} catch (error) {
|
|
889
|
+
io.error("Failed to prepare project output");
|
|
890
|
+
io.error(error instanceof Error ? error.message : String(error));
|
|
891
|
+
return 1;
|
|
892
|
+
}
|
|
847
893
|
try {
|
|
848
|
-
await copyDir(templateDir,
|
|
894
|
+
await copyDir(templateDir, stagingTarget, { appName: name });
|
|
849
895
|
} catch (error) {
|
|
896
|
+
await fs.rm(stagingTarget, {
|
|
897
|
+
recursive: true,
|
|
898
|
+
force: true
|
|
899
|
+
});
|
|
850
900
|
io.error("Failed to copy template");
|
|
851
901
|
io.error(error instanceof Error ? error.message : String(error));
|
|
852
902
|
return 1;
|
|
853
903
|
}
|
|
854
904
|
try {
|
|
855
|
-
await writeBlueprintFiles(
|
|
905
|
+
await writeBlueprintFiles(stagingTarget, blueprint);
|
|
856
906
|
} catch (error) {
|
|
907
|
+
await fs.rm(stagingTarget, {
|
|
908
|
+
recursive: true,
|
|
909
|
+
force: true
|
|
910
|
+
});
|
|
857
911
|
io.error("Failed to write project blueprint");
|
|
858
912
|
io.error(error instanceof Error ? error.message : String(error));
|
|
859
913
|
return 1;
|
|
860
914
|
}
|
|
861
915
|
if (parsed.skills) try {
|
|
862
916
|
const { bundledNames, targetSkillsDir } = await installBundledSkills({
|
|
863
|
-
cwd:
|
|
917
|
+
cwd: stagingTarget,
|
|
864
918
|
force: true
|
|
865
919
|
});
|
|
866
920
|
io.log(`Installed ${bundledNames.length} bundled Askr skills into ${path.basename(targetSkillsDir)}/`);
|
|
867
921
|
io.log("");
|
|
868
922
|
} catch (error) {
|
|
923
|
+
await fs.rm(stagingTarget, {
|
|
924
|
+
recursive: true,
|
|
925
|
+
force: true
|
|
926
|
+
});
|
|
869
927
|
io.error("Failed to install bundled Askr skills");
|
|
870
928
|
io.error(error instanceof Error ? error.message : String(error));
|
|
871
929
|
return 1;
|
|
@@ -874,35 +932,57 @@ async function runCreateCli(args = process.argv.slice(2), io = console) {
|
|
|
874
932
|
io.log("Skipping bundled Askr skill installation (--no-skills)");
|
|
875
933
|
io.log("");
|
|
876
934
|
}
|
|
935
|
+
const pm = detectPm();
|
|
877
936
|
if (!parsed.install) {
|
|
937
|
+
try {
|
|
938
|
+
await publishStagedDirectory(stagingTarget, target);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
await fs.rm(stagingTarget, {
|
|
941
|
+
recursive: true,
|
|
942
|
+
force: true
|
|
943
|
+
});
|
|
944
|
+
io.error("Failed to publish generated project");
|
|
945
|
+
io.error(error instanceof Error ? error.message : String(error));
|
|
946
|
+
return 1;
|
|
947
|
+
}
|
|
878
948
|
io.log("Skipping dependency installation (--no-install)");
|
|
879
949
|
io.log("");
|
|
880
950
|
io.log("Next steps:");
|
|
881
951
|
io.log(` cd ${name}`);
|
|
882
952
|
io.log(" review .askr/builder-brief.md");
|
|
883
953
|
if (!parsed.skills) io.log(" askr skills install");
|
|
884
|
-
io.log(
|
|
885
|
-
io.log(
|
|
954
|
+
io.log(` ${pm} install`);
|
|
955
|
+
io.log(` ${pm} run dev`);
|
|
886
956
|
return 0;
|
|
887
957
|
}
|
|
888
|
-
const pm = detectPm();
|
|
889
958
|
io.log(`Installing dependencies with ${pm}...`);
|
|
890
959
|
io.log("");
|
|
891
960
|
const result = spawnSync(pm, ["install"], {
|
|
892
|
-
cwd:
|
|
961
|
+
cwd: stagingTarget,
|
|
893
962
|
stdio: "inherit",
|
|
894
963
|
shell: process.platform === "win32"
|
|
895
964
|
});
|
|
965
|
+
if (result.status !== 0) {
|
|
966
|
+
await fs.rm(stagingTarget, {
|
|
967
|
+
recursive: true,
|
|
968
|
+
force: true
|
|
969
|
+
});
|
|
970
|
+
io.error(`Dependency installation with ${pm} failed; no project files were published.`);
|
|
971
|
+
if (result.error) io.error(result.error.message);
|
|
972
|
+
return 1;
|
|
973
|
+
}
|
|
896
974
|
io.log("");
|
|
897
975
|
io.log(`Success! Created ${name}`);
|
|
898
976
|
io.log("");
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
977
|
+
try {
|
|
978
|
+
await publishStagedDirectory(stagingTarget, target);
|
|
979
|
+
} catch (error) {
|
|
980
|
+
await fs.rm(stagingTarget, {
|
|
981
|
+
recursive: true,
|
|
982
|
+
force: true
|
|
983
|
+
});
|
|
984
|
+
io.error("Failed to publish generated project");
|
|
985
|
+
io.error(error instanceof Error ? error.message : String(error));
|
|
906
986
|
return 1;
|
|
907
987
|
}
|
|
908
988
|
io.log("Next steps:");
|
|
@@ -919,5 +999,3 @@ async function main() {
|
|
|
919
999
|
if (isDirectExecution(import.meta.url)) main();
|
|
920
1000
|
//#endregion
|
|
921
1001
|
export { runCreateCli };
|
|
922
|
-
|
|
923
|
-
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
//#region src/directory-swap.ts
|
|
5
|
+
async function exists(target) {
|
|
6
|
+
return Boolean(await fs.stat(target).catch(() => null));
|
|
7
|
+
}
|
|
8
|
+
async function createSiblingStage(target, label) {
|
|
9
|
+
const resolved = path.resolve(target);
|
|
10
|
+
const parent = path.dirname(resolved);
|
|
11
|
+
await fs.mkdir(parent, { recursive: true });
|
|
12
|
+
return fs.mkdtemp(path.join(parent, `.${path.basename(resolved)}.${label}-`));
|
|
13
|
+
}
|
|
14
|
+
async function publishStagedDirectory(stage, target) {
|
|
15
|
+
const resolvedTarget = path.resolve(target);
|
|
16
|
+
const backup = path.join(path.dirname(resolvedTarget), `.${path.basename(resolvedTarget)}.askr-backup-${randomUUID()}`);
|
|
17
|
+
const hadTarget = await exists(resolvedTarget);
|
|
18
|
+
let movedTarget = false;
|
|
19
|
+
try {
|
|
20
|
+
if (hadTarget) {
|
|
21
|
+
await fs.rename(resolvedTarget, backup);
|
|
22
|
+
movedTarget = true;
|
|
23
|
+
}
|
|
24
|
+
await fs.rename(stage, resolvedTarget);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (movedTarget && !await exists(resolvedTarget) && await exists(backup)) await fs.rename(backup, resolvedTarget);
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
if (movedTarget) await fs.rm(backup, {
|
|
30
|
+
recursive: true,
|
|
31
|
+
force: true
|
|
32
|
+
}).catch(() => void 0);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { publishStagedDirectory as n, createSiblingStage as t };
|