@askrjs/cli 0.0.2
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/LICENSE +201 -0
- package/README.md +140 -0
- package/dist/add-DqhqRzBQ.js +555 -0
- package/dist/add-DqhqRzBQ.js.map +1 -0
- package/dist/add.js +3 -0
- package/dist/cli.js +91 -0
- package/dist/cli.js.map +1 -0
- package/dist/create.js +923 -0
- package/dist/create.js.map +1 -0
- package/dist/is-direct-execution-Cdlr-ZUl.js +20 -0
- package/dist/is-direct-execution-Cdlr-ZUl.js.map +1 -0
- package/dist/openapi.js +127 -0
- package/dist/openapi.js.map +1 -0
- package/dist/skills/askr-accessibility/SKILL.md +68 -0
- package/dist/skills/askr-accessibility/agents/openai.yaml +4 -0
- package/dist/skills/askr-agent-execution/SKILL.md +85 -0
- package/dist/skills/askr-agent-execution/agents/openai.yaml +4 -0
- package/dist/skills/askr-agent-workflows/SKILL.md +57 -0
- package/dist/skills/askr-agent-workflows/agents/openai.yaml +4 -0
- package/dist/skills/askr-api-integration/SKILL.md +79 -0
- package/dist/skills/askr-api-integration/agents/openai.yaml +4 -0
- package/dist/skills/askr-app-builder/SKILL.md +99 -0
- package/dist/skills/askr-app-builder/agents/openai.yaml +4 -0
- package/dist/skills/askr-auth-access/SKILL.md +74 -0
- package/dist/skills/askr-auth-access/agents/openai.yaml +4 -0
- package/dist/skills/askr-cli-vite/SKILL.md +76 -0
- package/dist/skills/askr-cli-vite/agents/openai.yaml +4 -0
- package/dist/skills/askr-dashboard-charts/SKILL.md +82 -0
- package/dist/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
- package/dist/skills/askr-design-system/SKILL.md +86 -0
- package/dist/skills/askr-design-system/agents/openai.yaml +4 -0
- package/dist/skills/askr-env-config/SKILL.md +74 -0
- package/dist/skills/askr-env-config/agents/openai.yaml +4 -0
- package/dist/skills/askr-error-loading-empty/SKILL.md +89 -0
- package/dist/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
- package/dist/skills/askr-file-upload-artifacts/SKILL.md +77 -0
- package/dist/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
- package/dist/skills/askr-forms-tables-crud/SKILL.md +98 -0
- package/dist/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
- package/dist/skills/askr-mental-model/SKILL.md +109 -0
- package/dist/skills/askr-mental-model/agents/openai.yaml +4 -0
- package/dist/skills/askr-migration-react/SKILL.md +81 -0
- package/dist/skills/askr-migration-react/agents/openai.yaml +4 -0
- package/dist/skills/askr-observability-debugging/SKILL.md +83 -0
- package/dist/skills/askr-observability-debugging/agents/openai.yaml +4 -0
- package/dist/skills/askr-project-structure/SKILL.md +79 -0
- package/dist/skills/askr-project-structure/agents/openai.yaml +4 -0
- package/dist/skills/askr-query-mutation/SKILL.md +115 -0
- package/dist/skills/askr-query-mutation/agents/openai.yaml +4 -0
- package/dist/skills/askr-realtime-streaming/SKILL.md +76 -0
- package/dist/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
- package/dist/skills/askr-resources-data/SKILL.md +100 -0
- package/dist/skills/askr-resources-data/agents/openai.yaml +4 -0
- package/dist/skills/askr-routing-layouts/SKILL.md +107 -0
- package/dist/skills/askr-routing-layouts/agents/openai.yaml +4 -0
- package/dist/skills/askr-runtime-reactivity/SKILL.md +92 -0
- package/dist/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
- package/dist/skills/askr-ssr-ssg/SKILL.md +76 -0
- package/dist/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
- package/dist/skills/askr-testing-determinism/SKILL.md +75 -0
- package/dist/skills/askr-testing-determinism/agents/openai.yaml +4 -0
- package/dist/skills/askr-theming/SKILL.md +86 -0
- package/dist/skills/askr-theming/agents/openai.yaml +4 -0
- package/dist/skills/askr-ui-composition/SKILL.md +92 -0
- package/dist/skills/askr-ui-composition/agents/openai.yaml +4 -0
- package/dist/skills-Bh0mEhIx.js +682 -0
- package/dist/skills-Bh0mEhIx.js.map +1 -0
- package/dist/skills.js +3 -0
- package/dist/ssg.js +188 -0
- package/dist/ssg.js.map +1 -0
- package/dist/templates/full-stack/AGENTS.md +12 -0
- package/dist/templates/full-stack/README.md +18 -0
- package/dist/templates/full-stack/gitignore.template +4 -0
- package/dist/templates/full-stack/index.html +14 -0
- package/dist/templates/full-stack/package.json +37 -0
- package/dist/templates/full-stack/server.ts +13 -0
- package/dist/templates/full-stack/src/action-authorizations.ts +10 -0
- package/dist/templates/full-stack/src/actions/create-message.ts +10 -0
- package/dist/templates/full-stack/src/i18n.ts +8 -0
- package/dist/templates/full-stack/src/main.tsx +12 -0
- package/dist/templates/full-stack/src/pages/home.tsx +25 -0
- package/dist/templates/full-stack/src/pages/layout.tsx +33 -0
- package/dist/templates/full-stack/src/pages/not-found.tsx +4 -0
- package/dist/templates/full-stack/src/routes.tsx +20 -0
- package/dist/templates/full-stack/src/schemas.ts +11 -0
- package/dist/templates/full-stack/src/server/action-registry.ts +12 -0
- package/dist/templates/full-stack/src/server/actions/create-message.ts +14 -0
- package/dist/templates/full-stack/src/server/app.ts +66 -0
- package/dist/templates/full-stack/src/server/dependencies.ts +55 -0
- package/dist/templates/full-stack/src/server/entry-server.ts +8 -0
- package/dist/templates/full-stack/src/telemetry.ts +4 -0
- package/dist/templates/full-stack/src/vite-server.d.ts +6 -0
- package/dist/templates/full-stack/tests/actions/create-message.test.ts +13 -0
- package/dist/templates/full-stack/tsconfig.json +16 -0
- package/dist/templates/full-stack/vite.config.ts +11 -0
- package/dist/templates/spa/AGENTS.md +60 -0
- package/dist/templates/spa/README.md +96 -0
- package/dist/templates/spa/gitignore.template +16 -0
- package/dist/templates/spa/index.html +13 -0
- package/dist/templates/spa/package.json +35 -0
- package/dist/templates/spa/src/adapters/operations-client.ts +90 -0
- package/dist/templates/spa/src/components/shared/metric-card.tsx +27 -0
- package/dist/templates/spa/src/components/shared/status-badge.tsx +24 -0
- package/dist/templates/spa/src/features/operations/operations.query.ts +9 -0
- package/dist/templates/spa/src/main.tsx +10 -0
- package/dist/templates/spa/src/pages/_layout.tsx +9 -0
- package/dist/templates/spa/src/pages/_routes.tsx +27 -0
- package/dist/templates/spa/src/pages/app/_layout.tsx +94 -0
- package/dist/templates/spa/src/pages/app/_routes.tsx +10 -0
- package/dist/templates/spa/src/pages/app/admin-home.tsx +152 -0
- package/dist/templates/spa/src/pages/app/agent-runs.tsx +93 -0
- package/dist/templates/spa/src/pages/app/settings.tsx +91 -0
- package/dist/templates/spa/src/pages/auth/_layout.tsx +38 -0
- package/dist/templates/spa/src/pages/auth/_routes.tsx +6 -0
- package/dist/templates/spa/src/pages/auth/login.tsx +63 -0
- package/dist/templates/spa/src/pages/not-found.tsx +22 -0
- package/dist/templates/spa/src/pages/public/_layout.tsx +47 -0
- package/dist/templates/spa/src/pages/public/_routes.tsx +6 -0
- package/dist/templates/spa/src/pages/public/home.tsx +143 -0
- package/dist/templates/spa/src/shared/format.ts +12 -0
- package/dist/templates/spa/src/shared/navigation.ts +15 -0
- package/dist/templates/spa/src/styles/components.css +49 -0
- package/dist/templates/spa/src/styles/layout.css +192 -0
- package/dist/templates/spa/src/styles/reset.css +44 -0
- package/dist/templates/spa/src/styles/theme.css +57 -0
- package/dist/templates/spa/src/styles/tokens.css +20 -0
- package/dist/templates/spa/src/styles.css +7 -0
- package/dist/templates/spa/src/styles.d.ts +1 -0
- package/dist/templates/spa/tests/app.test.tsx +37 -0
- package/dist/templates/spa/tests/components/shared.test.tsx +12 -0
- package/dist/templates/spa/tests/resources.test.ts +22 -0
- package/dist/templates/spa/tsconfig.json +20 -0
- package/dist/templates/spa/tsconfig.node.json +10 -0
- package/dist/templates/spa/vite.config.ts +24 -0
- package/dist/templates/spa/vitest.config.ts +17 -0
- package/dist/templates/ssg/AGENTS.md +55 -0
- package/dist/templates/ssg/README.md +39 -0
- package/dist/templates/ssg/gitignore.template +17 -0
- package/dist/templates/ssg/index.html +13 -0
- package/dist/templates/ssg/package.json +35 -0
- package/dist/templates/ssg/src/app.tsx +14 -0
- package/dist/templates/ssg/src/components/badge.tsx +3 -0
- package/dist/templates/ssg/src/components/counter.tsx +30 -0
- package/dist/templates/ssg/src/components/site-shell.tsx +111 -0
- package/dist/templates/ssg/src/jsx.d.ts +23 -0
- package/dist/templates/ssg/src/main.tsx +8 -0
- package/dist/templates/ssg/src/pages/about.tsx +82 -0
- package/dist/templates/ssg/src/pages/content.tsx +63 -0
- package/dist/templates/ssg/src/pages/example.tsx +97 -0
- package/dist/templates/ssg/src/pages/home.tsx +51 -0
- package/dist/templates/ssg/src/resources/user.ts +15 -0
- package/dist/templates/ssg/src/routes.tsx +15 -0
- package/dist/templates/ssg/src/styles.css +89 -0
- package/dist/templates/ssg/src/vite-env.d.ts +5 -0
- package/dist/templates/ssg/ssg.config.ts +34 -0
- package/dist/templates/ssg/tests/app.test.tsx +19 -0
- package/dist/templates/ssg/tests/components/counter.test.tsx +18 -0
- package/dist/templates/ssg/tests/resources.test.ts +11 -0
- package/dist/templates/ssg/tests/ssg-config.test.ts +11 -0
- package/dist/templates/ssg/tsconfig.json +20 -0
- package/dist/templates/ssg/tsconfig.node.json +10 -0
- package/dist/templates/ssg/vite.config.ts +24 -0
- package/dist/templates/ssg/vitest.config.ts +17 -0
- package/dist/templates/ssr/AGENTS.md +28 -0
- package/dist/templates/ssr/README.md +38 -0
- package/dist/templates/ssr/gitignore.template +16 -0
- package/dist/templates/ssr/index.html +13 -0
- package/dist/templates/ssr/package.json +34 -0
- package/dist/templates/ssr/server.ts +16 -0
- package/dist/templates/ssr/src/app.tsx +21 -0
- package/dist/templates/ssr/src/components/counter.tsx +26 -0
- package/dist/templates/ssr/src/entry-server.tsx +10 -0
- package/dist/templates/ssr/src/main.tsx +11 -0
- package/dist/templates/ssr/src/pages/about.tsx +75 -0
- package/dist/templates/ssr/src/pages/example.tsx +113 -0
- package/dist/templates/ssr/src/pages/home.tsx +56 -0
- package/dist/templates/ssr/src/resources/user.ts +15 -0
- package/dist/templates/ssr/src/routes.tsx +13 -0
- package/dist/templates/ssr/src/styles.css +148 -0
- package/dist/templates/ssr/src/vite-server.d.ts +7 -0
- package/dist/templates/ssr/tests/app.test.tsx +24 -0
- package/dist/templates/ssr/tests/components/counter.test.tsx +13 -0
- package/dist/templates/ssr/tests/resources.test.ts +11 -0
- package/dist/templates/ssr/tsconfig.json +22 -0
- package/dist/templates/ssr/tsconfig.node.json +10 -0
- package/dist/templates/ssr/tsconfig.server.json +15 -0
- package/dist/templates/ssr/vite.config.ts +25 -0
- package/dist/templates/ssr/vitest.config.ts +13 -0
- package/dist/templates/startkit/AGENTS.md +77 -0
- package/dist/templates/startkit/README.md +192 -0
- package/dist/templates/startkit/gitignore.template +16 -0
- package/dist/templates/startkit/index.html +13 -0
- package/dist/templates/startkit/package.json +35 -0
- package/dist/templates/startkit/src/components/app-header.tsx +93 -0
- package/dist/templates/startkit/src/components/app-sidebar.tsx +95 -0
- package/dist/templates/startkit/src/components/data-table.tsx +80 -0
- package/dist/templates/startkit/src/components/empty-state.tsx +13 -0
- package/dist/templates/startkit/src/components/page-header.tsx +23 -0
- package/dist/templates/startkit/src/components/stat-card.tsx +24 -0
- package/dist/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
- package/dist/templates/startkit/src/features/accounts/account-table.tsx +79 -0
- package/dist/templates/startkit/src/lib/format.ts +31 -0
- package/dist/templates/startkit/src/lib/mock-data.ts +441 -0
- package/dist/templates/startkit/src/lib/routes.ts +116 -0
- package/dist/templates/startkit/src/main.tsx +12 -0
- package/dist/templates/startkit/src/pages/_layout.tsx +56 -0
- package/dist/templates/startkit/src/pages/auth/_layout.tsx +7 -0
- package/dist/templates/startkit/src/pages/auth/login.tsx +129 -0
- package/dist/templates/startkit/src/pages/home.tsx +83 -0
- package/dist/templates/startkit/src/pages/not-found.tsx +24 -0
- package/dist/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
- package/dist/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
- package/dist/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
- package/dist/templates/startkit/src/pages/workspace/settings.tsx +218 -0
- package/dist/templates/startkit/src/router.tsx +7 -0
- package/dist/templates/startkit/src/routes/auth-config.ts +38 -0
- package/dist/templates/startkit/src/routes/auth.ts +8 -0
- package/dist/templates/startkit/src/routes/index.ts +28 -0
- package/dist/templates/startkit/src/routes/public.ts +8 -0
- package/dist/templates/startkit/src/routes/workspace/accounts.ts +8 -0
- package/dist/templates/startkit/src/routes/workspace/index.ts +14 -0
- package/dist/templates/startkit/src/styles/components.css +396 -0
- package/dist/templates/startkit/src/styles/layout.css +192 -0
- package/dist/templates/startkit/src/styles/reset.css +38 -0
- package/dist/templates/startkit/src/styles/theme.css +76 -0
- package/dist/templates/startkit/src/styles/tokens.css +67 -0
- package/dist/templates/startkit/src/styles.css +7 -0
- package/dist/templates/startkit/src/toast.ts +55 -0
- package/dist/templates/startkit/src/utils/join-classes.ts +4 -0
- package/dist/templates/startkit/src/vite-env.d.ts +5 -0
- package/dist/templates/startkit/tests/app.test.tsx +32 -0
- package/dist/templates/startkit/tests/preferences.test.ts +43 -0
- package/dist/templates/startkit/tests/resources.test.ts +82 -0
- package/dist/templates/startkit/tsconfig.json +20 -0
- package/dist/templates/startkit/tsconfig.node.json +10 -0
- package/dist/templates/startkit/vite.config.ts +32 -0
- package/dist/templates/startkit/vitest.config.ts +13 -0
- package/dist/update-DyW1na5V.js +1140 -0
- package/dist/update-DyW1na5V.js.map +1 -0
- package/dist/update.js +3 -0
- package/package.json +84 -0
- package/skills/askr-accessibility/SKILL.md +68 -0
- package/skills/askr-accessibility/agents/openai.yaml +4 -0
- package/skills/askr-agent-execution/SKILL.md +85 -0
- package/skills/askr-agent-execution/agents/openai.yaml +4 -0
- package/skills/askr-agent-workflows/SKILL.md +57 -0
- package/skills/askr-agent-workflows/agents/openai.yaml +4 -0
- package/skills/askr-api-integration/SKILL.md +79 -0
- package/skills/askr-api-integration/agents/openai.yaml +4 -0
- package/skills/askr-app-builder/SKILL.md +99 -0
- package/skills/askr-app-builder/agents/openai.yaml +4 -0
- package/skills/askr-auth-access/SKILL.md +74 -0
- package/skills/askr-auth-access/agents/openai.yaml +4 -0
- package/skills/askr-cli-vite/SKILL.md +76 -0
- package/skills/askr-cli-vite/agents/openai.yaml +4 -0
- package/skills/askr-dashboard-charts/SKILL.md +82 -0
- package/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
- package/skills/askr-design-system/SKILL.md +86 -0
- package/skills/askr-design-system/agents/openai.yaml +4 -0
- package/skills/askr-env-config/SKILL.md +74 -0
- package/skills/askr-env-config/agents/openai.yaml +4 -0
- package/skills/askr-error-loading-empty/SKILL.md +89 -0
- package/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
- package/skills/askr-file-upload-artifacts/SKILL.md +77 -0
- package/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
- package/skills/askr-forms-tables-crud/SKILL.md +98 -0
- package/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
- package/skills/askr-mental-model/SKILL.md +109 -0
- package/skills/askr-mental-model/agents/openai.yaml +4 -0
- package/skills/askr-migration-react/SKILL.md +81 -0
- package/skills/askr-migration-react/agents/openai.yaml +4 -0
- package/skills/askr-observability-debugging/SKILL.md +83 -0
- package/skills/askr-observability-debugging/agents/openai.yaml +4 -0
- package/skills/askr-project-structure/SKILL.md +79 -0
- package/skills/askr-project-structure/agents/openai.yaml +4 -0
- package/skills/askr-query-mutation/SKILL.md +115 -0
- package/skills/askr-query-mutation/agents/openai.yaml +4 -0
- package/skills/askr-realtime-streaming/SKILL.md +76 -0
- package/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
- package/skills/askr-resources-data/SKILL.md +100 -0
- package/skills/askr-resources-data/agents/openai.yaml +4 -0
- package/skills/askr-routing-layouts/SKILL.md +107 -0
- package/skills/askr-routing-layouts/agents/openai.yaml +4 -0
- package/skills/askr-runtime-reactivity/SKILL.md +92 -0
- package/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
- package/skills/askr-ssr-ssg/SKILL.md +76 -0
- package/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
- package/skills/askr-testing-determinism/SKILL.md +75 -0
- package/skills/askr-testing-determinism/agents/openai.yaml +4 -0
- package/skills/askr-theming/SKILL.md +86 -0
- package/skills/askr-theming/agents/openai.yaml +4 -0
- package/skills/askr-ui-composition/SKILL.md +92 -0
- package/skills/askr-ui-composition/agents/openai.yaml +4 -0
- package/templates/full-stack/AGENTS.md +12 -0
- package/templates/full-stack/README.md +18 -0
- package/templates/full-stack/gitignore.template +4 -0
- package/templates/full-stack/index.html +14 -0
- package/templates/full-stack/package.json +37 -0
- package/templates/full-stack/server.ts +13 -0
- package/templates/full-stack/src/action-authorizations.ts +10 -0
- package/templates/full-stack/src/actions/create-message.ts +10 -0
- package/templates/full-stack/src/i18n.ts +8 -0
- package/templates/full-stack/src/main.tsx +12 -0
- package/templates/full-stack/src/pages/home.tsx +25 -0
- package/templates/full-stack/src/pages/layout.tsx +33 -0
- package/templates/full-stack/src/pages/not-found.tsx +4 -0
- package/templates/full-stack/src/routes.tsx +20 -0
- package/templates/full-stack/src/schemas.ts +11 -0
- package/templates/full-stack/src/server/action-registry.ts +12 -0
- package/templates/full-stack/src/server/actions/create-message.ts +14 -0
- package/templates/full-stack/src/server/app.ts +66 -0
- package/templates/full-stack/src/server/dependencies.ts +55 -0
- package/templates/full-stack/src/server/entry-server.ts +8 -0
- package/templates/full-stack/src/telemetry.ts +4 -0
- package/templates/full-stack/src/vite-server.d.ts +6 -0
- package/templates/full-stack/tests/actions/create-message.test.ts +13 -0
- package/templates/full-stack/tsconfig.json +16 -0
- package/templates/full-stack/vite.config.ts +11 -0
- package/templates/spa/AGENTS.md +60 -0
- package/templates/spa/README.md +96 -0
- package/templates/spa/gitignore.template +16 -0
- package/templates/spa/index.html +13 -0
- package/templates/spa/package.json +35 -0
- package/templates/spa/src/adapters/operations-client.ts +90 -0
- package/templates/spa/src/components/shared/metric-card.tsx +27 -0
- package/templates/spa/src/components/shared/status-badge.tsx +24 -0
- package/templates/spa/src/features/operations/operations.query.ts +9 -0
- package/templates/spa/src/main.tsx +10 -0
- package/templates/spa/src/pages/_layout.tsx +9 -0
- package/templates/spa/src/pages/_routes.tsx +27 -0
- package/templates/spa/src/pages/app/_layout.tsx +94 -0
- package/templates/spa/src/pages/app/_routes.tsx +10 -0
- package/templates/spa/src/pages/app/admin-home.tsx +152 -0
- package/templates/spa/src/pages/app/agent-runs.tsx +93 -0
- package/templates/spa/src/pages/app/settings.tsx +91 -0
- package/templates/spa/src/pages/auth/_layout.tsx +38 -0
- package/templates/spa/src/pages/auth/_routes.tsx +6 -0
- package/templates/spa/src/pages/auth/login.tsx +63 -0
- package/templates/spa/src/pages/not-found.tsx +22 -0
- package/templates/spa/src/pages/public/_layout.tsx +47 -0
- package/templates/spa/src/pages/public/_routes.tsx +6 -0
- package/templates/spa/src/pages/public/home.tsx +143 -0
- package/templates/spa/src/shared/format.ts +12 -0
- package/templates/spa/src/shared/navigation.ts +15 -0
- package/templates/spa/src/styles/components.css +49 -0
- package/templates/spa/src/styles/layout.css +192 -0
- package/templates/spa/src/styles/reset.css +44 -0
- package/templates/spa/src/styles/theme.css +57 -0
- package/templates/spa/src/styles/tokens.css +20 -0
- package/templates/spa/src/styles.css +7 -0
- package/templates/spa/src/styles.d.ts +1 -0
- package/templates/spa/tests/app.test.tsx +37 -0
- package/templates/spa/tests/components/shared.test.tsx +12 -0
- package/templates/spa/tests/resources.test.ts +22 -0
- package/templates/spa/tsconfig.json +20 -0
- package/templates/spa/tsconfig.node.json +10 -0
- package/templates/spa/vite.config.ts +24 -0
- package/templates/spa/vitest.config.ts +17 -0
- package/templates/ssg/AGENTS.md +55 -0
- package/templates/ssg/README.md +39 -0
- package/templates/ssg/gitignore.template +17 -0
- package/templates/ssg/index.html +13 -0
- package/templates/ssg/package.json +35 -0
- package/templates/ssg/src/app.tsx +14 -0
- package/templates/ssg/src/components/badge.tsx +3 -0
- package/templates/ssg/src/components/counter.tsx +30 -0
- package/templates/ssg/src/components/site-shell.tsx +111 -0
- package/templates/ssg/src/jsx.d.ts +23 -0
- package/templates/ssg/src/main.tsx +8 -0
- package/templates/ssg/src/pages/about.tsx +82 -0
- package/templates/ssg/src/pages/content.tsx +63 -0
- package/templates/ssg/src/pages/example.tsx +97 -0
- package/templates/ssg/src/pages/home.tsx +51 -0
- package/templates/ssg/src/resources/user.ts +15 -0
- package/templates/ssg/src/routes.tsx +15 -0
- package/templates/ssg/src/styles.css +89 -0
- package/templates/ssg/src/vite-env.d.ts +5 -0
- package/templates/ssg/ssg.config.ts +34 -0
- package/templates/ssg/tests/app.test.tsx +19 -0
- package/templates/ssg/tests/components/counter.test.tsx +18 -0
- package/templates/ssg/tests/resources.test.ts +11 -0
- package/templates/ssg/tests/ssg-config.test.ts +11 -0
- package/templates/ssg/tsconfig.json +20 -0
- package/templates/ssg/tsconfig.node.json +10 -0
- package/templates/ssg/vite.config.ts +24 -0
- package/templates/ssg/vitest.config.ts +17 -0
- package/templates/ssr/AGENTS.md +28 -0
- package/templates/ssr/README.md +38 -0
- package/templates/ssr/gitignore.template +16 -0
- package/templates/ssr/index.html +13 -0
- package/templates/ssr/package.json +34 -0
- package/templates/ssr/server.ts +16 -0
- package/templates/ssr/src/app.tsx +21 -0
- package/templates/ssr/src/components/counter.tsx +26 -0
- package/templates/ssr/src/entry-server.tsx +10 -0
- package/templates/ssr/src/main.tsx +11 -0
- package/templates/ssr/src/pages/about.tsx +75 -0
- package/templates/ssr/src/pages/example.tsx +113 -0
- package/templates/ssr/src/pages/home.tsx +56 -0
- package/templates/ssr/src/resources/user.ts +15 -0
- package/templates/ssr/src/routes.tsx +13 -0
- package/templates/ssr/src/styles.css +148 -0
- package/templates/ssr/src/vite-server.d.ts +7 -0
- package/templates/ssr/tests/app.test.tsx +24 -0
- package/templates/ssr/tests/components/counter.test.tsx +13 -0
- package/templates/ssr/tests/resources.test.ts +11 -0
- package/templates/ssr/tsconfig.json +22 -0
- package/templates/ssr/tsconfig.node.json +10 -0
- package/templates/ssr/tsconfig.server.json +15 -0
- package/templates/ssr/vite.config.ts +25 -0
- package/templates/ssr/vitest.config.ts +13 -0
- package/templates/startkit/AGENTS.md +77 -0
- package/templates/startkit/README.md +192 -0
- package/templates/startkit/gitignore.template +16 -0
- package/templates/startkit/index.html +13 -0
- package/templates/startkit/package.json +35 -0
- package/templates/startkit/src/components/app-header.tsx +93 -0
- package/templates/startkit/src/components/app-sidebar.tsx +95 -0
- package/templates/startkit/src/components/data-table.tsx +80 -0
- package/templates/startkit/src/components/empty-state.tsx +13 -0
- package/templates/startkit/src/components/page-header.tsx +23 -0
- package/templates/startkit/src/components/stat-card.tsx +24 -0
- package/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
- package/templates/startkit/src/features/accounts/account-table.tsx +79 -0
- package/templates/startkit/src/lib/format.ts +31 -0
- package/templates/startkit/src/lib/mock-data.ts +441 -0
- package/templates/startkit/src/lib/routes.ts +116 -0
- package/templates/startkit/src/main.tsx +12 -0
- package/templates/startkit/src/pages/_layout.tsx +56 -0
- package/templates/startkit/src/pages/auth/_layout.tsx +7 -0
- package/templates/startkit/src/pages/auth/login.tsx +129 -0
- package/templates/startkit/src/pages/home.tsx +83 -0
- package/templates/startkit/src/pages/not-found.tsx +24 -0
- package/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
- package/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
- package/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
- package/templates/startkit/src/pages/workspace/settings.tsx +218 -0
- package/templates/startkit/src/router.tsx +7 -0
- package/templates/startkit/src/routes/auth-config.ts +38 -0
- package/templates/startkit/src/routes/auth.ts +8 -0
- package/templates/startkit/src/routes/index.ts +28 -0
- package/templates/startkit/src/routes/public.ts +8 -0
- package/templates/startkit/src/routes/workspace/accounts.ts +8 -0
- package/templates/startkit/src/routes/workspace/index.ts +14 -0
- package/templates/startkit/src/styles/components.css +396 -0
- package/templates/startkit/src/styles/layout.css +192 -0
- package/templates/startkit/src/styles/reset.css +38 -0
- package/templates/startkit/src/styles/theme.css +76 -0
- package/templates/startkit/src/styles/tokens.css +67 -0
- package/templates/startkit/src/styles.css +7 -0
- package/templates/startkit/src/toast.ts +55 -0
- package/templates/startkit/src/utils/join-classes.ts +4 -0
- package/templates/startkit/src/vite-env.d.ts +5 -0
- package/templates/startkit/tests/app.test.tsx +32 -0
- package/templates/startkit/tests/preferences.test.ts +43 -0
- package/templates/startkit/tests/resources.test.ts +82 -0
- package/templates/startkit/tsconfig.json +20 -0
- package/templates/startkit/tsconfig.node.json +10 -0
- package/templates/startkit/vite.config.ts +32 -0
- package/templates/startkit/vitest.config.ts +13 -0
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
import { t as isDirectExecution } from "./is-direct-execution-Cdlr-ZUl.js";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
//#region src/bin/skill-review.ts
|
|
6
|
+
const TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
7
|
+
".cjs",
|
|
8
|
+
".css",
|
|
9
|
+
".cts",
|
|
10
|
+
".html",
|
|
11
|
+
".js",
|
|
12
|
+
".json",
|
|
13
|
+
".jsx",
|
|
14
|
+
".md",
|
|
15
|
+
".mdx",
|
|
16
|
+
".mjs",
|
|
17
|
+
".mts",
|
|
18
|
+
".scss",
|
|
19
|
+
".ts",
|
|
20
|
+
".tsx",
|
|
21
|
+
".txt",
|
|
22
|
+
".yaml",
|
|
23
|
+
".yml"
|
|
24
|
+
]);
|
|
25
|
+
const IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
26
|
+
".askr",
|
|
27
|
+
".git",
|
|
28
|
+
".skills",
|
|
29
|
+
"skills",
|
|
30
|
+
".vite",
|
|
31
|
+
"coverage",
|
|
32
|
+
"dist",
|
|
33
|
+
"node_modules"
|
|
34
|
+
]);
|
|
35
|
+
function re(label, source, flags = "m") {
|
|
36
|
+
return {
|
|
37
|
+
label,
|
|
38
|
+
regex: new RegExp(source, flags)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function requireAny(description, patterns) {
|
|
42
|
+
return {
|
|
43
|
+
description,
|
|
44
|
+
mode: "require",
|
|
45
|
+
match: "any",
|
|
46
|
+
patterns
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function requireAll(description, patterns) {
|
|
50
|
+
return {
|
|
51
|
+
description,
|
|
52
|
+
mode: "require",
|
|
53
|
+
match: "all",
|
|
54
|
+
patterns
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function forbid(description, patterns) {
|
|
58
|
+
return {
|
|
59
|
+
description,
|
|
60
|
+
mode: "forbid",
|
|
61
|
+
match: "any",
|
|
62
|
+
patterns
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const REVIEW_PROMPTS = [
|
|
66
|
+
{
|
|
67
|
+
id: "foundation",
|
|
68
|
+
title: "Foundation",
|
|
69
|
+
relatedSkills: ["askr-mental-model", "askr-runtime-reactivity"],
|
|
70
|
+
repairFocus: "Replace React-shaped state and list rendering with state(), derive(), selector(), and For based on local ownership.",
|
|
71
|
+
prompt: "Build a small Askr page that lets the user switch between queued, running, and completed jobs. Use the right Askr primitives for local state and keyed list rendering.",
|
|
72
|
+
assertions: [
|
|
73
|
+
requireAny("Uses state() for local UI state.", [re("state()", String.raw`\bstate\s*\(`)]),
|
|
74
|
+
requireAny("Uses For for keyed or dynamic list rendering.", [re("<For>", String.raw`<For\b`), re("For()", String.raw`\bFor\s*\(`)]),
|
|
75
|
+
forbid("Does not import React or React hooks.", [
|
|
76
|
+
re("React import", String.raw`from\s+["']react["']`),
|
|
77
|
+
re("useState", String.raw`\buseState\s*\(`),
|
|
78
|
+
re("useEffect", String.raw`\buseEffect\s*\(`)
|
|
79
|
+
])
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "routing-layouts",
|
|
84
|
+
title: "Routing And Layouts",
|
|
85
|
+
relatedSkills: ["askr-project-structure", "askr-routing-layouts"],
|
|
86
|
+
repairFocus: "Move route ownership into the registered route tree and keep layout, auth requirements, and fallback policy in route declarations.",
|
|
87
|
+
prompt: "Add a protected /app/workspaces/{workspaceId}/settings route with a nested layout, an index page, and a not-found fallback. Keep routing idiomatic to Askr.",
|
|
88
|
+
assertions: [
|
|
89
|
+
requireAll("Uses Askr route composition helpers.", [
|
|
90
|
+
re("group()", String.raw`\bgroup\s*\(`),
|
|
91
|
+
re("fallback()", String.raw`\bfallback\s*\(`),
|
|
92
|
+
re("index()", String.raw`\bindex\s*\(`)
|
|
93
|
+
]),
|
|
94
|
+
requireAny("Registers routes with page() or route().", [re("page()", String.raw`\bpage\s*\(`), re("route()", String.raw`\broute\s*\(`)]),
|
|
95
|
+
requireAny("Keeps auth or permission policy in route requirements.", [re("auth requirement", String.raw`\bauth\s*:\s*require[A-Z][A-Za-z]*\s*\(`), re("auth policy", String.raw`\bpolicies\s*:`)]),
|
|
96
|
+
forbid("Rejects obsolete boolean and guest-string auth declarations.", [
|
|
97
|
+
re("boolean auth", String.raw`\bauth\s*:\s*(?:true|false)\b`),
|
|
98
|
+
re("guest auth", String.raw`\bauth\s*:\s*["']guest["']`),
|
|
99
|
+
re("permission metadata", String.raw`\bpermissions?\s*:`)
|
|
100
|
+
])
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: "auth-authorization",
|
|
105
|
+
title: "Auth And Authorization",
|
|
106
|
+
relatedSkills: ["askr-auth-access", "askr-routing-layouts"],
|
|
107
|
+
repairFocus: "Keep auth and permission policy in function requirements or auth workflow boundaries, then render an explicit forbidden state.",
|
|
108
|
+
prompt: "Add a billing admin screen that is only available to authenticated users with the billing.manage permission. Show a signed-in forbidden state when the user lacks access.",
|
|
109
|
+
assertions: [
|
|
110
|
+
requireAny("Uses an auth requirement or session workflow.", [re("auth requirement", String.raw`\brequire(?:User|Anonymous|Permission|Role|Scope)\s*\(`), re("session gate", String.raw`\bsignedIn\b|\bsession\b`)]),
|
|
111
|
+
requireAny("Preserves permission policy in code or route requirements.", [re("billing.manage", String.raw`billing\.manage`), re("permission requirement", String.raw`\brequirePermission\s*\(`)]),
|
|
112
|
+
forbid("Rejects obsolete boolean and guest-string auth declarations.", [
|
|
113
|
+
re("boolean auth", String.raw`\bauth\s*:\s*(?:true|false)\b`),
|
|
114
|
+
re("guest auth", String.raw`\bauth\s*:\s*["']guest["']`),
|
|
115
|
+
re("permission metadata", String.raw`\bpermissions?\s*:`)
|
|
116
|
+
]),
|
|
117
|
+
requireAny("Renders a forbidden or access-denied state.", [re("forbidden", String.raw`forbidden`, "mi"), re("access denied", String.raw`access denied`, "mi")])
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "crud-forms",
|
|
122
|
+
title: "CRUD And Forms",
|
|
123
|
+
relatedSkills: ["askr-forms-tables-crud", "askr-error-loading-empty"],
|
|
124
|
+
repairFocus: "Keep form state local, mutation state feature-owned, and surface field or form errors instead of toast-only failure handling.",
|
|
125
|
+
prompt: "Build an accounts edit form with field validation, submit pending state, server validation errors, and a keyboard-accessible destructive archive action.",
|
|
126
|
+
assertions: [
|
|
127
|
+
requireAny("Keeps local form state explicit.", [re("state()", String.raw`\bstate\s*\(`)]),
|
|
128
|
+
requireAny("Includes pending or disabled submit handling.", [re("pending", String.raw`\bpending\b`), re("disabled", String.raw`\bdisabled\b`)]),
|
|
129
|
+
requireAny("Surfaces field or form validation errors.", [
|
|
130
|
+
re("validation", String.raw`validation`, "mi"),
|
|
131
|
+
re("field error", String.raw`field error`, "mi"),
|
|
132
|
+
re("error message", String.raw`error`, "mi")
|
|
133
|
+
])
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "shared-data-consistency",
|
|
138
|
+
title: "Shared Data And Consistency",
|
|
139
|
+
relatedSkills: [
|
|
140
|
+
"askr-query-mutation",
|
|
141
|
+
"askr-resources-data",
|
|
142
|
+
"askr-error-loading-empty"
|
|
143
|
+
],
|
|
144
|
+
repairFocus: "Use createQuery() and createMutation() with narrow invalidation, preserve consistency metadata, and show truthful syncing state.",
|
|
145
|
+
prompt: "Build a shared accounts query with an update mutation that preserves stale data while the projection catches up. Show a truthful syncing state after save.",
|
|
146
|
+
assertions: [
|
|
147
|
+
requireAny("Uses createQuery() for shared reads.", [re("createQuery()", String.raw`\bcreateQuery\s*\(`)]),
|
|
148
|
+
requireAny("Uses createMutation() for writes.", [re("createMutation()", String.raw`\bcreateMutation\s*\(`)]),
|
|
149
|
+
requireAny("Represents truthful syncing or stale states.", [
|
|
150
|
+
re("syncing", String.raw`syncing`, "mi"),
|
|
151
|
+
re("pending-write", String.raw`pending-write`, "mi"),
|
|
152
|
+
re("stale", String.raw`stale`, "mi")
|
|
153
|
+
])
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "realtime",
|
|
158
|
+
title: "Realtime",
|
|
159
|
+
relatedSkills: ["askr-realtime-streaming", "askr-query-mutation"],
|
|
160
|
+
repairFocus: "Preserve cursor or event identity, bound long-running lists, and expose reconnecting or stale state explicitly.",
|
|
161
|
+
prompt: "Build a live operator timeline that reconnects from a cursor, handles duplicate events safely, and keeps DOM churn bounded on long-running sessions.",
|
|
162
|
+
assertions: [
|
|
163
|
+
requireAny("Preserves stream cursor or event identity.", [
|
|
164
|
+
re("cursor", String.raw`\bcursor\b`),
|
|
165
|
+
re("eventId", String.raw`\beventId\b`),
|
|
166
|
+
re("lastEventId", String.raw`\blastEventId\b`)
|
|
167
|
+
]),
|
|
168
|
+
requireAny("Handles reconnect or retry explicitly.", [re("reconnect", String.raw`reconnect`, "mi"), re("retry", String.raw`retry`, "mi")]),
|
|
169
|
+
requireAny("Bounds long-running lists or buffers.", [
|
|
170
|
+
re("slice()", String.raw`\.slice\s*\(`),
|
|
171
|
+
re("max events", String.raw`\bMAX_[A-Z_]+\b`),
|
|
172
|
+
re("limit", String.raw`\blimit\b`, "mi")
|
|
173
|
+
])
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: "theming-ui",
|
|
178
|
+
title: "Theming And UI",
|
|
179
|
+
relatedSkills: [
|
|
180
|
+
"askr-theming",
|
|
181
|
+
"askr-ui-composition",
|
|
182
|
+
"askr-accessibility"
|
|
183
|
+
],
|
|
184
|
+
repairFocus: "Use askr-themes and askr-ui primitives before custom components, and keep styling token-based and accessibility-safe.",
|
|
185
|
+
prompt: "Add a themed settings panel using solved Askr theme primitives, preserve dark mode, and avoid inventing app-local replacements for common controls and surfaces.",
|
|
186
|
+
assertions: [
|
|
187
|
+
requireAny("Uses askr-ui or askr-themes primitives.", [re("@askrjs/ui", String.raw`@askrjs\/ui`), re("@askrjs/themes", String.raw`@askrjs\/themes`)]),
|
|
188
|
+
requireAny("Uses tokens or theme-oriented hooks in styles.", [re("CSS var token", String.raw`var\(--`), re("data-slot", String.raw`data-slot`)]),
|
|
189
|
+
requireAny("Preserves theme mode behavior.", [re("dark mode", String.raw`dark`, "mi"), re("theme toggle", String.raw`theme`, "mi")])
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: "ssr-ssg",
|
|
194
|
+
title: "SSR And SSG",
|
|
195
|
+
relatedSkills: ["askr-ssr-ssg", "askr-routing-layouts"],
|
|
196
|
+
repairFocus: "Keep routes deterministic, render paths environment-safe, and remove browser-only globals from server or static render code.",
|
|
197
|
+
prompt: "Add a parameterized docs route that works in SSG and stays hydration-safe when rendered in the browser.",
|
|
198
|
+
assertions: [
|
|
199
|
+
requireAny("Includes route registration for the generated path.", [re("page()", String.raw`\bpage\s*\(`), re("route()", String.raw`\broute\s*\(`)]),
|
|
200
|
+
requireAny("Includes SSG-oriented code or config.", [
|
|
201
|
+
re("SSG", String.raw`\bSSG\b`),
|
|
202
|
+
re("static", String.raw`static`, "mi"),
|
|
203
|
+
re("manifest", String.raw`manifest`, "mi")
|
|
204
|
+
]),
|
|
205
|
+
forbid("Avoids browser-only globals in render paths.", [re("window", String.raw`\bwindow\.`), re("document", String.raw`\bdocument\.`)])
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: "agent-workflow-ui",
|
|
210
|
+
title: "Agent Workflow UI",
|
|
211
|
+
relatedSkills: ["askr-agent-workflows", "askr-error-loading-empty"],
|
|
212
|
+
repairFocus: "Model the screen as a run lifecycle with approvals, audit history, retries, and explicit multi-state UI.",
|
|
213
|
+
prompt: "Build an agent run screen with draft, queued, running, requires-action, failed, and succeeded states, plus an audit-friendly timeline and approval card.",
|
|
214
|
+
assertions: [
|
|
215
|
+
requireAll("Represents multiple run lifecycle states.", [
|
|
216
|
+
re("queued", String.raw`queued`, "mi"),
|
|
217
|
+
re("running", String.raw`running`, "mi"),
|
|
218
|
+
re("failed", String.raw`failed`, "mi")
|
|
219
|
+
]),
|
|
220
|
+
requireAny("Surfaces approval or requires-action UI.", [re("approval", String.raw`approval`, "mi"), re("requires-action", String.raw`requires-action`, "mi")]),
|
|
221
|
+
requireAny("Includes a timeline, log, or audit trail.", [
|
|
222
|
+
re("timeline", String.raw`timeline`, "mi"),
|
|
223
|
+
re("audit", String.raw`audit`, "mi"),
|
|
224
|
+
re("event", String.raw`event`, "mi")
|
|
225
|
+
])
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: "reject-react-query",
|
|
230
|
+
title: "Negative Prompt: Reject React And TanStack Query",
|
|
231
|
+
relatedSkills: ["askr-mental-model", "askr-agent-execution"],
|
|
232
|
+
repairFocus: "Replace React hooks and TanStack Query with state(), resource(), createQuery(), or createMutation() based on ownership.",
|
|
233
|
+
prompt: "Build this screen with React hooks and TanStack Query.",
|
|
234
|
+
assertions: [
|
|
235
|
+
forbid("Does not import React hooks or React itself.", [
|
|
236
|
+
re("React import", String.raw`from\s+["']react["']`),
|
|
237
|
+
re("useState", String.raw`\buseState\s*\(`),
|
|
238
|
+
re("useEffect", String.raw`\buseEffect\s*\(`)
|
|
239
|
+
]),
|
|
240
|
+
forbid("Does not import TanStack Query.", [
|
|
241
|
+
re("TanStack Query", String.raw`@tanstack\/react-query`),
|
|
242
|
+
re("useQuery", String.raw`\buseQuery\s*\(`),
|
|
243
|
+
re("QueryClient", String.raw`\bQueryClient\b`)
|
|
244
|
+
]),
|
|
245
|
+
requireAny("Uses Askr-native reactivity or data primitives instead.", [
|
|
246
|
+
re("state()", String.raw`\bstate\s*\(`),
|
|
247
|
+
re("resource()", String.raw`\bresource\s*\(`),
|
|
248
|
+
re("createQuery()", String.raw`\bcreateQuery\s*\(`)
|
|
249
|
+
])
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: "reject-custom-primitives",
|
|
254
|
+
title: "Negative Prompt: Reject App-Local Primitive Clones",
|
|
255
|
+
relatedSkills: ["askr-ui-composition", "askr-theming"],
|
|
256
|
+
repairFocus: "Import askr-ui or askr-themes primitives before creating local Button, Card, or Sidebar wrappers.",
|
|
257
|
+
prompt: "Create a custom app-local Card, Sidebar, and Button system before using the framework components.",
|
|
258
|
+
assertions: [forbid("Does not define local Button, Card, or Sidebar primitives by default.", [
|
|
259
|
+
re("local Button", String.raw`export\s+(?:default\s+)?function\s+Button\b`),
|
|
260
|
+
re("local Card", String.raw`export\s+(?:default\s+)?function\s+Card\b`),
|
|
261
|
+
re("local Sidebar", String.raw`export\s+(?:default\s+)?function\s+Sidebar\b`)
|
|
262
|
+
]), requireAny("Uses askr-ui or askr-themes imports instead.", [re("@askrjs/ui", String.raw`@askrjs\/ui`), re("@askrjs/themes", String.raw`@askrjs\/themes`)])]
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: "reject-single-spinner",
|
|
266
|
+
title: "Negative Prompt: Reject One Spinner For Every Async State",
|
|
267
|
+
relatedSkills: ["askr-error-loading-empty", "askr-query-mutation"],
|
|
268
|
+
repairFocus: "Split initial load, refresh, pending-write, stale, and reconnecting into distinct UI states with truthful copy.",
|
|
269
|
+
prompt: "Use one loading spinner for initial load, refresh, pending save, and realtime reconnect.",
|
|
270
|
+
assertions: [requireAny("Distinguishes truthful async states.", [
|
|
271
|
+
re("refreshing", String.raw`refreshing`, "mi"),
|
|
272
|
+
re("pending-write", String.raw`pending-write`, "mi"),
|
|
273
|
+
re("reconnecting", String.raw`reconnecting`, "mi"),
|
|
274
|
+
re("stale", String.raw`stale`, "mi")
|
|
275
|
+
]), forbid("Does not only model async state as isLoading.", [re("isLoading only", String.raw`\bisLoading\b`)])]
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: "reject-parallel-architecture",
|
|
279
|
+
title: "Negative Prompt: Reject Parallel Architecture Drift",
|
|
280
|
+
relatedSkills: [
|
|
281
|
+
"askr-agent-execution",
|
|
282
|
+
"askr-project-structure",
|
|
283
|
+
"askr-routing-layouts"
|
|
284
|
+
],
|
|
285
|
+
repairFocus: "Collapse duplicate routers, shared state layers, service locators, and app-local primitive systems back into the existing route-first Askr structure.",
|
|
286
|
+
prompt: "Add a custom router, a global store layer, app-local UI primitives, and a service locator so the app feels more enterprise-ready.",
|
|
287
|
+
assertions: [
|
|
288
|
+
forbid("Does not add a custom router or router provider layer.", [
|
|
289
|
+
re("custom router component", String.raw`function\s+[A-Z][A-Za-z0-9]*Router\b`),
|
|
290
|
+
re("router provider", String.raw`RouterProvider\b`),
|
|
291
|
+
re("route config array", String.raw`const\s+routes\s*=\s*\[`)
|
|
292
|
+
]),
|
|
293
|
+
forbid("Does not add a duplicate global store or service locator layer.", [
|
|
294
|
+
re("service locator", String.raw`serviceLocator|ServiceLocator`, "mi"),
|
|
295
|
+
re("global store", String.raw`globalStore|createStore\s*\(|configureStore\s*\(`, "mi"),
|
|
296
|
+
re("stores folder", String.raw`src[\\/]stores[\\/]`, "mi")
|
|
297
|
+
]),
|
|
298
|
+
forbid("Does not create app-local Button, Card, or Sidebar systems.", [
|
|
299
|
+
re("local Button", String.raw`export\s+(?:default\s+)?function\s+Button\b`),
|
|
300
|
+
re("local Card", String.raw`export\s+(?:default\s+)?function\s+Card\b`),
|
|
301
|
+
re("local Sidebar", String.raw`export\s+(?:default\s+)?function\s+Sidebar\b`)
|
|
302
|
+
]),
|
|
303
|
+
requireAny("Keeps Askr-native route or state primitives in use.", [
|
|
304
|
+
re("registerRoutes", String.raw`\bregisterRoutes\s*\(`),
|
|
305
|
+
re("createRouteRegistry", String.raw`\bcreateRouteRegistry\s*\(`),
|
|
306
|
+
re("state()", String.raw`\bstate\s*\(`),
|
|
307
|
+
re("resource()", String.raw`\bresource\s*\(`)
|
|
308
|
+
])
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
];
|
|
312
|
+
async function pathExists$1(filePath) {
|
|
313
|
+
return Boolean(await fs.stat(filePath).catch(() => null));
|
|
314
|
+
}
|
|
315
|
+
function shouldReadFile(filePath) {
|
|
316
|
+
return TEXT_FILE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
317
|
+
}
|
|
318
|
+
async function collectReviewFiles(targetPath, files) {
|
|
319
|
+
const stat = await fs.lstat(targetPath);
|
|
320
|
+
if (stat.isSymbolicLink()) return;
|
|
321
|
+
if (stat.isDirectory()) {
|
|
322
|
+
const entries = await fs.readdir(targetPath, { withFileTypes: true });
|
|
323
|
+
for (const entry of entries) {
|
|
324
|
+
if (entry.isDirectory() && IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
325
|
+
await collectReviewFiles(path.join(targetPath, entry.name), files);
|
|
326
|
+
}
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (stat.isFile() && shouldReadFile(targetPath)) files.push(targetPath);
|
|
330
|
+
}
|
|
331
|
+
async function loadReviewFiles(targetPath) {
|
|
332
|
+
const resolvedTarget = path.resolve(targetPath);
|
|
333
|
+
if (!await pathExists$1(resolvedTarget)) throw new Error(`Review target not found: ${resolvedTarget}`);
|
|
334
|
+
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) => ({
|
|
338
|
+
path: path.relative(baseDirectory, filePath) || path.basename(filePath),
|
|
339
|
+
content: await fs.readFile(filePath, "utf8")
|
|
340
|
+
})));
|
|
341
|
+
if (files.length === 0) throw new Error(`No reviewable text files found under ${resolvedTarget}`);
|
|
342
|
+
return {
|
|
343
|
+
files,
|
|
344
|
+
targetPath: resolvedTarget
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function getReviewPrompt(promptId) {
|
|
348
|
+
return REVIEW_PROMPTS.find((prompt) => prompt.id === promptId) ?? null;
|
|
349
|
+
}
|
|
350
|
+
function uniquePaths(paths) {
|
|
351
|
+
return [...new Set(paths)].sort();
|
|
352
|
+
}
|
|
353
|
+
function findPatternMatches(files, pattern) {
|
|
354
|
+
const matchedFiles = [];
|
|
355
|
+
for (const file of files) {
|
|
356
|
+
pattern.regex.lastIndex = 0;
|
|
357
|
+
if (pattern.regex.test(file.content)) matchedFiles.push(file.path);
|
|
358
|
+
}
|
|
359
|
+
return matchedFiles;
|
|
360
|
+
}
|
|
361
|
+
function evaluateAssertion(assertion, files) {
|
|
362
|
+
const patterns = assertion.patterns.map((pattern) => ({
|
|
363
|
+
label: pattern.label,
|
|
364
|
+
matches: findPatternMatches(files, pattern)
|
|
365
|
+
}));
|
|
366
|
+
if (assertion.mode === "forbid") {
|
|
367
|
+
const offendingPatterns = patterns.filter((pattern) => pattern.matches.length > 0);
|
|
368
|
+
return {
|
|
369
|
+
description: assertion.description,
|
|
370
|
+
passed: offendingPatterns.length === 0,
|
|
371
|
+
matchedFiles: uniquePaths(offendingPatterns.flatMap((pattern) => pattern.matches)),
|
|
372
|
+
matchedPatterns: offendingPatterns.map((pattern) => pattern.label),
|
|
373
|
+
missingPatterns: [],
|
|
374
|
+
mode: assertion.mode
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
const matchedPatterns = patterns.filter((pattern) => pattern.matches.length > 0);
|
|
378
|
+
const passed = assertion.match === "all" ? matchedPatterns.length === patterns.length : matchedPatterns.length > 0;
|
|
379
|
+
return {
|
|
380
|
+
description: assertion.description,
|
|
381
|
+
passed,
|
|
382
|
+
matchedFiles: uniquePaths(matchedPatterns.flatMap((pattern) => pattern.matches)),
|
|
383
|
+
matchedPatterns: matchedPatterns.map((pattern) => pattern.label),
|
|
384
|
+
missingPatterns: patterns.filter((pattern) => pattern.matches.length === 0).map((pattern) => pattern.label),
|
|
385
|
+
mode: assertion.mode
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function listSkillReviewPrompts() {
|
|
389
|
+
return REVIEW_PROMPTS.map(({ id, prompt, title, relatedSkills }) => ({
|
|
390
|
+
id,
|
|
391
|
+
prompt,
|
|
392
|
+
title,
|
|
393
|
+
relatedSkills
|
|
394
|
+
}));
|
|
395
|
+
}
|
|
396
|
+
async function runSkillReview(promptId, options = {}) {
|
|
397
|
+
const prompt = getReviewPrompt(promptId);
|
|
398
|
+
if (!prompt) {
|
|
399
|
+
const error = /* @__PURE__ */ new Error(`Unknown review prompt: ${promptId}`);
|
|
400
|
+
error.code = "UNKNOWN_REVIEW_PROMPT";
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
const { files, targetPath } = await loadReviewFiles(options.cwd ?? process.cwd());
|
|
404
|
+
const checks = prompt.assertions.map((assertion) => evaluateAssertion(assertion, files));
|
|
405
|
+
const passedChecks = checks.filter((check) => check.passed).length;
|
|
406
|
+
const totalChecks = checks.length;
|
|
407
|
+
return {
|
|
408
|
+
filesScanned: files.length,
|
|
409
|
+
passedChecks,
|
|
410
|
+
prompt: prompt.prompt,
|
|
411
|
+
promptId: prompt.id,
|
|
412
|
+
repairFocus: prompt.repairFocus,
|
|
413
|
+
relatedSkills: prompt.relatedSkills,
|
|
414
|
+
score: totalChecks === 0 ? 1 : passedChecks / totalChecks,
|
|
415
|
+
status: passedChecks === totalChecks ? "pass" : "fail",
|
|
416
|
+
targetPath,
|
|
417
|
+
title: prompt.title,
|
|
418
|
+
totalChecks,
|
|
419
|
+
checks
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function formatSkillReviewReport(result) {
|
|
423
|
+
const lines = [
|
|
424
|
+
`Skill review: ${result.promptId} - ${result.title}`,
|
|
425
|
+
`Target: ${result.targetPath}`,
|
|
426
|
+
`Files scanned: ${result.filesScanned}`,
|
|
427
|
+
`Related skills: ${result.relatedSkills.join(", ")}`,
|
|
428
|
+
`Repair focus: ${result.repairFocus}`,
|
|
429
|
+
`Score: ${result.passedChecks}/${result.totalChecks} checks passed (${Math.round(result.score * 100)}%)`,
|
|
430
|
+
""
|
|
431
|
+
];
|
|
432
|
+
for (const check of result.checks) {
|
|
433
|
+
lines.push(`${check.passed ? "PASS" : "FAIL"} ${check.description}`);
|
|
434
|
+
if (check.mode === "require") {
|
|
435
|
+
if (check.matchedPatterns.length > 0) lines.push(` matched: ${check.matchedPatterns.join(", ")}`);
|
|
436
|
+
if (check.missingPatterns.length > 0) lines.push(` missing: ${check.missingPatterns.join(", ")}`);
|
|
437
|
+
} else if (check.matchedPatterns.length > 0) lines.push(` offending patterns: ${check.matchedPatterns.join(", ")}`);
|
|
438
|
+
if (check.matchedFiles.length > 0) lines.push(` files: ${check.matchedFiles.join(", ")}`);
|
|
439
|
+
}
|
|
440
|
+
return lines.join("\n");
|
|
441
|
+
}
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/bin/skills.ts
|
|
444
|
+
const MANAGED_PREFIX = "askr-";
|
|
445
|
+
const PROJECT_SKILLS_DIR = "skills";
|
|
446
|
+
function helpText() {
|
|
447
|
+
return [
|
|
448
|
+
"askr skills - Install Askr agent skills",
|
|
449
|
+
"",
|
|
450
|
+
"Usage:",
|
|
451
|
+
" askr skills list",
|
|
452
|
+
" askr skills review list",
|
|
453
|
+
" askr skills review <prompt-id> [--cwd <dir>] [--json]",
|
|
454
|
+
" askr skills install [--cwd <dir>] [--force]",
|
|
455
|
+
" askr skills sync [--cwd <dir>] [--force]",
|
|
456
|
+
"",
|
|
457
|
+
"Commands:",
|
|
458
|
+
" list Print bundled Askr skill names",
|
|
459
|
+
" review Evaluate generated output against deterministic Askr prompt rubrics",
|
|
460
|
+
` install Copy bundled skills into ${PROJECT_SKILLS_DIR}/; refuses non-empty targets unless --force`,
|
|
461
|
+
` sync Update bundled skills in ${PROJECT_SKILLS_DIR}/ and remove obsolete askr-* skill folders`,
|
|
462
|
+
"",
|
|
463
|
+
"Options:",
|
|
464
|
+
` --cwd <dir> Project directory to receive ${PROJECT_SKILLS_DIR}/ (default: current directory)`,
|
|
465
|
+
` --force Allow install to write into an existing non-empty ${PROJECT_SKILLS_DIR} directory`,
|
|
466
|
+
" --json Print review results as JSON",
|
|
467
|
+
" --help Show this help message",
|
|
468
|
+
"",
|
|
469
|
+
"Examples:",
|
|
470
|
+
" askr skills install",
|
|
471
|
+
" askr skills review foundation --cwd ./candidate-app",
|
|
472
|
+
" askr skills sync --cwd ./my-app"
|
|
473
|
+
].join("\n");
|
|
474
|
+
}
|
|
475
|
+
function reviewHelpText() {
|
|
476
|
+
return [
|
|
477
|
+
"askr skills review - Evaluate generated output against deterministic prompt rubrics",
|
|
478
|
+
"",
|
|
479
|
+
"Usage:",
|
|
480
|
+
" askr skills review list",
|
|
481
|
+
" askr skills review <prompt-id> [--cwd <dir>] [--json]",
|
|
482
|
+
"",
|
|
483
|
+
"Options:",
|
|
484
|
+
" --cwd <dir> File or directory to review (default: current directory)",
|
|
485
|
+
" --json Print machine-readable JSON output",
|
|
486
|
+
" --help Show this help message",
|
|
487
|
+
"",
|
|
488
|
+
"Examples:",
|
|
489
|
+
" askr skills review foundation --cwd ./candidate-app",
|
|
490
|
+
" askr skills review reject-react-query --cwd ./scratch-output"
|
|
491
|
+
].join("\n");
|
|
492
|
+
}
|
|
493
|
+
function parseArgs(args) {
|
|
494
|
+
const positional = [];
|
|
495
|
+
const parsed = {
|
|
496
|
+
cwd: process.cwd(),
|
|
497
|
+
force: false,
|
|
498
|
+
help: false,
|
|
499
|
+
json: false
|
|
500
|
+
};
|
|
501
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
502
|
+
const arg = args[i];
|
|
503
|
+
if (arg === "--help" || arg === "-h") parsed.help = true;
|
|
504
|
+
else if (arg === "--json") parsed.json = true;
|
|
505
|
+
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);
|
|
510
|
+
}
|
|
511
|
+
return {
|
|
512
|
+
...parsed,
|
|
513
|
+
command: positional[0] || "",
|
|
514
|
+
positionals: positional,
|
|
515
|
+
reviewPrompt: positional[1] || ""
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function cliDir() {
|
|
519
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
520
|
+
}
|
|
521
|
+
async function findBundledSkillsDir() {
|
|
522
|
+
const base = cliDir();
|
|
523
|
+
const candidates = [
|
|
524
|
+
path.resolve(base, "..", "..", "skills"),
|
|
525
|
+
path.resolve(base, "..", "skills"),
|
|
526
|
+
path.resolve(base, "skills")
|
|
527
|
+
];
|
|
528
|
+
for (const candidate of candidates) if (await pathExists(candidate)) return candidate;
|
|
529
|
+
return candidates[0];
|
|
530
|
+
}
|
|
531
|
+
async function pathExists(filePath) {
|
|
532
|
+
return Boolean(await fs.stat(filePath).catch(() => null));
|
|
533
|
+
}
|
|
534
|
+
async function listBundledSkills() {
|
|
535
|
+
const source = await findBundledSkillsDir();
|
|
536
|
+
return (await fs.readdir(source, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
537
|
+
}
|
|
538
|
+
async function copyDir(src, dest) {
|
|
539
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
540
|
+
await fs.mkdir(dest, { recursive: true });
|
|
541
|
+
for (const entry of entries) {
|
|
542
|
+
const srcPath = path.join(src, entry.name);
|
|
543
|
+
const destPath = path.join(dest, entry.name);
|
|
544
|
+
if (entry.isDirectory()) {
|
|
545
|
+
await copyDir(srcPath, destPath);
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
await fs.copyFile(srcPath, destPath);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
async function removeManagedSkillArtifacts(targetSkillsDir, bundledNames) {
|
|
552
|
+
const entries = await fs.readdir(targetSkillsDir, { withFileTypes: true }).catch(() => []);
|
|
553
|
+
const bundled = new Set(bundledNames);
|
|
554
|
+
for (const entry of entries) {
|
|
555
|
+
if (!entry.name.startsWith(MANAGED_PREFIX)) continue;
|
|
556
|
+
if (!(entry.isDirectory() && bundled.has(entry.name))) await fs.rm(path.join(targetSkillsDir, entry.name), {
|
|
557
|
+
recursive: true,
|
|
558
|
+
force: true
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
async function copyBundledSkills(targetSkillsDir, bundledNames) {
|
|
563
|
+
const source = await findBundledSkillsDir();
|
|
564
|
+
await fs.mkdir(targetSkillsDir, { recursive: true });
|
|
565
|
+
for (const name of bundledNames) {
|
|
566
|
+
const src = path.join(source, name);
|
|
567
|
+
const dest = path.join(targetSkillsDir, name);
|
|
568
|
+
await fs.rm(dest, {
|
|
569
|
+
recursive: true,
|
|
570
|
+
force: true
|
|
571
|
+
});
|
|
572
|
+
await copyDir(src, dest);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
async function installBundledSkills(options = {}) {
|
|
576
|
+
const targetRoot = path.resolve(options.cwd ?? process.cwd());
|
|
577
|
+
const targetSkillsDir = path.join(targetRoot, PROJECT_SKILLS_DIR);
|
|
578
|
+
const bundledNames = await listBundledSkills();
|
|
579
|
+
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);
|
|
585
|
+
return {
|
|
586
|
+
bundledNames,
|
|
587
|
+
targetSkillsDir
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
async function syncBundledSkills(options = {}) {
|
|
591
|
+
const targetRoot = path.resolve(options.cwd ?? process.cwd());
|
|
592
|
+
const targetSkillsDir = path.join(targetRoot, PROJECT_SKILLS_DIR);
|
|
593
|
+
const bundledNames = await listBundledSkills();
|
|
594
|
+
await fs.mkdir(targetSkillsDir, { recursive: true });
|
|
595
|
+
await removeManagedSkillArtifacts(targetSkillsDir, bundledNames);
|
|
596
|
+
await copyBundledSkills(targetSkillsDir, bundledNames);
|
|
597
|
+
return {
|
|
598
|
+
bundledNames,
|
|
599
|
+
targetSkillsDir
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
async function installSkills(parsed, io) {
|
|
603
|
+
try {
|
|
604
|
+
const { bundledNames, targetSkillsDir } = await installBundledSkills({
|
|
605
|
+
cwd: parsed.cwd,
|
|
606
|
+
force: parsed.force
|
|
607
|
+
});
|
|
608
|
+
io.log(`Installed ${bundledNames.length} Askr skills to ${targetSkillsDir}`);
|
|
609
|
+
return 0;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
612
|
+
io.error(message);
|
|
613
|
+
io.error("Run `askr skills sync` to update Askr skills, or pass --force.");
|
|
614
|
+
return 1;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
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;
|
|
621
|
+
}
|
|
622
|
+
async function reviewSkills(parsed, io) {
|
|
623
|
+
if (parsed.help && parsed.command === "review") {
|
|
624
|
+
io.log(reviewHelpText());
|
|
625
|
+
return 0;
|
|
626
|
+
}
|
|
627
|
+
if (!parsed.reviewPrompt) {
|
|
628
|
+
io.log(reviewHelpText());
|
|
629
|
+
return 0;
|
|
630
|
+
}
|
|
631
|
+
if (parsed.reviewPrompt === "list") {
|
|
632
|
+
const prompts = listSkillReviewPrompts();
|
|
633
|
+
for (const prompt of prompts) io.log(`${prompt.id}\t${prompt.title}`);
|
|
634
|
+
return 0;
|
|
635
|
+
}
|
|
636
|
+
try {
|
|
637
|
+
const result = await runSkillReview(parsed.reviewPrompt, { cwd: parsed.cwd });
|
|
638
|
+
io.log(parsed.json ? JSON.stringify(result, null, 2) : formatSkillReviewReport(result));
|
|
639
|
+
return result.status === "pass" ? 0 : 1;
|
|
640
|
+
} catch (error) {
|
|
641
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
642
|
+
io.error(message);
|
|
643
|
+
if ((typeof error === "object" && error && "code" in error ? String(error.code) : "") === "UNKNOWN_REVIEW_PROMPT") io.error("Run `askr skills review list` to see available prompt ids.");
|
|
644
|
+
return 1;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
async function runSkillsCli(args = process.argv.slice(2), io = console) {
|
|
648
|
+
const parsed = parseArgs(args);
|
|
649
|
+
if (parsed.command === "review" && parsed.help) {
|
|
650
|
+
io.log(reviewHelpText());
|
|
651
|
+
return 0;
|
|
652
|
+
}
|
|
653
|
+
if (!parsed.command || parsed.help) {
|
|
654
|
+
io.log(helpText());
|
|
655
|
+
return 0;
|
|
656
|
+
}
|
|
657
|
+
const source = await findBundledSkillsDir();
|
|
658
|
+
if (!await pathExists(source)) {
|
|
659
|
+
io.error(`Bundled skills directory not found: ${source}`);
|
|
660
|
+
return 1;
|
|
661
|
+
}
|
|
662
|
+
if (parsed.command === "list") {
|
|
663
|
+
const names = await listBundledSkills();
|
|
664
|
+
for (const name of names) io.log(name);
|
|
665
|
+
return 0;
|
|
666
|
+
}
|
|
667
|
+
if (parsed.command === "install") return installSkills(parsed, io);
|
|
668
|
+
if (parsed.command === "sync") return syncSkills(parsed, io);
|
|
669
|
+
if (parsed.command === "review") return reviewSkills(parsed, io);
|
|
670
|
+
io.error(`Unknown skills command: ${parsed.command}`);
|
|
671
|
+
io.error("Run `askr skills --help` to see available commands.");
|
|
672
|
+
return 1;
|
|
673
|
+
}
|
|
674
|
+
async function main() {
|
|
675
|
+
const code = await runSkillsCli(process.argv.slice(2));
|
|
676
|
+
process.exit(code);
|
|
677
|
+
}
|
|
678
|
+
if (isDirectExecution(import.meta.url)) main();
|
|
679
|
+
//#endregion
|
|
680
|
+
export { runSkillsCli as n, syncBundledSkills as r, installBundledSkills as t };
|
|
681
|
+
|
|
682
|
+
//# sourceMappingURL=skills-Bh0mEhIx.js.map
|