@askrjs/cli 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +9 -7
  2. package/dist/add.js +554 -1
  3. package/dist/add.js.map +1 -0
  4. package/dist/cli.js +43 -14
  5. package/dist/cli.js.map +1 -1
  6. package/dist/discovery-Difb7Y4G.js +325 -0
  7. package/dist/discovery-Difb7Y4G.js.map +1 -0
  8. package/dist/generate.js +396 -0
  9. package/dist/generate.js.map +1 -0
  10. package/dist/openapi.js +5 -4
  11. package/dist/openapi.js.map +1 -1
  12. package/dist/planner-VAj7qlxr.js +287 -0
  13. package/dist/planner-VAj7qlxr.js.map +1 -0
  14. package/dist/range-YUs9eimn.js +127 -0
  15. package/dist/range-YUs9eimn.js.map +1 -0
  16. package/dist/registry-CyrRHRG5.js +211 -0
  17. package/dist/registry-CyrRHRG5.js.map +1 -0
  18. package/dist/skills/askr-dashboard-charts/SKILL.md +61 -44
  19. package/dist/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
  20. package/dist/specification-DXnDOC-0.js +51 -0
  21. package/dist/specification-DXnDOC-0.js.map +1 -0
  22. package/dist/templates/full-stack/AGENTS.md +0 -1
  23. package/dist/templates/full-stack/README.md +0 -1
  24. package/dist/templates/full-stack/index.html +0 -1
  25. package/dist/templates/full-stack/package.json +4 -2
  26. package/dist/templates/full-stack/server.ts +5 -9
  27. package/dist/templates/full-stack/src/action-authorizations.ts +2 -2
  28. package/dist/templates/full-stack/src/actions/create-message.ts +5 -5
  29. package/dist/templates/full-stack/src/i18n.ts +4 -4
  30. package/dist/templates/full-stack/src/main.tsx +4 -5
  31. package/dist/templates/full-stack/src/pages/home.tsx +5 -5
  32. package/dist/templates/full-stack/src/pages/layout.tsx +15 -5
  33. package/dist/templates/full-stack/src/pages/not-found.tsx +5 -2
  34. package/dist/templates/full-stack/src/routes.tsx +11 -12
  35. package/dist/templates/full-stack/src/schemas.ts +1 -2
  36. package/dist/templates/full-stack/src/server/action-registry.ts +6 -10
  37. package/dist/templates/full-stack/src/server/actions/create-message.ts +4 -4
  38. package/dist/templates/full-stack/src/server/app.ts +67 -57
  39. package/dist/templates/full-stack/src/server/dependencies.ts +10 -10
  40. package/dist/templates/full-stack/src/server/entry-server.ts +3 -3
  41. package/dist/templates/full-stack/src/telemetry.ts +1 -2
  42. package/dist/templates/full-stack/src/vite-server.d.ts +2 -3
  43. package/dist/templates/full-stack/tests/actions/create-message.test.ts +7 -8
  44. package/dist/templates/full-stack/tsconfig.json +0 -1
  45. package/dist/templates/full-stack/vite.config.ts +5 -6
  46. package/dist/templates/spa/AGENTS.md +1 -1
  47. package/dist/templates/spa/package.json +1 -1
  48. package/dist/templates/spa/src/adapters/operations-client.ts +7 -2
  49. package/dist/templates/spa/src/pages/app/admin-home.tsx +21 -3
  50. package/dist/templates/spa/src/styles.css +1 -1
  51. package/dist/templates/ssg/tests/ssg-config.test.ts +3 -3
  52. package/dist/templates/ssr/server.ts +4 -10
  53. package/dist/templates/ssr/src/entry-server.tsx +6 -4
  54. package/dist/update.js +284 -2
  55. package/dist/update.js.map +1 -0
  56. package/dist/writer-D8qe_7ud.js +228 -0
  57. package/dist/writer-D8qe_7ud.js.map +1 -0
  58. package/package.json +11 -15
  59. package/skills/askr-dashboard-charts/SKILL.md +61 -44
  60. package/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
  61. package/templates/full-stack/AGENTS.md +0 -1
  62. package/templates/full-stack/README.md +0 -1
  63. package/templates/full-stack/index.html +0 -1
  64. package/templates/full-stack/package.json +4 -2
  65. package/templates/full-stack/server.ts +5 -9
  66. package/templates/full-stack/src/action-authorizations.ts +2 -2
  67. package/templates/full-stack/src/actions/create-message.ts +5 -5
  68. package/templates/full-stack/src/i18n.ts +4 -4
  69. package/templates/full-stack/src/main.tsx +4 -5
  70. package/templates/full-stack/src/pages/home.tsx +5 -5
  71. package/templates/full-stack/src/pages/layout.tsx +15 -5
  72. package/templates/full-stack/src/pages/not-found.tsx +5 -2
  73. package/templates/full-stack/src/routes.tsx +11 -12
  74. package/templates/full-stack/src/schemas.ts +1 -2
  75. package/templates/full-stack/src/server/action-registry.ts +6 -10
  76. package/templates/full-stack/src/server/actions/create-message.ts +4 -4
  77. package/templates/full-stack/src/server/app.ts +67 -57
  78. package/templates/full-stack/src/server/dependencies.ts +10 -10
  79. package/templates/full-stack/src/server/entry-server.ts +3 -3
  80. package/templates/full-stack/src/telemetry.ts +1 -2
  81. package/templates/full-stack/src/vite-server.d.ts +2 -3
  82. package/templates/full-stack/tests/actions/create-message.test.ts +7 -8
  83. package/templates/full-stack/tsconfig.json +0 -1
  84. package/templates/full-stack/vite.config.ts +5 -6
  85. package/templates/spa/AGENTS.md +1 -1
  86. package/templates/spa/package.json +1 -1
  87. package/templates/spa/src/adapters/operations-client.ts +7 -2
  88. package/templates/spa/src/pages/app/admin-home.tsx +21 -3
  89. package/templates/spa/src/styles.css +1 -1
  90. package/templates/ssg/tests/ssg-config.test.ts +3 -3
  91. package/templates/ssr/server.ts +4 -10
  92. package/templates/ssr/src/entry-server.tsx +6 -4
  93. package/dist/add-DqhqRzBQ.js +0 -555
  94. package/dist/add-DqhqRzBQ.js.map +0 -1
  95. package/dist/update-DyW1na5V.js +0 -1140
  96. package/dist/update-DyW1na5V.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","names":[],"sources":["../src/file-changes.ts","../src/bin/add.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nexport interface FileChange {\n readonly filePath: string;\n readonly content: string;\n}\n\ninterface StagedChange extends FileChange {\n readonly original: Buffer | null;\n readonly mode: number;\n readonly temporaryPath: string;\n}\n\nexport interface FileChangeWriterOptions {\n readonly replace?: (temporaryPath: string, filePath: string) => Promise<void>;\n}\n\nasync function remove(paths: readonly string[]): Promise<void> {\n await Promise.all(\n paths.map((filePath) => fs.rm(filePath, { force: true }).catch(() => undefined)),\n );\n}\n\nasync function restore(changes: readonly StagedChange[]): Promise<boolean> {\n let complete = true;\n for (const change of [...changes].reverse()) {\n try {\n if (change.original === null) {\n await fs.rm(change.filePath, { force: true });\n continue;\n }\n const rollbackPath = path.join(\n path.dirname(change.filePath),\n `.${path.basename(change.filePath)}.askr-rollback-${randomUUID()}`,\n );\n await fs.writeFile(rollbackPath, change.original, { flag: \"wx\", mode: change.mode });\n await fs.rename(rollbackPath, change.filePath);\n } catch {\n complete = false;\n }\n }\n return complete;\n}\n\nexport async function writeFileChanges(\n changes: readonly FileChange[],\n options: FileChangeWriterOptions = {},\n): Promise<void> {\n const ordered = [...changes].sort((left, right) => left.filePath.localeCompare(right.filePath));\n if (new Set(ordered.map((change) => change.filePath)).size !== ordered.length) {\n throw new Error(\"File changes contain duplicate target paths.\");\n }\n const replace = options.replace ?? fs.rename;\n const staged: StagedChange[] = [];\n try {\n for (const change of ordered) {\n await fs.mkdir(path.dirname(change.filePath), { recursive: true });\n const stat = await fs.stat(change.filePath).catch(() => null);\n const original = stat ? await fs.readFile(change.filePath) : null;\n const temporaryPath = path.join(\n path.dirname(change.filePath),\n `.${path.basename(change.filePath)}.askr-change-${randomUUID()}`,\n );\n const mode = stat?.mode ?? 0o644;\n await fs.writeFile(temporaryPath, change.content, { flag: \"wx\", mode });\n staged.push({ ...change, original, mode, temporaryPath });\n }\n } catch (error) {\n await remove(staged.map((change) => change.temporaryPath));\n throw error;\n }\n\n const replaced: StagedChange[] = [];\n try {\n for (const change of staged) {\n await replace(change.temporaryPath, change.filePath);\n replaced.push(change);\n }\n } catch {\n const complete = await restore(replaced);\n await remove(staged.map((change) => change.temporaryPath));\n throw new Error(\n complete\n ? \"File replacement failed; completed changes were rolled back.\"\n : \"File replacement failed and rollback was incomplete.\",\n );\n }\n}\n","#!/usr/bin/env node\n\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { isDirectExecution } from \"./is-direct-execution\";\nimport { writeFileChanges } from \"../file-changes\";\n\ntype CliIo = Pick<Console, \"error\" | \"log\">;\n\nconst BRANCH_CONFIG = {\n app: {\n badge: \"app route\",\n pagesDir: [\"src\", \"pages\", \"app\"],\n routesFile: [\"src\", \"pages\", \"app\", \"_routes.tsx\"],\n },\n public: {\n badge: \"public route\",\n pagesDir: [\"src\", \"pages\", \"public\"],\n routesFile: [\"src\", \"pages\", \"public\", \"_routes.tsx\"],\n },\n} as const;\n\ntype BranchName = keyof typeof BRANCH_CONFIG;\n\ninterface ParsedArgs {\n branch: string;\n cwd: string;\n force: boolean;\n help: boolean;\n routePath: string;\n title: string;\n errors: string[];\n command: string;\n name: string;\n}\n\nfunction helpText(): string {\n return [\n \"askr add - Generate code into an existing Askr project\",\n \"\",\n \"Usage:\",\n \" askr add page <name> [--branch app|public] [--cwd <dir>] [--title <title>] [--route <path>] [--force]\",\n \" askr add action <name> --route <path> [--cwd <dir>] [--force]\",\n \"\",\n \"Commands:\",\n \" page Scaffold a route page and register it in a route-first SPA branch\",\n \" action Scaffold a browser descriptor, server handler, registration, authorization, and test\",\n \"\",\n \"Options:\",\n \" --branch <name> Route branch to target (default: app)\",\n \" --cwd <dir> Project directory (default: current directory)\",\n \" --title <text> Override the generated page title\",\n \" --route <path> Override the generated route path\",\n \" --force Overwrite an existing page file\",\n \" --help Show this help message\",\n \"\",\n \"Examples:\",\n \" askr add page audit-log\",\n \" askr add page ops/audit-log --branch public\",\n ' askr add page approvals --title \"Human approvals\" --route /app/approvals',\n \" askr add action approve-request --route /requests/{id}\",\n \"\",\n \"Notes:\",\n \" Page generation supports route-first SPA projects created from `askr create spa`.\",\n \" Action generation supports projects created from `askr create full-stack`.\",\n ].join(\"\\n\");\n}\n\nfunction parseArgs(args: string[]): ParsedArgs {\n const positional: string[] = [];\n const parsed = {\n branch: \"app\",\n cwd: process.cwd(),\n force: false,\n help: false,\n routePath: \"\",\n title: \"\",\n errors: [] as string[],\n };\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n\n if (arg === \"--help\" || arg === \"-h\") {\n parsed.help = true;\n } else if (arg === \"--force\") {\n parsed.force = true;\n } else if (arg === \"--branch\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --branch\");\n } else {\n parsed.branch = args[index + 1];\n index += 1;\n }\n } else if (arg === \"--cwd\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --cwd\");\n } else {\n parsed.cwd = args[index + 1];\n index += 1;\n }\n } else if (arg === \"--title\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --title\");\n } else {\n parsed.title = args[index + 1].trim();\n index += 1;\n }\n } else if (arg === \"--route\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --route\");\n } else {\n parsed.routePath = args[index + 1].trim();\n index += 1;\n }\n } else {\n positional.push(arg);\n }\n }\n\n return {\n ...parsed,\n command: positional[0] || \"\",\n name: positional[1] || \"\",\n };\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n return Boolean(await fs.stat(filePath).catch(() => null));\n}\n\nfunction slugifySegment(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction normalizePageSegments(input: string): string[] {\n const segments = input\n .replace(/^\\/+|\\/+$/g, \"\")\n .split(\"/\")\n .map((segment) => slugifySegment(segment.trim()))\n .filter(Boolean);\n\n if (segments.length === 0 || segments.some((segment) => segment.startsWith(\"_\"))) {\n return [];\n }\n\n return segments;\n}\n\nfunction toWords(segments: string[]): string[] {\n return segments.flatMap((segment) => segment.split(\"-\").filter(Boolean));\n}\n\nfunction toTitleCase(words: string[]): string {\n return words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(\" \");\n}\n\nfunction buildComponentName(segments: string[]): string {\n return `${toWords(segments)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\")}Page`;\n}\n\nfunction buildIdentifier(segments: string[]): string {\n const [first = \"action\", ...rest] = toWords(segments);\n return [first.toLowerCase(), ...rest.map((word) => word.charAt(0).toUpperCase() + word.slice(1))]\n .join(\"\")\n .replace(/^[^a-z_$]/i, \"action\");\n}\n\ninterface DeclaredAction {\n readonly slug: string;\n readonly descriptorName: string;\n readonly handlerName: string;\n readonly routePath: string;\n}\n\nfunction renderAuthorizationRegistry(actions: readonly DeclaredAction[]): string {\n const imports = actions.map(\n (action) => `import { ${action.descriptorName} } from './actions/${action.slug}.js';`,\n );\n const routes = new Map<string, DeclaredAction[]>();\n for (const action of actions) {\n const entries = routes.get(action.routePath) ?? [];\n entries.push(action);\n routes.set(action.routePath, entries);\n }\n const routeLines = [...routes]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(\n ([routePath, entries]) =>\n ` ${JSON.stringify(routePath)}: [${entries.map((entry) => entry.descriptorName).join(\", \")}],`,\n );\n return [\n \"import type { ActionDescriptor } from '@askrjs/askr/actions';\",\n ...imports,\n \"\",\n \"const actionsByRoute: Readonly<Record<string, readonly ActionDescriptor[]>> = Object.freeze({\",\n ...routeLines,\n \"});\",\n \"\",\n \"export function actionsFor(path: string): readonly ActionDescriptor[] {\",\n \" return actionsByRoute[path] ?? [];\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderServerActionRegistry(actions: readonly DeclaredAction[]): string {\n return [\n \"import { defineServerActions, handleAction } from '@askrjs/server/askr';\",\n ...actions.map(\n (action) => `import { ${action.descriptorName} } from '../actions/${action.slug}.js';`,\n ),\n ...actions.map(\n (action) => `import { ${action.handlerName} } from './actions/${action.slug}.js';`,\n ),\n \"import type { AppDependencies } from './dependencies.js';\",\n \"\",\n \"export function createActions(deps: AppDependencies) {\",\n \" return defineServerActions({ dependencies: deps,\",\n \" csrf: { secret: process.env.CSRF_SECRET ?? 'development-only-secret' },\",\n \" },\",\n ...actions.map(\n (action) => ` handleAction(${action.descriptorName}, ${action.handlerName}),`,\n ),\n \" );\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nasync function discoverDeclaredActions(\n projectRoot: string,\n replacement: { readonly filePath: string; readonly content: string },\n): Promise<DeclaredAction[]> {\n const actionsDir = path.join(projectRoot, \"src\", \"actions\");\n const names = await fs.readdir(actionsDir).catch(() => []);\n const files = new Set(\n names.filter((name) => name.endsWith(\".ts\")).map((name) => path.join(actionsDir, name)),\n );\n files.add(replacement.filePath);\n const actions: DeclaredAction[] = [];\n for (const filePath of [...files].sort()) {\n const content =\n filePath === replacement.filePath ? replacement.content : await fs.readFile(filePath, \"utf8\");\n const descriptor = /export const (\\w+Action) = defineAction\\(/.exec(content)?.[1];\n if (!descriptor) continue;\n const routeName = `${descriptor}Route`;\n const routeMatch = new RegExp(`export const ${routeName} = (['\"])(.*?)\\\\1;`).exec(content);\n if (!routeMatch)\n throw new Error(`Action descriptor ${path.basename(filePath)} must declare ${routeName}.`);\n const slug = path.basename(filePath, \".ts\");\n actions.push({\n slug,\n descriptorName: descriptor,\n handlerName: buildIdentifier([slug]),\n routePath: routeMatch[2]!,\n });\n }\n return actions.sort((left, right) => left.slug.localeCompare(right.slug));\n}\n\nfunction renderActionDescriptor(options: {\n descriptorName: string;\n routePath: string;\n slug: string;\n}): string {\n return [\n \"import { defineAction } from '@askrjs/askr/actions';\",\n \"import { schema } from '@askrjs/schema';\",\n \"\",\n `export const ${options.descriptorName}Route = ${JSON.stringify(options.routePath)};`,\n \"\",\n `export const ${options.descriptorName} = defineAction({`,\n ` id: '${options.slug}',`,\n \" input: schema.object({ value: schema.string({ minLength: 1 }) }),\",\n \" invalidates: [],\",\n \"});\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderActionHandler(options: {\n descriptorName: string;\n handlerName: string;\n slug: string;\n}): string {\n return [\n \"import type { InferSchema } from '@askrjs/schema';\",\n `import { ${options.descriptorName} } from '../../actions/${options.slug}.js';`,\n \"import type { AppDependencies } from '../dependencies.js';\",\n \"\",\n `type Input = InferSchema<typeof ${options.descriptorName}.input>;`,\n \"\",\n `export async function ${options.handlerName}(`,\n \" _context: unknown,\",\n \" input: Input,\",\n \" deps: Pick<AppDependencies, 'actions'>,\",\n \") {\",\n \" await deps.actions.record({ action: \" +\n JSON.stringify(options.slug) +\n \", value: input.value });\",\n \" return { result: { accepted: true } };\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderActionTest(options: { descriptorName: string; slug: string }): string {\n return [\n \"import { describe, expect, it } from 'vitest';\",\n `import { ${options.descriptorName} } from '../../src/actions/${options.slug}.js';`,\n \"\",\n `describe('${options.slug} action', () => {`,\n \" it('should expose a browser-safe executable input contract', () => {\",\n ` expect(${options.descriptorName}.id).toBe('${options.slug}');`,\n ` expect(${options.descriptorName}.input.safeParse({ value: 'example' }).success).toBe(true);`,\n ` expect(${options.descriptorName}.input.safeParse({ value: '' }).success).toBe(false);`,\n \" });\",\n \"});\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction buildRoutePath(branch: BranchName, segments: string[], overridePath = \"\"): string {\n if (!overridePath) {\n const suffix = segments.join(\"/\");\n return branch === \"app\" ? `/app/${suffix}` : `/${suffix}`;\n }\n\n const normalized = overridePath.startsWith(\"/\") ? overridePath : `/${overridePath}`;\n if (branch === \"app\") {\n return normalized === \"/app\" || normalized.startsWith(\"/app/\")\n ? normalized\n : `/app${normalized}`;\n }\n\n if (normalized === \"/app\" || normalized.startsWith(\"/app/\")) {\n throw new Error(\"Public branch routes cannot live under /app.\");\n }\n\n return normalized;\n}\n\nfunction toImportSpecifier(fromFile: string, toFile: string): string {\n const relativePath = path.relative(path.dirname(fromFile), toFile).replace(/\\\\/g, \"/\");\n const withoutExtension = relativePath.replace(/\\.tsx$/i, \"\");\n return withoutExtension.startsWith(\".\") ? withoutExtension : `./${withoutExtension}`;\n}\n\nfunction createUpdatedRouteFile(\n routeFileContent: string,\n options: { componentName: string; importSpecifier: string; routePath: string },\n): string {\n const normalized = routeFileContent.replace(/\\r\\n/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const lastImportIndex = lines.reduce(\n (currentIndex, line, index) => (line.startsWith(\"import \") ? index : currentIndex),\n -1,\n );\n\n if (lastImportIndex === -1) {\n throw new Error(\"Unsupported route file: could not find import block.\");\n }\n\n const importLine = `import ${options.componentName} from '${options.importSpecifier}';`;\n if (\n normalized.includes(importLine) ||\n normalized.includes(`route('${options.routePath}',`) ||\n normalized.includes(`route(\"${options.routePath}\",`)\n ) {\n throw new Error(`Route '${options.routePath}' is already registered.`);\n }\n\n lines.splice(lastImportIndex + 1, 0, importLine);\n\n const closingIndex = lines.map((line) => line.trim()).lastIndexOf(\"}\");\n if (closingIndex === -1) {\n throw new Error(\"Unsupported route file: could not find registration function body.\");\n }\n\n lines.splice(closingIndex, 0, ` route('${options.routePath}', ${options.componentName});`);\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderPageFile(options: {\n badge: string;\n componentName: string;\n routePath: string;\n title: string;\n}): string {\n return [\n \"import {\",\n \" Badge,\",\n \" Card,\",\n \" CardContent,\",\n \" CardDescription,\",\n \" CardHeader,\",\n \" CardTitle,\",\n \"} from '@askrjs/themes/components';\",\n \"import { Stack } from '@askrjs/themes/components';\",\n \"\",\n `export default function ${options.componentName}() {`,\n \" return (\",\n ' <Stack gap=\"5\">',\n ' <section class=\"page-heading\">',\n ' <Stack gap=\"2\">',\n ` <Badge>${options.badge}</Badge>`,\n ` <h1>${options.title}</h1>`,\n ' <p class=\"lead\">',\n ` Route-first scaffold for ${options.routePath}. Keep adapters, queries, and mutations outside the page as this surface grows.`,\n \" </p>\",\n \" </Stack>\",\n \" </section>\",\n \"\",\n \" <Card>\",\n \" <CardHeader>\",\n \" <CardTitle>Next step</CardTitle>\",\n \" <CardDescription>\",\n \" Move view logic into feature folders and keep loading, empty, error, and success states explicit.\",\n \" </CardDescription>\",\n \" </CardHeader>\",\n \" <CardContent>\",\n ' <Stack gap=\"3\">',\n \" <p>Start with a focused feature boundary instead of inline data fetching.</p>\",\n \" <p>Prefer resource(), derive(), and For once the page takes on real state.</p>\",\n \" </Stack>\",\n \" </CardContent>\",\n \" </Card>\",\n \" </Stack>\",\n \" );\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nasync function addPage(parsed: ParsedArgs, io: CliIo): Promise<number> {\n if (!parsed.name) {\n io.error(\"Page name is required.\");\n return 1;\n }\n\n const branch = parsed.branch.toLowerCase() as BranchName;\n const branchConfig = BRANCH_CONFIG[branch];\n if (!branchConfig) {\n io.error(`Unsupported branch '${parsed.branch}'. Use app or public.`);\n return 1;\n }\n\n const segments = normalizePageSegments(parsed.name);\n if (segments.length === 0) {\n io.error(\"Page name must contain at least one non-empty path segment.\");\n return 1;\n }\n\n const projectRoot = path.resolve(parsed.cwd);\n const routesFile = path.join(projectRoot, ...branchConfig.routesFile);\n if (!(await pathExists(routesFile))) {\n io.error(`Unsupported project layout. Expected route file: ${routesFile}`);\n io.error(\n \"askr add page currently supports route-first SPA projects created by `askr create spa`.\",\n );\n return 1;\n }\n\n const pageFile = path.join(projectRoot, ...branchConfig.pagesDir, ...segments).concat(\".tsx\");\n if ((await pathExists(pageFile)) && !parsed.force) {\n io.error(`Page file already exists: ${pageFile}`);\n io.error(\"Pass --force to overwrite the existing file.\");\n return 1;\n }\n\n const title = parsed.title || toTitleCase(toWords(segments));\n const componentName = buildComponentName(segments);\n let routePath = \"\";\n try {\n routePath = buildRoutePath(branch, segments, parsed.routePath);\n } catch (error) {\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n const importSpecifier = toImportSpecifier(routesFile, pageFile);\n let updatedRoutes = \"\";\n try {\n const routeFileContent = await fs.readFile(routesFile, \"utf8\");\n updatedRoutes = createUpdatedRouteFile(routeFileContent, {\n componentName,\n importSpecifier,\n routePath,\n });\n } catch (error) {\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n try {\n await fs.mkdir(path.dirname(pageFile), { recursive: true });\n await fs.writeFile(\n pageFile,\n renderPageFile({\n badge: branchConfig.badge,\n componentName,\n routePath,\n title,\n }),\n \"utf8\",\n );\n await fs.writeFile(routesFile, updatedRoutes, \"utf8\");\n } catch (error) {\n io.error(\"Failed to write generated page artifacts.\");\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n io.log(`Added ${branch} page '${title}'.`);\n io.log(` File: ${path.relative(projectRoot, pageFile).replace(/\\\\/g, \"/\")}`);\n io.log(` Route: ${routePath}`);\n io.log(` Router: ${path.relative(projectRoot, routesFile).replace(/\\\\/g, \"/\")}`);\n return 0;\n}\n\nasync function addAction(parsed: ParsedArgs, io: CliIo): Promise<number> {\n if (!parsed.name) {\n io.error(\"Action name is required.\");\n return 1;\n }\n if (!parsed.routePath || !parsed.routePath.startsWith(\"/\")) {\n io.error(\"Action generation requires an absolute --route path.\");\n return 1;\n }\n\n const segments = normalizePageSegments(parsed.name);\n if (segments.length === 0) {\n io.error(\"Action name must contain at least one non-empty path segment.\");\n return 1;\n }\n\n const projectRoot = path.resolve(parsed.cwd);\n const slug = segments.join(\"-\");\n const handlerName = buildIdentifier(segments);\n const descriptorName = `${handlerName}Action`;\n const descriptorFile = path.join(projectRoot, \"src\", \"actions\", `${slug}.ts`);\n const handlerFile = path.join(projectRoot, \"src\", \"server\", \"actions\", `${slug}.ts`);\n const registryFile = path.join(projectRoot, \"src\", \"server\", \"action-registry.ts\");\n const authorizationFile = path.join(projectRoot, \"src\", \"action-authorizations.ts\");\n const testFile = path.join(projectRoot, \"tests\", \"actions\", `${slug}.test.ts`);\n\n if (!(await pathExists(registryFile)) || !(await pathExists(authorizationFile))) {\n io.error(\"Unsupported project layout. Expected an `askr create full-stack` project.\");\n return 1;\n }\n if (!parsed.force && ((await pathExists(descriptorFile)) || (await pathExists(handlerFile)))) {\n io.error(`Action '${slug}' already exists. Pass --force to replace its generated files.`);\n return 1;\n }\n\n try {\n const descriptor = renderActionDescriptor({\n descriptorName,\n routePath: parsed.routePath,\n slug,\n });\n const actions = await discoverDeclaredActions(projectRoot, {\n filePath: descriptorFile,\n content: descriptor,\n });\n await writeFileChanges([\n { filePath: descriptorFile, content: descriptor },\n {\n filePath: handlerFile,\n content: renderActionHandler({ descriptorName, handlerName, slug }),\n },\n { filePath: testFile, content: renderActionTest({ descriptorName, slug }) },\n { filePath: registryFile, content: renderServerActionRegistry(actions) },\n { filePath: authorizationFile, content: renderAuthorizationRegistry(actions) },\n ]);\n } catch (error) {\n io.error(\"Failed to write generated action artifacts.\");\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n io.log(`Added action '${slug}' for ${parsed.routePath}.`);\n io.log(` Descriptor: ${path.relative(projectRoot, descriptorFile).replace(/\\\\/g, \"/\")}`);\n io.log(` Handler: ${path.relative(projectRoot, handlerFile).replace(/\\\\/g, \"/\")}`);\n io.log(` Test: ${path.relative(projectRoot, testFile).replace(/\\\\/g, \"/\")}`);\n return 0;\n}\n\nexport async function runAddCli(\n args: string[] = process.argv.slice(2),\n io: CliIo = console,\n): Promise<number> {\n const parsed = parseArgs(args);\n\n if (parsed.errors.length > 0) {\n for (const message of parsed.errors) {\n io.error(message);\n }\n return 1;\n }\n\n if (!parsed.command || parsed.help) {\n io.log(helpText());\n return 0;\n }\n\n if (parsed.command === \"page\") {\n return addPage(parsed, io);\n }\n\n if (parsed.command === \"action\") {\n return addAction(parsed, io);\n }\n\n io.error(`Unknown add command: ${parsed.command}`);\n io.error(\"Run `askr add --help` to see available commands.\");\n return 1;\n}\n\nasync function main(): Promise<void> {\n const code = await runAddCli(process.argv.slice(2));\n process.exit(code);\n}\n\nif (isDirectExecution(import.meta.url)) {\n void main();\n}\n"],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -1,11 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as isDirectExecution } from "./is-direct-execution-Cdlr-ZUl.js";
3
- import { t as runAddCli } from "./add-DqhqRzBQ.js";
4
- import { n as runSkillsCli } from "./skills-Bh0mEhIx.js";
5
- import { runCreateCli } from "./create.js";
6
- import { runOpenApiCli } from "./openapi.js";
7
- import { runSsgCli } from "./ssg.js";
8
- import { t as runUpdateCli } from "./update-DyW1na5V.js";
9
3
  import path from "node:path";
10
4
  import { readFileSync } from "node:fs";
11
5
  import { fileURLToPath } from "node:url";
@@ -40,10 +34,13 @@ function printHelp(io = console) {
40
34
  io.log("Commands:");
41
35
  io.log(" add Generate pages or declared actions into an Askr project");
42
36
  io.log(" create Create a new Askr app from a template or product prompt");
37
+ io.log(" generate Generate an @askrjs/fetch client from OpenAPI");
43
38
  io.log(" openapi Generate or check an OpenAPI YAML artifact");
44
39
  io.log(" skills Install or sync Askr agent skills");
45
40
  io.log(" ssg Run static-site generation");
46
- io.log(" update Plan or apply dependency manifest updates");
41
+ io.log(" outdated List available dependency updates");
42
+ io.log(" update Apply safe dependency updates");
43
+ io.log(" upgrade Apply latest peer-compatible dependency upgrades");
47
44
  io.log("");
48
45
  io.log("Options:");
49
46
  io.log(" --help, -h Show help");
@@ -58,7 +55,9 @@ function printHelp(io = console) {
58
55
  io.log(" askr openapi --check");
59
56
  io.log(" askr skills review foundation --cwd ./candidate-app");
60
57
  io.log(" askr ssg --config ./ssg.config.ts --output ./dist/static");
61
- io.log(" askr update -u");
58
+ io.log(" askr outdated");
59
+ io.log(" askr update");
60
+ io.log(" askr upgrade");
62
61
  }
63
62
  async function runCli(args = process.argv.slice(2), io = console) {
64
63
  const command = args[0];
@@ -70,12 +69,42 @@ async function runCli(args = process.argv.slice(2), io = console) {
70
69
  printHelp(io);
71
70
  return 0;
72
71
  }
73
- if (command === "create") return runCreateCli(args.slice(1), io);
74
- if (command === "add") return runAddCli(args.slice(1), io);
75
- if (command === "ssg") return runSsgCli(args.slice(1), void 0, io);
76
- if (command === "openapi") return runOpenApiCli(args.slice(1), io);
77
- if (command === "skills") return runSkillsCli(args.slice(1), io);
78
- if (command === "update") return runUpdateCli(args.slice(1), io);
72
+ if (command === "create") {
73
+ const { runCreateCli } = await import("./create.js");
74
+ return runCreateCli(args.slice(1), io);
75
+ }
76
+ if (command === "add") {
77
+ const { runAddCli } = await import("./add.js");
78
+ return runAddCli(args.slice(1), io);
79
+ }
80
+ if (command === "generate") {
81
+ const { runGenerateCli } = await import("./generate.js");
82
+ return runGenerateCli(args.slice(1), io);
83
+ }
84
+ if (command === "ssg") {
85
+ const { runSsgCli } = await import("./ssg.js");
86
+ return runSsgCli(args.slice(1), void 0, io);
87
+ }
88
+ if (command === "openapi") {
89
+ const { runOpenApiCli } = await import("./openapi.js");
90
+ return runOpenApiCli(args.slice(1), io);
91
+ }
92
+ if (command === "skills") {
93
+ const { runSkillsCli } = await import("./skills.js");
94
+ return runSkillsCli(args.slice(1), io);
95
+ }
96
+ if (command === "update") {
97
+ const { runUpdateCli } = await import("./update.js");
98
+ return runUpdateCli(args.slice(1), io);
99
+ }
100
+ if (command === "upgrade") {
101
+ const { runUpgradeCli } = await import("./update.js");
102
+ return runUpgradeCli(args.slice(1), io);
103
+ }
104
+ if (command === "outdated") {
105
+ const { runOutdatedCli } = await import("./update.js");
106
+ return runOutdatedCli(args.slice(1), io);
107
+ }
79
108
  io.error(`Unknown command: ${command}`);
80
109
  io.error("Run `askr --help` to see available commands.");
81
110
  return 1;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/bin/package-version.ts","../src/bin/cli.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nlet cachedVersion: string | null = null;\n\nexport function getCliVersion(): string {\n if (cachedVersion) {\n return cachedVersion;\n }\n\n let currentDir = path.dirname(fileURLToPath(import.meta.url));\n\n while (true) {\n const packageJsonPath = path.join(currentDir, \"package.json\");\n\n try {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n name?: string;\n version?: string;\n };\n\n if (parsed.name === \"@askrjs/cli\" && typeof parsed.version === \"string\") {\n cachedVersion = parsed.version;\n return cachedVersion;\n }\n } catch {\n // Keep walking upward until we find the package root.\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n break;\n }\n currentDir = parentDir;\n }\n\n throw new Error(\"Could not determine @askrjs/cli package version.\");\n}\n","#!/usr/bin/env node\n\nimport { runAddCli } from \"./add\";\nimport { runCreateCli } from \"./create\";\nimport { isDirectExecution } from \"./is-direct-execution\";\nimport { getCliVersion } from \"./package-version\";\nimport { runOpenApiCli } from \"./openapi\";\nimport { runSkillsCli } from \"./skills\";\nimport { runSsgCli } from \"./ssg\";\nimport { runUpdateCli } from \"./update\";\n\ntype CliIo = Pick<Console, \"error\" | \"log\">;\n\nfunction printHelp(io: CliIo = console): void {\n io.log(\"askr - Unified CLI for the Askr platform\");\n io.log(\"\");\n io.log(\"Usage:\");\n io.log(\" askr <command> [args]\");\n io.log(\"\");\n io.log(\"Commands:\");\n io.log(\" add Generate pages or declared actions into an Askr project\");\n io.log(\" create Create a new Askr app from a template or product prompt\");\n io.log(\" openapi Generate or check an OpenAPI YAML artifact\");\n io.log(\" skills Install or sync Askr agent skills\");\n io.log(\" ssg Run static-site generation\");\n io.log(\" update Plan or apply dependency manifest updates\");\n io.log(\"\");\n io.log(\"Options:\");\n io.log(\" --help, -h Show help\");\n io.log(\" --version, -v Print CLI version\");\n io.log(\"\");\n io.log(\"Examples:\");\n io.log(\" askr create startkit my-app\");\n io.log(' askr create --prompt \"Agent workflow console with approvals\"');\n io.log(\" askr add page audit-log\");\n io.log(\" askr add action approve-request --route /requests/{id}\");\n io.log(\" askr skills install\");\n io.log(\" askr openapi --check\");\n io.log(\" askr skills review foundation --cwd ./candidate-app\");\n io.log(\" askr ssg --config ./ssg.config.ts --output ./dist/static\");\n io.log(\" askr update -u\");\n}\n\nexport async function runCli(\n args: string[] = process.argv.slice(2),\n io: CliIo = console,\n): Promise<number> {\n const command = args[0];\n\n if (command === \"--version\" || command === \"-v\") {\n io.log(getCliVersion());\n return 0;\n }\n\n if (!command || command === \"--help\" || command === \"-h\") {\n printHelp(io);\n return 0;\n }\n\n if (command === \"create\") {\n return runCreateCli(args.slice(1), io);\n }\n\n if (command === \"add\") {\n return runAddCli(args.slice(1), io);\n }\n\n if (command === \"ssg\") {\n return runSsgCli(args.slice(1), undefined, io);\n }\n\n if (command === \"openapi\") {\n return runOpenApiCli(args.slice(1), io);\n }\n\n if (command === \"skills\") {\n return runSkillsCli(args.slice(1), io);\n }\n\n if (command === \"update\") {\n return runUpdateCli(args.slice(1), io);\n }\n\n io.error(`Unknown command: ${command}`);\n io.error(\"Run `askr --help` to see available commands.\");\n return 1;\n}\n\nasync function main(): Promise<void> {\n const code = await runCli(process.argv.slice(2));\n process.exit(code);\n}\n\nif (isDirectExecution(import.meta.url)) {\n void main();\n}\n"],"mappings":";;;;;;;;;;;;AAIA,IAAI,gBAA+B;AAEnC,SAAgB,gBAAwB;CACtC,IAAI,eACF,OAAO;CAGT,IAAI,aAAa,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CAE5D,OAAO,MAAM;EACX,MAAM,kBAAkB,KAAK,KAAK,YAAY,cAAc;EAE5D,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,aAAa,iBAAiB,MAAM,CAAC;GAK/D,IAAI,OAAO,SAAS,iBAAiB,OAAO,OAAO,YAAY,UAAU;IACvE,gBAAgB,OAAO;IACvB,OAAO;GACT;EACF,QAAQ,CAER;EAEA,MAAM,YAAY,KAAK,QAAQ,UAAU;EACzC,IAAI,cAAc,YAChB;EAEF,aAAa;CACf;CAEA,MAAM,IAAI,MAAM,kDAAkD;AACpE;;;ACzBA,SAAS,UAAU,KAAY,SAAe;CAC5C,GAAG,IAAI,0CAA0C;CACjD,GAAG,IAAI,EAAE;CACT,GAAG,IAAI,QAAQ;CACf,GAAG,IAAI,yBAAyB;CAChC,GAAG,IAAI,EAAE;CACT,GAAG,IAAI,WAAW;CAClB,GAAG,IAAI,sEAAsE;CAC7E,GAAG,IAAI,sEAAsE;CAC7E,GAAG,IAAI,yDAAyD;CAChE,GAAG,IAAI,gDAAgD;CACvD,GAAG,IAAI,yCAAyC;CAChD,GAAG,IAAI,wDAAwD;CAC/D,GAAG,IAAI,EAAE;CACT,GAAG,IAAI,UAAU;CACjB,GAAG,IAAI,4BAA4B;CACnC,GAAG,IAAI,oCAAoC;CAC3C,GAAG,IAAI,EAAE;CACT,GAAG,IAAI,WAAW;CAClB,GAAG,IAAI,+BAA+B;CACtC,GAAG,IAAI,kEAAgE;CACvE,GAAG,IAAI,2BAA2B;CAClC,GAAG,IAAI,0DAA0D;CACjE,GAAG,IAAI,uBAAuB;CAC9B,GAAG,IAAI,wBAAwB;CAC/B,GAAG,IAAI,uDAAuD;CAC9D,GAAG,IAAI,4DAA4D;CACnE,GAAG,IAAI,kBAAkB;AAC3B;AAEA,eAAsB,OACpB,OAAiB,QAAQ,KAAK,MAAM,CAAC,GACrC,KAAY,SACK;CACjB,MAAM,UAAU,KAAK;CAErB,IAAI,YAAY,eAAe,YAAY,MAAM;EAC/C,GAAG,IAAI,cAAc,CAAC;EACtB,OAAO;CACT;CAEA,IAAI,CAAC,WAAW,YAAY,YAAY,YAAY,MAAM;EACxD,UAAU,EAAE;EACZ,OAAO;CACT;CAEA,IAAI,YAAY,UACd,OAAO,aAAa,KAAK,MAAM,CAAC,GAAG,EAAE;CAGvC,IAAI,YAAY,OACd,OAAO,UAAU,KAAK,MAAM,CAAC,GAAG,EAAE;CAGpC,IAAI,YAAY,OACd,OAAO,UAAU,KAAK,MAAM,CAAC,GAAG,KAAA,GAAW,EAAE;CAG/C,IAAI,YAAY,WACd,OAAO,cAAc,KAAK,MAAM,CAAC,GAAG,EAAE;CAGxC,IAAI,YAAY,UACd,OAAO,aAAa,KAAK,MAAM,CAAC,GAAG,EAAE;CAGvC,IAAI,YAAY,UACd,OAAO,aAAa,KAAK,MAAM,CAAC,GAAG,EAAE;CAGvC,GAAG,MAAM,oBAAoB,SAAS;CACtC,GAAG,MAAM,8CAA8C;CACvD,OAAO;AACT;AAEA,eAAe,OAAsB;CACnC,MAAM,OAAO,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC;CAC/C,QAAQ,KAAK,IAAI;AACnB;AAEA,IAAI,kBAAkB,OAAO,KAAK,GAAG,GACnC,KAAU"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/bin/package-version.ts","../src/bin/cli.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nlet cachedVersion: string | null = null;\n\nexport function getCliVersion(): string {\n if (cachedVersion) {\n return cachedVersion;\n }\n\n let currentDir = path.dirname(fileURLToPath(import.meta.url));\n\n while (true) {\n const packageJsonPath = path.join(currentDir, \"package.json\");\n\n try {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n name?: string;\n version?: string;\n };\n\n if (parsed.name === \"@askrjs/cli\" && typeof parsed.version === \"string\") {\n cachedVersion = parsed.version;\n return cachedVersion;\n }\n } catch {\n // Keep walking upward until we find the package root.\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n break;\n }\n currentDir = parentDir;\n }\n\n throw new Error(\"Could not determine @askrjs/cli package version.\");\n}\n","#!/usr/bin/env node\n\nimport { isDirectExecution } from \"./is-direct-execution\";\nimport { getCliVersion } from \"./package-version\";\n\ntype CliIo = Pick<Console, \"error\" | \"log\">;\n\nfunction printHelp(io: CliIo = console): void {\n io.log(\"askr - Unified CLI for the Askr platform\");\n io.log(\"\");\n io.log(\"Usage:\");\n io.log(\" askr <command> [args]\");\n io.log(\"\");\n io.log(\"Commands:\");\n io.log(\" add Generate pages or declared actions into an Askr project\");\n io.log(\" create Create a new Askr app from a template or product prompt\");\n io.log(\" generate Generate an @askrjs/fetch client from OpenAPI\");\n io.log(\" openapi Generate or check an OpenAPI YAML artifact\");\n io.log(\" skills Install or sync Askr agent skills\");\n io.log(\" ssg Run static-site generation\");\n io.log(\" outdated List available dependency updates\");\n io.log(\" update Apply safe dependency updates\");\n io.log(\" upgrade Apply latest peer-compatible dependency upgrades\");\n io.log(\"\");\n io.log(\"Options:\");\n io.log(\" --help, -h Show help\");\n io.log(\" --version, -v Print CLI version\");\n io.log(\"\");\n io.log(\"Examples:\");\n io.log(\" askr create startkit my-app\");\n io.log(' askr create --prompt \"Agent workflow console with approvals\"');\n io.log(\" askr add page audit-log\");\n io.log(\" askr add action approve-request --route /requests/{id}\");\n io.log(\" askr skills install\");\n io.log(\" askr openapi --check\");\n io.log(\" askr skills review foundation --cwd ./candidate-app\");\n io.log(\" askr ssg --config ./ssg.config.ts --output ./dist/static\");\n io.log(\" askr outdated\");\n io.log(\" askr update\");\n io.log(\" askr upgrade\");\n}\n\nexport async function runCli(\n args: string[] = process.argv.slice(2),\n io: CliIo = console,\n): Promise<number> {\n const command = args[0];\n\n if (command === \"--version\" || command === \"-v\") {\n io.log(getCliVersion());\n return 0;\n }\n\n if (!command || command === \"--help\" || command === \"-h\") {\n printHelp(io);\n return 0;\n }\n\n if (command === \"create\") {\n const { runCreateCli } = await import(\"./create\");\n return runCreateCli(args.slice(1), io);\n }\n\n if (command === \"add\") {\n const { runAddCli } = await import(\"./add\");\n return runAddCli(args.slice(1), io);\n }\n\n if (command === \"generate\") {\n const { runGenerateCli } = await import(\"./generate\");\n return runGenerateCli(args.slice(1), io);\n }\n\n if (command === \"ssg\") {\n const { runSsgCli } = await import(\"./ssg\");\n return runSsgCli(args.slice(1), undefined, io);\n }\n\n if (command === \"openapi\") {\n const { runOpenApiCli } = await import(\"./openapi\");\n return runOpenApiCli(args.slice(1), io);\n }\n\n if (command === \"skills\") {\n const { runSkillsCli } = await import(\"./skills\");\n return runSkillsCli(args.slice(1), io);\n }\n\n if (command === \"update\") {\n const { runUpdateCli } = await import(\"./update\");\n return runUpdateCli(args.slice(1), io);\n }\n\n if (command === \"upgrade\") {\n const { runUpgradeCli } = await import(\"./update\");\n return runUpgradeCli(args.slice(1), io);\n }\n\n if (command === \"outdated\") {\n const { runOutdatedCli } = await import(\"./update\");\n return runOutdatedCli(args.slice(1), io);\n }\n\n io.error(`Unknown command: ${command}`);\n io.error(\"Run `askr --help` to see available commands.\");\n return 1;\n}\n\nasync function main(): Promise<void> {\n const code = await runCli(process.argv.slice(2));\n process.exit(code);\n}\n\nif (isDirectExecution(import.meta.url)) {\n void main();\n}\n"],"mappings":"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"}
@@ -0,0 +1,325 @@
1
+ import { t as analyzeRange } from "./range-YUs9eimn.js";
2
+ import { t as parseDependencySpecification } from "./specification-DXnDOC-0.js";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { load } from "js-yaml";
6
+ import { minimatch } from "minimatch";
7
+ //#region src/update/types.ts
8
+ const DEPENDENCY_SECTIONS = [
9
+ "dependencies",
10
+ "devDependencies",
11
+ "optionalDependencies",
12
+ "peerDependencies"
13
+ ];
14
+ //#endregion
15
+ //#region src/update/discovery.ts
16
+ async function isFile(filePath) {
17
+ return (await fs.stat(filePath).catch(() => null))?.isFile() ?? false;
18
+ }
19
+ async function readManifest(manifestPath) {
20
+ let source;
21
+ try {
22
+ source = await fs.readFile(manifestPath, "utf8");
23
+ } catch {
24
+ throw new Error(`Unable to read manifest: ${manifestPath}`);
25
+ }
26
+ try {
27
+ const value = JSON.parse(source.replace(/^\uFEFF/, ""));
28
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
29
+ return value;
30
+ } catch {
31
+ throw new Error(`Malformed package manifest: ${manifestPath}`);
32
+ }
33
+ }
34
+ function packageWorkspacePatterns(manifest) {
35
+ if (!("workspaces" in manifest)) return null;
36
+ const declaration = manifest.workspaces;
37
+ const patterns = Array.isArray(declaration) ? declaration : declaration && typeof declaration === "object" && !Array.isArray(declaration) ? declaration.packages : null;
38
+ if (!Array.isArray(patterns) || patterns.some((pattern) => typeof pattern !== "string")) throw new Error("Invalid package.json workspaces declaration; expected an array of paths.");
39
+ return patterns;
40
+ }
41
+ async function pnpmWorkspacePatterns(root) {
42
+ const workspacePath = path.join(root, "pnpm-workspace.yaml");
43
+ if (!await isFile(workspacePath)) return null;
44
+ const source = await fs.readFile(workspacePath, "utf8");
45
+ let value;
46
+ try {
47
+ value = load(source);
48
+ } catch {
49
+ throw new Error(`Malformed pnpm workspace declaration: ${workspacePath}`);
50
+ }
51
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid pnpm workspace declaration; expected a mapping with packages.");
52
+ const packages = value.packages;
53
+ if (!Array.isArray(packages) || packages.some((pattern) => typeof pattern !== "string")) throw new Error("Invalid pnpm workspace declaration; expected packages to be an array.");
54
+ return packages;
55
+ }
56
+ async function findProjectRoot(start) {
57
+ const resolved = path.resolve(start);
58
+ if (!(await fs.stat(resolved).catch(() => null))?.isDirectory()) throw new Error(`Working directory does not exist: ${resolved}`);
59
+ let directory = resolved;
60
+ let nearestManifestDirectory = null;
61
+ while (true) {
62
+ const manifestPath = path.join(directory, "package.json");
63
+ const hasManifest = await isFile(manifestPath);
64
+ if (hasManifest) {
65
+ const manifest = await readManifest(manifestPath);
66
+ nearestManifestDirectory ??= directory;
67
+ if (packageWorkspacePatterns(manifest) !== null) return directory;
68
+ }
69
+ if (await isFile(path.join(directory, "pnpm-workspace.yaml"))) {
70
+ if (!hasManifest) throw new Error(`Workspace root is missing package.json: ${directory}`);
71
+ await pnpmWorkspacePatterns(directory);
72
+ return directory;
73
+ }
74
+ const parent = path.dirname(directory);
75
+ if (parent === directory) break;
76
+ directory = parent;
77
+ }
78
+ if (nearestManifestDirectory) return nearestManifestDirectory;
79
+ throw new Error(`No package.json found from ${resolved}.`);
80
+ }
81
+ function parsePolicy(manifest) {
82
+ const empty = {
83
+ ignore: [],
84
+ tags: {}
85
+ };
86
+ if (!("askr" in manifest)) return empty;
87
+ if (!manifest.askr || typeof manifest.askr !== "object" || Array.isArray(manifest.askr)) throw new Error("Invalid askr update configuration in the workspace root.");
88
+ const update = manifest.askr.update;
89
+ if (update === void 0) return empty;
90
+ if (!update || typeof update !== "object" || Array.isArray(update)) throw new Error("Invalid askr.update configuration in the workspace root.");
91
+ const config = update;
92
+ const ignore = config.ignore ?? [];
93
+ const tags = config.tags ?? {};
94
+ if (!Array.isArray(ignore) || ignore.some((entry) => typeof entry !== "string")) throw new Error("Invalid askr.update.ignore configuration; expected an array of patterns.");
95
+ if (!tags || typeof tags !== "object" || Array.isArray(tags) || Object.entries(tags).some(([name, tag]) => !name || typeof tag !== "string" || !tag)) throw new Error("Invalid askr.update.tags configuration; expected package-to-tag strings.");
96
+ return {
97
+ ignore,
98
+ tags
99
+ };
100
+ }
101
+ function relativeManifestPath(root, manifestPath) {
102
+ return path.relative(root, manifestPath).split(path.sep).join("/") || "package.json";
103
+ }
104
+ function workspaceName(manifest, fallback) {
105
+ return typeof manifest.name === "string" && manifest.name.trim() ? manifest.name : fallback;
106
+ }
107
+ const WORKSPACE_GLOB_OPTIONS = {
108
+ dot: true,
109
+ nocase: process.platform === "win32",
110
+ windowsPathsNoEscape: true
111
+ };
112
+ function normalizeWorkspacePattern(pattern) {
113
+ const leadingBangs = pattern.match(/^!+/)?.[0].length ?? 0;
114
+ const negative = leadingBangs % 2 === 1;
115
+ let value = pattern.slice(leadingBangs);
116
+ value = value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
117
+ if (value.endsWith("/package.json")) value = value.slice(0, -13);
118
+ if (value === ".." || value.startsWith("../")) throw new Error(`Workspace patterns outside the project root are unsupported: ${pattern}`);
119
+ return {
120
+ negative,
121
+ value: value || "."
122
+ };
123
+ }
124
+ function matchesWorkspace(relativeDirectory, patterns) {
125
+ let included = false;
126
+ for (const pattern of patterns) {
127
+ const normalized = normalizeWorkspacePattern(pattern);
128
+ if (minimatch(relativeDirectory, normalized.value, WORKSPACE_GLOB_OPTIONS)) included = !normalized.negative;
129
+ }
130
+ return included;
131
+ }
132
+ function mayContainWorkspace(relativeDirectory, patterns) {
133
+ return patterns.some((pattern) => {
134
+ const normalized = normalizeWorkspacePattern(pattern);
135
+ return !normalized.negative && minimatch(relativeDirectory, normalized.value, {
136
+ ...WORKSPACE_GLOB_OPTIONS,
137
+ partial: true
138
+ });
139
+ });
140
+ }
141
+ async function mapDeclaredWorkspaces(root, patterns) {
142
+ const directories = [];
143
+ if (matchesWorkspace(".", patterns)) directories.push(root);
144
+ const visit = async (directory, relativeDirectory) => {
145
+ const entries = await fs.readdir(directory, { withFileTypes: true });
146
+ entries.sort((left, right) => left.name.localeCompare(right.name));
147
+ for (const entry of entries) {
148
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
149
+ const childRelative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
150
+ if (!mayContainWorkspace(childRelative, patterns)) continue;
151
+ const child = path.join(directory, entry.name);
152
+ const isSymbolicDirectory = entry.isSymbolicLink() && (await fs.stat(child).catch(() => null))?.isDirectory();
153
+ if (!entry.isDirectory() && !isSymbolicDirectory) continue;
154
+ if (matchesWorkspace(childRelative, patterns) && await isFile(path.join(child, "package.json"))) directories.push(child);
155
+ if (!entry.isSymbolicLink()) await visit(child, childRelative);
156
+ }
157
+ };
158
+ await visit(root, "");
159
+ const mapped = /* @__PURE__ */ new Map();
160
+ for (const directory of directories.sort((left, right) => left.localeCompare(right))) {
161
+ const name = workspaceName(await readManifest(path.join(directory, "package.json")), path.basename(directory));
162
+ if (mapped.has(name)) throw new Error(`Multiple workspaces with the same name '${name}'.`);
163
+ mapped.set(name, directory);
164
+ }
165
+ return mapped;
166
+ }
167
+ async function discoverWorkspaces(root) {
168
+ const rootManifestPath = path.join(root, "package.json");
169
+ const rootManifest = await readManifest(rootManifestPath);
170
+ const policy = parsePolicy(rootManifest);
171
+ const packagePatterns = packageWorkspacePatterns(rootManifest) ?? [];
172
+ const pnpmPatterns = await pnpmWorkspacePatterns(root) ?? [];
173
+ const patterns = [...packagePatterns, ...pnpmPatterns];
174
+ const mapped = patterns.length > 0 ? await mapDeclaredWorkspaces(root, patterns) : /* @__PURE__ */ new Map();
175
+ const rootName = workspaceName(rootManifest, "(root)");
176
+ if (mapped.has(rootName)) throw new Error(`Duplicate workspace name '${rootName}' includes the workspace root.`);
177
+ const workspaces = [{
178
+ name: rootName,
179
+ directory: root,
180
+ manifestPath: rootManifestPath,
181
+ relativeManifestPath: "package.json",
182
+ manifest: rootManifest,
183
+ isRoot: true
184
+ }];
185
+ for (const [mappedName, directory] of mapped) {
186
+ const manifestPath = path.join(directory, "package.json");
187
+ const manifest = await readManifest(manifestPath);
188
+ workspaces.push({
189
+ name: workspaceName(manifest, mappedName),
190
+ directory,
191
+ manifestPath,
192
+ relativeManifestPath: relativeManifestPath(root, manifestPath),
193
+ manifest,
194
+ isRoot: false
195
+ });
196
+ }
197
+ workspaces.sort((left, right) => {
198
+ if (left.isRoot !== right.isRoot) return left.isRoot ? -1 : 1;
199
+ return left.name.localeCompare(right.name) || left.manifestPath.localeCompare(right.manifestPath);
200
+ });
201
+ return {
202
+ policy,
203
+ rootManifest,
204
+ workspaces
205
+ };
206
+ }
207
+ function matchesAny(value, patterns) {
208
+ return patterns.some((pattern) => minimatch(value, pattern, { dot: true }));
209
+ }
210
+ function isRegistryPackageName(packageName) {
211
+ if (!packageName || packageName.length > 214 || /^[._-]/.test(packageName) || /[\s%\\:]/.test(packageName)) return false;
212
+ if (!packageName.startsWith("@")) return !packageName.includes("/");
213
+ const parts = packageName.slice(1).split("/");
214
+ return parts.length === 2 && parts.every((part) => part.length > 0 && !/^[._-]/.test(part));
215
+ }
216
+ function classifySpecification(packageName, specification, directory, localNames) {
217
+ if (localNames.has(packageName)) return {
218
+ kind: "local",
219
+ registryManaged: false,
220
+ reason: "dependency resolves to a discovered workspace"
221
+ };
222
+ if (/^workspace:/i.test(specification)) return {
223
+ kind: "local",
224
+ registryManaged: false,
225
+ reason: "workspace protocol is not registry-managed"
226
+ };
227
+ if (/^link:/i.test(specification)) return {
228
+ kind: "local",
229
+ registryManaged: false,
230
+ reason: "link protocol is not registry-managed"
231
+ };
232
+ if (!isRegistryPackageName(packageName)) return {
233
+ kind: "manual",
234
+ registryManaged: false,
235
+ reason: "invalid registry package name"
236
+ };
237
+ const parsed = parseDependencySpecification(specification);
238
+ if ([
239
+ "file",
240
+ "git",
241
+ "remote"
242
+ ].includes(parsed.type)) return {
243
+ kind: "local",
244
+ registryManaged: false,
245
+ reason: `${parsed.type} specification is not registry-managed`
246
+ };
247
+ if (parsed.type === "alias") return {
248
+ kind: "manual",
249
+ registryManaged: false,
250
+ reason: "npm aliases require manual review"
251
+ };
252
+ if (parsed.type === "tag") return {
253
+ kind: "current",
254
+ registryManaged: true,
255
+ reason: "tracking tag is not rewritten"
256
+ };
257
+ if (parsed.type !== "range" && parsed.type !== "version") return {
258
+ kind: "manual",
259
+ registryManaged: false,
260
+ reason: "unsupported dependency specification"
261
+ };
262
+ const analysis = analyzeRange(specification);
263
+ if (analysis.tracking) return {
264
+ kind: "current",
265
+ registryManaged: true,
266
+ reason: analysis.reason
267
+ };
268
+ if (!analysis.shape) return {
269
+ kind: "manual",
270
+ registryManaged: false,
271
+ reason: analysis.reason
272
+ };
273
+ return {
274
+ kind: "fetch",
275
+ registryManaged: true,
276
+ reason: ""
277
+ };
278
+ }
279
+ function collectOccurrences(root, workspaces, localNames, policy, packagePatterns) {
280
+ const occurrences = [];
281
+ for (const workspace of workspaces) for (const section of DEPENDENCY_SECTIONS) {
282
+ const dependencies = workspace.manifest[section];
283
+ if (dependencies === void 0) continue;
284
+ if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) throw new Error(`Invalid ${section} in ${workspace.relativeManifestPath}; expected an object.`);
285
+ for (const [packageName, specification] of Object.entries(dependencies)) {
286
+ if (typeof specification !== "string") throw new Error(`Invalid ${section}.${packageName} in ${workspace.relativeManifestPath}.`);
287
+ if (packagePatterns.length > 0 && !matchesAny(packageName, packagePatterns)) continue;
288
+ if (packagePatterns.length === 0 && matchesAny(packageName, policy.ignore)) continue;
289
+ occurrences.push({
290
+ package: packageName,
291
+ workspace: workspace.name,
292
+ manifestPath: workspace.manifestPath,
293
+ relativeManifestPath: relativeManifestPath(root, workspace.manifestPath),
294
+ section,
295
+ currentSpecification: specification,
296
+ ...classifySpecification(packageName, specification, workspace.directory, localNames)
297
+ });
298
+ }
299
+ }
300
+ const sectionOrder = new Map(DEPENDENCY_SECTIONS.map((section, index) => [section, index]));
301
+ occurrences.sort((left, right) => left.package.localeCompare(right.package) || left.workspace.localeCompare(right.workspace) || left.relativeManifestPath.localeCompare(right.relativeManifestPath) || sectionOrder.get(left.section) - sectionOrder.get(right.section));
302
+ return occurrences;
303
+ }
304
+ async function discoverProject(options) {
305
+ const root = await findProjectRoot(options.cwd);
306
+ const { policy, workspaces } = await discoverWorkspaces(root);
307
+ const selectedWorkspaces = options.workspacePatterns.length === 0 ? workspaces : workspaces.filter((workspace) => matchesAny(workspace.name, options.workspacePatterns));
308
+ if (selectedWorkspaces.length === 0) throw new Error("No discovered workspace matches the requested --workspace filters.");
309
+ const localNames = new Set(workspaces.map((workspace) => workspace.name));
310
+ return {
311
+ root,
312
+ workspaces,
313
+ selectedWorkspaces,
314
+ policy,
315
+ occurrences: collectOccurrences(root, selectedWorkspaces, localNames, policy, options.packagePatterns),
316
+ contextOccurrences: collectOccurrences(root, selectedWorkspaces, localNames, {
317
+ ignore: [],
318
+ tags: policy.tags
319
+ }, [])
320
+ };
321
+ }
322
+ //#endregion
323
+ export { discoverProject };
324
+
325
+ //# sourceMappingURL=discovery-Difb7Y4G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery-Difb7Y4G.js","names":[],"sources":["../src/update/types.ts","../src/update/discovery.ts"],"sourcesContent":["export const DEPENDENCY_SECTIONS = [\n \"dependencies\",\n \"devDependencies\",\n \"optionalDependencies\",\n \"peerDependencies\",\n] as const;\n\nexport type DependencySection = (typeof DEPENDENCY_SECTIONS)[number];\n\nexport type UpdateStatus = \"current\" | \"safe\" | \"breaking\" | \"local\" | \"manual\" | \"error\";\n\nexport interface UpdatePolicy {\n ignore: string[];\n tags: Record<string, string>;\n}\n\nexport interface WorkspaceManifest {\n name: string;\n directory: string;\n manifestPath: string;\n relativeManifestPath: string;\n manifest: Record<string, unknown>;\n isRoot: boolean;\n}\n\nexport interface DependencyOccurrence {\n package: string;\n workspace: string;\n manifestPath: string;\n relativeManifestPath: string;\n section: DependencySection;\n currentSpecification: string;\n kind: \"fetch\" | \"local\" | \"manual\" | \"current\";\n registryManaged: boolean;\n reason: string;\n}\n\nexport interface DiscoveredProject {\n root: string;\n workspaces: WorkspaceManifest[];\n selectedWorkspaces: WorkspaceManifest[];\n policy: UpdatePolicy;\n occurrences: DependencyOccurrence[];\n contextOccurrences: DependencyOccurrence[];\n}\n\nexport interface Packument {\n \"dist-tags\"?: Record<string, unknown>;\n versions?: Record<string, unknown>;\n}\n\nexport interface PlannedOccurrence {\n workspace: string;\n manifestPath: string;\n relativeManifestPath: string;\n section: DependencySection;\n currentSpecification: string;\n proposedSpecification: string | null;\n status: UpdateStatus;\n reason: string;\n allowedVersion: string | null;\n}\n\nexport interface PackageDecision {\n package: string;\n selectedTag: string;\n targetVersion: string | null;\n status: UpdateStatus;\n reason: string;\n occurrences: PlannedOccurrence[];\n}\n\nexport interface UpdateSummary extends Record<UpdateStatus, number> {\n packages: number;\n occurrences: number;\n changedOccurrences: number;\n}\n\nexport interface UpdatePlan {\n decisions: PackageDecision[];\n summary: UpdateSummary;\n hasErrors: boolean;\n}\n\nexport interface ManifestValueEdit {\n manifestPath: string;\n section: DependencySection;\n package: string;\n currentSpecification: string;\n proposedSpecification: string;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { load } from \"js-yaml\";\nimport { minimatch } from \"minimatch\";\nimport { analyzeRange } from \"./range\";\nimport { parseDependencySpecification } from \"./specification\";\nimport {\n DEPENDENCY_SECTIONS,\n type DependencyOccurrence,\n type DiscoveredProject,\n type UpdatePolicy,\n type WorkspaceManifest,\n} from \"./types\";\n\ninterface DiscoveryOptions {\n cwd: string;\n packagePatterns: string[];\n workspacePatterns: string[];\n}\n\nasync function isFile(filePath: string): Promise<boolean> {\n return (await fs.stat(filePath).catch(() => null))?.isFile() ?? false;\n}\n\nasync function readManifest(manifestPath: string): Promise<Record<string, unknown>> {\n let source: string;\n try {\n source = await fs.readFile(manifestPath, \"utf8\");\n } catch {\n throw new Error(`Unable to read manifest: ${manifestPath}`);\n }\n\n try {\n const value = JSON.parse(source.replace(/^\\uFEFF/, \"\")) as unknown;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error();\n return value as Record<string, unknown>;\n } catch {\n throw new Error(`Malformed package manifest: ${manifestPath}`);\n }\n}\n\nfunction packageWorkspacePatterns(manifest: Record<string, unknown>): string[] | null {\n if (!(\"workspaces\" in manifest)) return null;\n const declaration = manifest.workspaces;\n const patterns = Array.isArray(declaration)\n ? declaration\n : declaration && typeof declaration === \"object\" && !Array.isArray(declaration)\n ? (declaration as Record<string, unknown>).packages\n : null;\n\n if (!Array.isArray(patterns) || patterns.some((pattern) => typeof pattern !== \"string\")) {\n throw new Error(\"Invalid package.json workspaces declaration; expected an array of paths.\");\n }\n return patterns as string[];\n}\n\nasync function pnpmWorkspacePatterns(root: string): Promise<string[] | null> {\n const workspacePath = path.join(root, \"pnpm-workspace.yaml\");\n if (!(await isFile(workspacePath))) return null;\n\n const source = await fs.readFile(workspacePath, \"utf8\");\n let value: unknown;\n try {\n value = load(source);\n } catch {\n throw new Error(`Malformed pnpm workspace declaration: ${workspacePath}`);\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\"Invalid pnpm workspace declaration; expected a mapping with packages.\");\n }\n const packages = (value as Record<string, unknown>).packages;\n if (!Array.isArray(packages) || packages.some((pattern) => typeof pattern !== \"string\")) {\n throw new Error(\"Invalid pnpm workspace declaration; expected packages to be an array.\");\n }\n return packages as string[];\n}\n\nasync function findProjectRoot(start: string): Promise<string> {\n const resolved = path.resolve(start);\n const startStat = await fs.stat(resolved).catch(() => null);\n if (!startStat?.isDirectory()) throw new Error(`Working directory does not exist: ${resolved}`);\n\n let directory = resolved;\n let nearestManifestDirectory: string | null = null;\n\n while (true) {\n const manifestPath = path.join(directory, \"package.json\");\n const hasManifest = await isFile(manifestPath);\n if (hasManifest) {\n const manifest = await readManifest(manifestPath);\n nearestManifestDirectory ??= directory;\n if (packageWorkspacePatterns(manifest) !== null) return directory;\n }\n\n if (await isFile(path.join(directory, \"pnpm-workspace.yaml\"))) {\n if (!hasManifest) throw new Error(`Workspace root is missing package.json: ${directory}`);\n await pnpmWorkspacePatterns(directory);\n return directory;\n }\n\n const parent = path.dirname(directory);\n if (parent === directory) break;\n directory = parent;\n }\n\n if (nearestManifestDirectory) return nearestManifestDirectory;\n throw new Error(`No package.json found from ${resolved}.`);\n}\n\nfunction parsePolicy(manifest: Record<string, unknown>): UpdatePolicy {\n const empty = { ignore: [], tags: {} };\n if (!(\"askr\" in manifest)) return empty;\n if (!manifest.askr || typeof manifest.askr !== \"object\" || Array.isArray(manifest.askr)) {\n throw new Error(\"Invalid askr update configuration in the workspace root.\");\n }\n const update = (manifest.askr as Record<string, unknown>).update;\n if (update === undefined) return empty;\n if (!update || typeof update !== \"object\" || Array.isArray(update)) {\n throw new Error(\"Invalid askr.update configuration in the workspace root.\");\n }\n\n const config = update as Record<string, unknown>;\n const ignore = config.ignore ?? [];\n const tags = config.tags ?? {};\n if (!Array.isArray(ignore) || ignore.some((entry) => typeof entry !== \"string\")) {\n throw new Error(\"Invalid askr.update.ignore configuration; expected an array of patterns.\");\n }\n if (\n !tags ||\n typeof tags !== \"object\" ||\n Array.isArray(tags) ||\n Object.entries(tags).some(([name, tag]) => !name || typeof tag !== \"string\" || !tag)\n ) {\n throw new Error(\"Invalid askr.update.tags configuration; expected package-to-tag strings.\");\n }\n\n return { ignore: ignore as string[], tags: tags as Record<string, string> };\n}\n\nfunction relativeManifestPath(root: string, manifestPath: string): string {\n return path.relative(root, manifestPath).split(path.sep).join(\"/\") || \"package.json\";\n}\n\nfunction workspaceName(manifest: Record<string, unknown>, fallback: string): string {\n return typeof manifest.name === \"string\" && manifest.name.trim() ? manifest.name : fallback;\n}\n\nconst WORKSPACE_GLOB_OPTIONS = {\n dot: true,\n nocase: process.platform === \"win32\",\n windowsPathsNoEscape: true,\n} as const;\n\nfunction normalizeWorkspacePattern(pattern: string): { negative: boolean; value: string } {\n const leadingBangs = pattern.match(/^!+/)?.[0].length ?? 0;\n const negative = leadingBangs % 2 === 1;\n let value = pattern.slice(leadingBangs);\n value = value.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (value.endsWith(\"/package.json\")) value = value.slice(0, -\"/package.json\".length);\n if (value === \"..\" || value.startsWith(\"../\")) {\n throw new Error(`Workspace patterns outside the project root are unsupported: ${pattern}`);\n }\n return { negative, value: value || \".\" };\n}\n\nfunction matchesWorkspace(relativeDirectory: string, patterns: string[]): boolean {\n let included = false;\n for (const pattern of patterns) {\n const normalized = normalizeWorkspacePattern(pattern);\n if (minimatch(relativeDirectory, normalized.value, WORKSPACE_GLOB_OPTIONS)) {\n included = !normalized.negative;\n }\n }\n return included;\n}\n\nfunction mayContainWorkspace(relativeDirectory: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n const normalized = normalizeWorkspacePattern(pattern);\n return (\n !normalized.negative &&\n minimatch(relativeDirectory, normalized.value, {\n ...WORKSPACE_GLOB_OPTIONS,\n partial: true,\n })\n );\n });\n}\n\nasync function mapDeclaredWorkspaces(\n root: string,\n patterns: string[],\n): Promise<Map<string, string>> {\n const directories: string[] = [];\n if (matchesWorkspace(\".\", patterns)) directories.push(root);\n\n const visit = async (directory: string, relativeDirectory: string): Promise<void> => {\n const entries = await fs.readdir(directory, { withFileTypes: true });\n entries.sort((left, right) => left.name.localeCompare(right.name));\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const childRelative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;\n if (!mayContainWorkspace(childRelative, patterns)) continue;\n const child = path.join(directory, entry.name);\n const isSymbolicDirectory =\n entry.isSymbolicLink() && (await fs.stat(child).catch(() => null))?.isDirectory();\n if (!entry.isDirectory() && !isSymbolicDirectory) continue;\n if (\n matchesWorkspace(childRelative, patterns) &&\n (await isFile(path.join(child, \"package.json\")))\n ) {\n directories.push(child);\n }\n if (!entry.isSymbolicLink()) await visit(child, childRelative);\n }\n };\n\n await visit(root, \"\");\n const mapped = new Map<string, string>();\n for (const directory of directories.sort((left, right) => left.localeCompare(right))) {\n const manifest = await readManifest(path.join(directory, \"package.json\"));\n const fallback = path.basename(directory);\n const name = workspaceName(manifest, fallback);\n if (mapped.has(name)) {\n throw new Error(`Multiple workspaces with the same name '${name}'.`);\n }\n mapped.set(name, directory);\n }\n return mapped;\n}\n\nasync function discoverWorkspaces(root: string): Promise<{\n policy: UpdatePolicy;\n rootManifest: Record<string, unknown>;\n workspaces: WorkspaceManifest[];\n}> {\n const rootManifestPath = path.join(root, \"package.json\");\n const rootManifest = await readManifest(rootManifestPath);\n const policy = parsePolicy(rootManifest);\n const packagePatterns = packageWorkspacePatterns(rootManifest) ?? [];\n const pnpmPatterns = (await pnpmWorkspacePatterns(root)) ?? [];\n const patterns = [...packagePatterns, ...pnpmPatterns];\n const mapped = patterns.length > 0 ? await mapDeclaredWorkspaces(root, patterns) : new Map();\n\n const rootName = workspaceName(rootManifest, \"(root)\");\n if (mapped.has(rootName)) {\n throw new Error(`Duplicate workspace name '${rootName}' includes the workspace root.`);\n }\n\n const workspaces: WorkspaceManifest[] = [\n {\n name: rootName,\n directory: root,\n manifestPath: rootManifestPath,\n relativeManifestPath: \"package.json\",\n manifest: rootManifest,\n isRoot: true,\n },\n ];\n\n for (const [mappedName, directory] of mapped) {\n const manifestPath = path.join(directory, \"package.json\");\n const manifest = await readManifest(manifestPath);\n workspaces.push({\n name: workspaceName(manifest, mappedName),\n directory,\n manifestPath,\n relativeManifestPath: relativeManifestPath(root, manifestPath),\n manifest,\n isRoot: false,\n });\n }\n\n workspaces.sort((left, right) => {\n if (left.isRoot !== right.isRoot) return left.isRoot ? -1 : 1;\n return (\n left.name.localeCompare(right.name) || left.manifestPath.localeCompare(right.manifestPath)\n );\n });\n return { policy, rootManifest, workspaces };\n}\n\nfunction matchesAny(value: string, patterns: string[]): boolean {\n return patterns.some((pattern) => minimatch(value, pattern, { dot: true }));\n}\n\nfunction isRegistryPackageName(packageName: string): boolean {\n if (\n !packageName ||\n packageName.length > 214 ||\n /^[._-]/.test(packageName) ||\n /[\\s%\\\\:]/.test(packageName)\n ) {\n return false;\n }\n if (!packageName.startsWith(\"@\")) return !packageName.includes(\"/\");\n const parts = packageName.slice(1).split(\"/\");\n return parts.length === 2 && parts.every((part) => part.length > 0 && !/^[._-]/.test(part));\n}\n\nfunction classifySpecification(\n packageName: string,\n specification: string,\n directory: string,\n localNames: Set<string>,\n): Pick<DependencyOccurrence, \"kind\" | \"registryManaged\" | \"reason\"> {\n if (localNames.has(packageName)) {\n return {\n kind: \"local\",\n registryManaged: false,\n reason: \"dependency resolves to a discovered workspace\",\n };\n }\n if (/^workspace:/i.test(specification)) {\n return {\n kind: \"local\",\n registryManaged: false,\n reason: \"workspace protocol is not registry-managed\",\n };\n }\n if (/^link:/i.test(specification)) {\n return {\n kind: \"local\",\n registryManaged: false,\n reason: \"link protocol is not registry-managed\",\n };\n }\n if (!isRegistryPackageName(packageName)) {\n return {\n kind: \"manual\",\n registryManaged: false,\n reason: \"invalid registry package name\",\n };\n }\n\n const parsed = parseDependencySpecification(specification);\n\n if ([\"file\", \"git\", \"remote\"].includes(parsed.type)) {\n return {\n kind: \"local\",\n registryManaged: false,\n reason: `${parsed.type} specification is not registry-managed`,\n };\n }\n if (parsed.type === \"alias\") {\n return { kind: \"manual\", registryManaged: false, reason: \"npm aliases require manual review\" };\n }\n if (parsed.type === \"tag\") {\n return { kind: \"current\", registryManaged: true, reason: \"tracking tag is not rewritten\" };\n }\n if (parsed.type !== \"range\" && parsed.type !== \"version\") {\n return {\n kind: \"manual\",\n registryManaged: false,\n reason: \"unsupported dependency specification\",\n };\n }\n\n const analysis = analyzeRange(specification);\n if (analysis.tracking) {\n return { kind: \"current\", registryManaged: true, reason: analysis.reason };\n }\n if (!analysis.shape) {\n return { kind: \"manual\", registryManaged: false, reason: analysis.reason };\n }\n return { kind: \"fetch\", registryManaged: true, reason: \"\" };\n}\n\nfunction collectOccurrences(\n root: string,\n workspaces: WorkspaceManifest[],\n localNames: Set<string>,\n policy: UpdatePolicy,\n packagePatterns: string[],\n): DependencyOccurrence[] {\n const occurrences: DependencyOccurrence[] = [];\n for (const workspace of workspaces) {\n for (const section of DEPENDENCY_SECTIONS) {\n const dependencies = workspace.manifest[section];\n if (dependencies === undefined) continue;\n if (!dependencies || typeof dependencies !== \"object\" || Array.isArray(dependencies)) {\n throw new Error(\n `Invalid ${section} in ${workspace.relativeManifestPath}; expected an object.`,\n );\n }\n\n for (const [packageName, specification] of Object.entries(dependencies)) {\n if (typeof specification !== \"string\") {\n throw new Error(\n `Invalid ${section}.${packageName} in ${workspace.relativeManifestPath}.`,\n );\n }\n if (packagePatterns.length > 0 && !matchesAny(packageName, packagePatterns)) continue;\n if (packagePatterns.length === 0 && matchesAny(packageName, policy.ignore)) continue;\n occurrences.push({\n package: packageName,\n workspace: workspace.name,\n manifestPath: workspace.manifestPath,\n relativeManifestPath: relativeManifestPath(root, workspace.manifestPath),\n section,\n currentSpecification: specification,\n ...classifySpecification(packageName, specification, workspace.directory, localNames),\n });\n }\n }\n }\n\n const sectionOrder = new Map(DEPENDENCY_SECTIONS.map((section, index) => [section, index]));\n occurrences.sort(\n (left, right) =>\n left.package.localeCompare(right.package) ||\n left.workspace.localeCompare(right.workspace) ||\n left.relativeManifestPath.localeCompare(right.relativeManifestPath) ||\n sectionOrder.get(left.section)! - sectionOrder.get(right.section)!,\n );\n return occurrences;\n}\n\nexport async function discoverProject(options: DiscoveryOptions): Promise<DiscoveredProject> {\n const root = await findProjectRoot(options.cwd);\n const { policy, workspaces } = await discoverWorkspaces(root);\n const selectedWorkspaces =\n options.workspacePatterns.length === 0\n ? workspaces\n : workspaces.filter((workspace) => matchesAny(workspace.name, options.workspacePatterns));\n if (selectedWorkspaces.length === 0) {\n throw new Error(\"No discovered workspace matches the requested --workspace filters.\");\n }\n\n const localNames = new Set(workspaces.map((workspace) => workspace.name));\n return {\n root,\n workspaces,\n selectedWorkspaces,\n policy,\n occurrences: collectOccurrences(\n root,\n selectedWorkspaces,\n localNames,\n policy,\n options.packagePatterns,\n ),\n contextOccurrences: collectOccurrences(\n root,\n selectedWorkspaces,\n localNames,\n { ignore: [], tags: policy.tags },\n [],\n ),\n };\n}\n"],"mappings":"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"}