designmaker-cli 0.1.0

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 (154) hide show
  1. package/dist/commands/doctor.d.ts +1 -0
  2. package/dist/commands/doctor.js +26 -0
  3. package/dist/commands/doctor.js.map +1 -0
  4. package/dist/commands/import.d.ts +1 -0
  5. package/dist/commands/import.js +45 -0
  6. package/dist/commands/import.js.map +1 -0
  7. package/dist/commands/rebuild.d.ts +1 -0
  8. package/dist/commands/rebuild.js +32 -0
  9. package/dist/commands/rebuild.js.map +1 -0
  10. package/dist/commands/start.d.ts +1 -0
  11. package/dist/commands/start.js +103 -0
  12. package/dist/commands/start.js.map +1 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +65 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/lib/ai/build-annotation-prompt.d.ts +6 -0
  17. package/dist/lib/ai/build-annotation-prompt.js +40 -0
  18. package/dist/lib/ai/build-annotation-prompt.js.map +1 -0
  19. package/dist/lib/ai/providers/index.d.ts +10 -0
  20. package/dist/lib/ai/providers/index.js +27 -0
  21. package/dist/lib/ai/providers/index.js.map +1 -0
  22. package/dist/lib/ai/providers/openai.d.ts +9 -0
  23. package/dist/lib/ai/providers/openai.js +77 -0
  24. package/dist/lib/ai/providers/openai.js.map +1 -0
  25. package/dist/lib/ai/providers/response-schema.d.ts +159 -0
  26. package/dist/lib/ai/providers/response-schema.js +21 -0
  27. package/dist/lib/ai/providers/response-schema.js.map +1 -0
  28. package/dist/lib/annotations/annotation-generator.d.ts +9 -0
  29. package/dist/lib/annotations/annotation-generator.js +90 -0
  30. package/dist/lib/annotations/annotation-generator.js.map +1 -0
  31. package/dist/lib/annotations/run-annotation-generation.d.ts +13 -0
  32. package/dist/lib/annotations/run-annotation-generation.js +52 -0
  33. package/dist/lib/annotations/run-annotation-generation.js.map +1 -0
  34. package/dist/lib/bundle/annotated-bundle.d.ts +15 -0
  35. package/dist/lib/bundle/annotated-bundle.js +63 -0
  36. package/dist/lib/bundle/annotated-bundle.js.map +1 -0
  37. package/dist/lib/bundle/shell-dist.d.ts +1 -0
  38. package/dist/lib/bundle/shell-dist.js +29 -0
  39. package/dist/lib/bundle/shell-dist.js.map +1 -0
  40. package/dist/lib/config.d.ts +13 -0
  41. package/dist/lib/config.js +84 -0
  42. package/dist/lib/config.js.map +1 -0
  43. package/dist/lib/doctor/doctor-checks.d.ts +12 -0
  44. package/dist/lib/doctor/doctor-checks.js +98 -0
  45. package/dist/lib/doctor/doctor-checks.js.map +1 -0
  46. package/dist/lib/env.d.ts +1 -0
  47. package/dist/lib/env.js +5 -0
  48. package/dist/lib/env.js.map +1 -0
  49. package/dist/lib/logger.d.ts +6 -0
  50. package/dist/lib/logger.js +15 -0
  51. package/dist/lib/logger.js.map +1 -0
  52. package/dist/lib/project/detect-artifacts.d.ts +1 -0
  53. package/dist/lib/project/detect-artifacts.js +10 -0
  54. package/dist/lib/project/detect-artifacts.js.map +1 -0
  55. package/dist/lib/project/detect-framework.d.ts +3 -0
  56. package/dist/lib/project/detect-framework.js +14 -0
  57. package/dist/lib/project/detect-framework.js.map +1 -0
  58. package/dist/lib/project/detect-package-manager.d.ts +3 -0
  59. package/dist/lib/project/detect-package-manager.js +33 -0
  60. package/dist/lib/project/detect-package-manager.js.map +1 -0
  61. package/dist/lib/project/detect-scripts.d.ts +6 -0
  62. package/dist/lib/project/detect-scripts.js +8 -0
  63. package/dist/lib/project/detect-scripts.js.map +1 -0
  64. package/dist/lib/project/package-json.d.ts +23 -0
  65. package/dist/lib/project/package-json.js +20 -0
  66. package/dist/lib/project/package-json.js.map +1 -0
  67. package/dist/lib/project/project-scan.d.ts +2 -0
  68. package/dist/lib/project/project-scan.js +35 -0
  69. package/dist/lib/project/project-scan.js.map +1 -0
  70. package/dist/lib/prompt/is-tty.d.ts +1 -0
  71. package/dist/lib/prompt/is-tty.js +5 -0
  72. package/dist/lib/prompt/is-tty.js.map +1 -0
  73. package/dist/lib/prototype/browser.d.ts +2 -0
  74. package/dist/lib/prototype/browser.js +5 -0
  75. package/dist/lib/prototype/browser.js.map +1 -0
  76. package/dist/lib/prototype/capture-all-pages.d.ts +13 -0
  77. package/dist/lib/prototype/capture-all-pages.js +22 -0
  78. package/dist/lib/prototype/capture-all-pages.js.map +1 -0
  79. package/dist/lib/prototype/dom-summary.d.ts +3 -0
  80. package/dist/lib/prototype/dom-summary.js +56 -0
  81. package/dist/lib/prototype/dom-summary.js.map +1 -0
  82. package/dist/lib/prototype/page-capture.d.ts +6 -0
  83. package/dist/lib/prototype/page-capture.js +36 -0
  84. package/dist/lib/prototype/page-capture.js.map +1 -0
  85. package/dist/lib/prototype/page-metadata.d.ts +7 -0
  86. package/dist/lib/prototype/page-metadata.js +9 -0
  87. package/dist/lib/prototype/page-metadata.js.map +1 -0
  88. package/dist/lib/prototype/prototype-session.d.ts +22 -0
  89. package/dist/lib/prototype/prototype-session.js +82 -0
  90. package/dist/lib/prototype/prototype-session.js.map +1 -0
  91. package/dist/lib/prototype/run-package-script.d.ts +2 -0
  92. package/dist/lib/prototype/run-package-script.js +21 -0
  93. package/dist/lib/prototype/run-package-script.js.map +1 -0
  94. package/dist/lib/prototype/start-static-preview.d.ts +5 -0
  95. package/dist/lib/prototype/start-static-preview.js +74 -0
  96. package/dist/lib/prototype/start-static-preview.js.map +1 -0
  97. package/dist/lib/prototype/startup-strategy.d.ts +7 -0
  98. package/dist/lib/prototype/startup-strategy.js +32 -0
  99. package/dist/lib/prototype/startup-strategy.js.map +1 -0
  100. package/dist/lib/prototype/visible-text.d.ts +2 -0
  101. package/dist/lib/prototype/visible-text.js +5 -0
  102. package/dist/lib/prototype/visible-text.js.map +1 -0
  103. package/dist/lib/prototype/wait-for-url.d.ts +1 -0
  104. package/dist/lib/prototype/wait-for-url.js +16 -0
  105. package/dist/lib/prototype/wait-for-url.js.map +1 -0
  106. package/dist/lib/requirements/parse-file.d.ts +1 -0
  107. package/dist/lib/requirements/parse-file.js +7 -0
  108. package/dist/lib/requirements/parse-file.js.map +1 -0
  109. package/dist/lib/requirements/parse-text.d.ts +1 -0
  110. package/dist/lib/requirements/parse-text.js +4 -0
  111. package/dist/lib/requirements/parse-text.js.map +1 -0
  112. package/dist/lib/requirements/requirements-discovery.d.ts +2 -0
  113. package/dist/lib/requirements/requirements-discovery.js +62 -0
  114. package/dist/lib/requirements/requirements-discovery.js.map +1 -0
  115. package/dist/lib/requirements/requirements-ranking.d.ts +1 -0
  116. package/dist/lib/requirements/requirements-ranking.js +41 -0
  117. package/dist/lib/requirements/requirements-ranking.js.map +1 -0
  118. package/dist/lib/routes/confirm-ai-routes.d.ts +10 -0
  119. package/dist/lib/routes/confirm-ai-routes.js +70 -0
  120. package/dist/lib/routes/confirm-ai-routes.js.map +1 -0
  121. package/dist/lib/routes/crawl-internal-links.d.ts +4 -0
  122. package/dist/lib/routes/crawl-internal-links.js +42 -0
  123. package/dist/lib/routes/crawl-internal-links.js.map +1 -0
  124. package/dist/lib/routes/normalize-route-path.d.ts +5 -0
  125. package/dist/lib/routes/normalize-route-path.js +52 -0
  126. package/dist/lib/routes/normalize-route-path.js.map +1 -0
  127. package/dist/lib/routes/resolve-capture-routes.d.ts +18 -0
  128. package/dist/lib/routes/resolve-capture-routes.js +47 -0
  129. package/dist/lib/routes/resolve-capture-routes.js.map +1 -0
  130. package/dist/lib/routes/routes-config.d.ts +21 -0
  131. package/dist/lib/routes/routes-config.js +31 -0
  132. package/dist/lib/routes/routes-config.js.map +1 -0
  133. package/dist/lib/workspace/paths.d.ts +8 -0
  134. package/dist/lib/workspace/paths.js +19 -0
  135. package/dist/lib/workspace/paths.js.map +1 -0
  136. package/dist/lib/workspace/read-json.d.ts +2 -0
  137. package/dist/lib/workspace/read-json.js +26 -0
  138. package/dist/lib/workspace/read-json.js.map +1 -0
  139. package/dist/lib/workspace/schema.d.ts +355 -0
  140. package/dist/lib/workspace/schema.js +71 -0
  141. package/dist/lib/workspace/schema.js.map +1 -0
  142. package/dist/lib/workspace/types.d.ts +81 -0
  143. package/dist/lib/workspace/types.js +2 -0
  144. package/dist/lib/workspace/types.js.map +1 -0
  145. package/dist/lib/workspace/workspace-store.d.ts +27 -0
  146. package/dist/lib/workspace/workspace-store.js +75 -0
  147. package/dist/lib/workspace/workspace-store.js.map +1 -0
  148. package/dist/lib/workspace/write-json.d.ts +1 -0
  149. package/dist/lib/workspace/write-json.js +10 -0
  150. package/dist/lib/workspace/write-json.js.map +1 -0
  151. package/package.json +34 -0
  152. package/templates/vercel.json +5 -0
  153. package/vendor/annotation-shell/annotation-shell.css +1 -0
  154. package/vendor/annotation-shell/annotation-shell.js +379 -0
@@ -0,0 +1,82 @@
1
+ import { join } from 'node:path';
2
+ import { logger } from '../logger.js';
3
+ import { scanProject } from '../project/project-scan.js';
4
+ import { launchBrowser } from './browser.js';
5
+ import { captureAllPages } from './capture-all-pages.js';
6
+ import { runPackageScript } from './run-package-script.js';
7
+ import { startStaticPreview } from './start-static-preview.js';
8
+ import { resolveStartupPlan } from './startup-strategy.js';
9
+ import { waitForUrl } from './wait-for-url.js';
10
+ import { resolveCaptureRoutes } from '../routes/resolve-capture-routes.js';
11
+ import { resolveAiRoutes } from '../routes/confirm-ai-routes.js';
12
+ export async function capturePrototype(projectRoot, initialScan, paths, options) {
13
+ let scan = initialScan;
14
+ let plan = resolveStartupPlan(scan);
15
+ if (plan.kind === 'build') {
16
+ logger.info('未发现静态产物,开始执行项目 build 脚本...');
17
+ await runPackageScript(projectRoot, scan.package_manager, 'build');
18
+ scan = await scanProject(projectRoot);
19
+ plan = resolveStartupPlan(scan);
20
+ }
21
+ if (plan.kind !== 'static' || !plan.artifactDir) {
22
+ logger.warn('当前仅支持静态产物采集;dev/preview 脚本采集将在后续任务补齐。');
23
+ return emptyCaptureResult(scan);
24
+ }
25
+ const artifactRoot = join(projectRoot, plan.artifactDir);
26
+ const server = await startStaticPreview(artifactRoot);
27
+ let browser = null;
28
+ try {
29
+ browser = await launchBrowser();
30
+ await waitForUrl(server.url);
31
+ const resolvedRoutes = await resolveCaptureRoutes({
32
+ cwd: options.cwd,
33
+ workspace: options.workspace,
34
+ pages: options.pages,
35
+ maxPages: options.maxPages,
36
+ noCrawl: options.noCrawl,
37
+ yes: options.yes,
38
+ browser,
39
+ baseUrl: server.url,
40
+ });
41
+ const aiRoutes = await resolveAiRoutes({
42
+ routes: resolvedRoutes.routes,
43
+ routesConfig: resolvedRoutes.routesConfig,
44
+ aiPages: options.aiPages,
45
+ yes: options.yes,
46
+ prompt: options.prompt,
47
+ });
48
+ const snapshots = await captureAllPages(browser, server.url, resolvedRoutes.routes, paths.pageSnapshotsDir);
49
+ const firstSnapshot = snapshots[0]?.snapshot ?? null;
50
+ const entryUrl = firstSnapshot?.url ?? null;
51
+ return {
52
+ scan: {
53
+ ...scan,
54
+ resolved_entry_url: entryUrl,
55
+ },
56
+ entryUrl,
57
+ routes: resolvedRoutes.routes,
58
+ aiRoutes,
59
+ snapshots,
60
+ snapshot: firstSnapshot,
61
+ snapshotFileName: snapshots[0]?.fileName ?? null,
62
+ };
63
+ }
64
+ finally {
65
+ if (browser) {
66
+ await browser.close();
67
+ }
68
+ await server.close();
69
+ }
70
+ }
71
+ function emptyCaptureResult(scan) {
72
+ return {
73
+ scan,
74
+ entryUrl: null,
75
+ routes: ['/'],
76
+ aiRoutes: ['/'],
77
+ snapshots: [],
78
+ snapshot: null,
79
+ snapshotFileName: null,
80
+ };
81
+ }
82
+ //# sourceMappingURL=prototype-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prototype-session.js","sourceRoot":"","sources":["../../../src/lib/prototype/prototype-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ProjectScanResult } from '../workspace/types.js';
2
+ export declare function runPackageScript(projectRoot: string, packageManager: ProjectScanResult['package_manager'], scriptName: string): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import { spawn } from 'node:child_process';
2
+ export async function runPackageScript(projectRoot, packageManager, scriptName) {
3
+ const command = packageManager === 'yarn' ? 'yarn' : packageManager === 'pnpm' ? 'pnpm' : 'npm';
4
+ const args = command === 'yarn' ? [scriptName] : ['run', scriptName];
5
+ await new Promise((resolve, reject) => {
6
+ const child = spawn(command, args, {
7
+ cwd: projectRoot,
8
+ stdio: 'inherit',
9
+ shell: false,
10
+ });
11
+ child.on('error', reject);
12
+ child.on('exit', (code) => {
13
+ if (code === 0) {
14
+ resolve();
15
+ return;
16
+ }
17
+ reject(new Error(`${command} ${args.join(' ')} 执行失败,退出码:${code ?? 'unknown'}`));
18
+ });
19
+ });
20
+ }
21
+ //# sourceMappingURL=run-package-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-package-script.js","sourceRoot":"","sources":["../../../src/lib/prototype/run-package-script.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,cAAoD,EACpD,UAAkB;IAElB,MAAM,OAAO,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IAChG,MAAM,IAAI,GAAG,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAErE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC;QAClF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface StaticPreviewServer {
2
+ url: string;
3
+ close: () => Promise<void>;
4
+ }
5
+ export declare function startStaticPreview(rootDir: string): Promise<StaticPreviewServer>;
@@ -0,0 +1,74 @@
1
+ import { createReadStream, existsSync, statSync } from 'node:fs';
2
+ import { createServer } from 'node:http';
3
+ import { extname, join, normalize } from 'node:path';
4
+ export async function startStaticPreview(rootDir) {
5
+ const server = createServer((request, response) => {
6
+ const requestUrl = new URL(request.url ?? '/', 'http://127.0.0.1');
7
+ const safePath = normalize(decodeURIComponent(requestUrl.pathname)).replace(/^(\.\.[/\\])+/, '');
8
+ const requestedPath = join(rootDir, safePath);
9
+ const filePath = resolveFilePath(rootDir, requestedPath, requestUrl.pathname);
10
+ if (!filePath) {
11
+ response.statusCode = 404;
12
+ response.end('Not found');
13
+ return;
14
+ }
15
+ response.setHeader('Content-Type', getContentType(filePath));
16
+ createReadStream(filePath).pipe(response);
17
+ });
18
+ const url = await listen(server);
19
+ return {
20
+ url,
21
+ close: () => new Promise((resolve, reject) => {
22
+ server.close((error) => (error ? reject(error) : resolve()));
23
+ }),
24
+ };
25
+ }
26
+ function resolveFilePath(rootDir, requestedPath, pathname) {
27
+ if (existsSync(requestedPath) && statSync(requestedPath).isFile()) {
28
+ return requestedPath;
29
+ }
30
+ if (pathname.endsWith('/')) {
31
+ const indexPath = join(requestedPath, 'index.html');
32
+ if (existsSync(indexPath) && statSync(indexPath).isFile())
33
+ return indexPath;
34
+ }
35
+ const spaFallback = join(rootDir, 'index.html');
36
+ if (existsSync(spaFallback) && statSync(spaFallback).isFile())
37
+ return spaFallback;
38
+ return null;
39
+ }
40
+ function listen(server) {
41
+ return new Promise((resolve, reject) => {
42
+ server.on('error', reject);
43
+ server.listen(0, '127.0.0.1', () => {
44
+ const address = server.address();
45
+ if (!address || typeof address === 'string') {
46
+ reject(new Error('无法获取静态预览端口'));
47
+ return;
48
+ }
49
+ resolve(`http://127.0.0.1:${address.port}`);
50
+ });
51
+ });
52
+ }
53
+ function getContentType(path) {
54
+ switch (extname(path)) {
55
+ case '.html':
56
+ return 'text/html; charset=utf-8';
57
+ case '.js':
58
+ return 'text/javascript; charset=utf-8';
59
+ case '.css':
60
+ return 'text/css; charset=utf-8';
61
+ case '.json':
62
+ return 'application/json; charset=utf-8';
63
+ case '.png':
64
+ return 'image/png';
65
+ case '.jpg':
66
+ case '.jpeg':
67
+ return 'image/jpeg';
68
+ case '.svg':
69
+ return 'image/svg+xml';
70
+ default:
71
+ return 'application/octet-stream';
72
+ }
73
+ }
74
+ //# sourceMappingURL=start-static-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-static-preview.js","sourceRoot":"","sources":["../../../src/lib/prototype/start-static-preview.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ProjectScanResult } from '../workspace/types.js';
2
+ export interface StartupPlan {
3
+ kind: 'static' | 'build' | 'script' | 'none';
4
+ artifactDir: string | null;
5
+ scriptName: string | null;
6
+ }
7
+ export declare function resolveStartupPlan(scan: ProjectScanResult): StartupPlan;
@@ -0,0 +1,32 @@
1
+ export function resolveStartupPlan(scan) {
2
+ const staticDir = scan.artifact_dirs[0];
3
+ if (staticDir) {
4
+ return {
5
+ kind: 'static',
6
+ artifactDir: staticDir,
7
+ scriptName: null,
8
+ };
9
+ }
10
+ if (scan.scripts.build) {
11
+ return {
12
+ kind: 'build',
13
+ artifactDir: null,
14
+ scriptName: 'build',
15
+ };
16
+ }
17
+ for (const scriptName of ['preview', 'dev', 'start']) {
18
+ if (scan.scripts[scriptName]) {
19
+ return {
20
+ kind: 'script',
21
+ artifactDir: null,
22
+ scriptName,
23
+ };
24
+ }
25
+ }
26
+ return {
27
+ kind: 'none',
28
+ artifactDir: null,
29
+ scriptName: null,
30
+ };
31
+ }
32
+ //# sourceMappingURL=startup-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-strategy.js","sourceRoot":"","sources":["../../../src/lib/prototype/startup-strategy.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,SAAS;YACtB,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,OAAO;YACL,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,IAAI;YACjB,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,UAAU,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,IAAI;gBACjB,UAAU;aACX,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Page } from 'playwright';
2
+ export declare function extractVisibleText(page: Page): Promise<string>;
@@ -0,0 +1,5 @@
1
+ export async function extractVisibleText(page) {
2
+ const result = await page.evaluate(`document.body.innerText.trim()`);
3
+ return String(result);
4
+ }
5
+ //# sourceMappingURL=visible-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visible-text.js","sourceRoot":"","sources":["../../../src/lib/prototype/visible-text.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAU;IACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function waitForUrl(url: string, timeoutMs?: number): Promise<void>;
@@ -0,0 +1,16 @@
1
+ export async function waitForUrl(url, timeoutMs = 10000) {
2
+ const startedAt = Date.now();
3
+ while (Date.now() - startedAt < timeoutMs) {
4
+ try {
5
+ const response = await fetch(url);
6
+ if (response.ok)
7
+ return;
8
+ }
9
+ catch {
10
+ // retry until timeout
11
+ }
12
+ await new Promise((resolve) => setTimeout(resolve, 250));
13
+ }
14
+ throw new Error(`等待 URL 可访问超时:${url}`);
15
+ }
16
+ //# sourceMappingURL=wait-for-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-url.js","sourceRoot":"","sources":["../../../src/lib/prototype/wait-for-url.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,SAAS,GAAG,KAAK;IAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,QAAQ,CAAC,EAAE;gBAAE,OAAO;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function parseMarkdownFile(path: string): Promise<string>;
@@ -0,0 +1,7 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { normalizeMarkdownText } from './parse-text.js';
3
+ export async function parseMarkdownFile(path) {
4
+ const raw = await readFile(path, 'utf8');
5
+ return normalizeMarkdownText(raw);
6
+ }
7
+ //# sourceMappingURL=parse-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-file.js","sourceRoot":"","sources":["../../../src/lib/requirements/parse-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAClD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,qBAAqB,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function normalizeMarkdownText(text: string): string;
@@ -0,0 +1,4 @@
1
+ export function normalizeMarkdownText(text) {
2
+ return text.replace(/\r\n/g, '\n').trim();
3
+ }
4
+ //# sourceMappingURL=parse-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-text.js","sourceRoot":"","sources":["../../../src/lib/requirements/parse-text.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { RequirementsContext } from '../workspace/types.js';
2
+ export declare function discoverRequirements(projectRoot: string): Promise<RequirementsContext>;
@@ -0,0 +1,62 @@
1
+ import { existsSync, readdirSync, statSync } from 'node:fs';
2
+ import { join, relative } from 'node:path';
3
+ import { parseMarkdownFile } from './parse-file.js';
4
+ import { rankRequirementFiles } from './requirements-ranking.js';
5
+ const CANDIDATE_DIRS = ['docs', 'prd', 'requirements'];
6
+ const IGNORED_DIRS = new Set(['.designmaker', 'node_modules', 'dist', 'build', 'out', '.git']);
7
+ const MAX_SELECTED_FILES = 5;
8
+ export async function discoverRequirements(projectRoot) {
9
+ const candidateFiles = discoverCandidateFiles(projectRoot);
10
+ const rankedFiles = rankRequirementFiles(candidateFiles);
11
+ const selectedFiles = rankedFiles.slice(0, MAX_SELECTED_FILES);
12
+ const combinedText = await combineMarkdownFiles(projectRoot, selectedFiles);
13
+ return {
14
+ candidate_files: rankedFiles,
15
+ selected_files: selectedFiles,
16
+ combined_text: combinedText,
17
+ updated_at: new Date().toISOString(),
18
+ };
19
+ }
20
+ function discoverCandidateFiles(projectRoot) {
21
+ const files = new Set();
22
+ for (const dir of CANDIDATE_DIRS) {
23
+ const absoluteDir = join(projectRoot, dir);
24
+ if (existsSync(absoluteDir) && statSync(absoluteDir).isDirectory()) {
25
+ for (const file of walkMarkdownFiles(projectRoot, absoluteDir)) {
26
+ files.add(file);
27
+ }
28
+ }
29
+ }
30
+ for (const item of readdirSync(projectRoot, { withFileTypes: true })) {
31
+ if (item.isFile() && item.name.toLowerCase().endsWith('.md')) {
32
+ files.add(item.name);
33
+ }
34
+ }
35
+ return [...files];
36
+ }
37
+ function walkMarkdownFiles(projectRoot, dir) {
38
+ const files = [];
39
+ for (const item of readdirSync(dir, { withFileTypes: true })) {
40
+ if (item.isDirectory()) {
41
+ if (IGNORED_DIRS.has(item.name))
42
+ continue;
43
+ files.push(...walkMarkdownFiles(projectRoot, join(dir, item.name)));
44
+ continue;
45
+ }
46
+ if (item.isFile() && item.name.toLowerCase().endsWith('.md')) {
47
+ files.push(relative(projectRoot, join(dir, item.name)));
48
+ }
49
+ }
50
+ return files;
51
+ }
52
+ async function combineMarkdownFiles(projectRoot, files) {
53
+ const chunks = [];
54
+ for (const file of files) {
55
+ const text = await parseMarkdownFile(join(projectRoot, file));
56
+ if (!text)
57
+ continue;
58
+ chunks.push(`<!-- source: ${file} -->\n${text}`);
59
+ }
60
+ return chunks.join('\n\n---\n\n');
61
+ }
62
+ //# sourceMappingURL=requirements-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requirements-discovery.js","sourceRoot":"","sources":["../../../src/lib/requirements/requirements-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function rankRequirementFiles(files: string[]): string[];
@@ -0,0 +1,41 @@
1
+ import { basename, dirname } from 'node:path';
2
+ const KEYWORD_WEIGHTS = [
3
+ { keyword: 'prd', weight: 100 },
4
+ { keyword: 'requirement', weight: 90 },
5
+ { keyword: 'requirements', weight: 90 },
6
+ { keyword: '需求', weight: 90 },
7
+ { keyword: '要件', weight: 90 },
8
+ { keyword: 'design', weight: 70 },
9
+ { keyword: '设计', weight: 70 },
10
+ { keyword: '設計', weight: 70 },
11
+ ];
12
+ const DIRECTORY_WEIGHTS = [
13
+ { segment: 'docs', weight: 30 },
14
+ { segment: 'prd', weight: 40 },
15
+ { segment: 'requirements', weight: 40 },
16
+ ];
17
+ export function rankRequirementFiles(files) {
18
+ return [...files].sort((a, b) => {
19
+ const scoreDelta = scoreFile(b) - scoreFile(a);
20
+ if (scoreDelta !== 0)
21
+ return scoreDelta;
22
+ return a.localeCompare(b);
23
+ });
24
+ }
25
+ function scoreFile(path) {
26
+ const lowerName = basename(path).toLowerCase();
27
+ const lowerDir = dirname(path).toLowerCase();
28
+ let score = 0;
29
+ for (const item of KEYWORD_WEIGHTS) {
30
+ if (lowerName.includes(item.keyword))
31
+ score += item.weight;
32
+ }
33
+ for (const item of DIRECTORY_WEIGHTS) {
34
+ if (lowerDir.split('/').includes(item.segment))
35
+ score += item.weight;
36
+ }
37
+ if (lowerName === 'readme.md')
38
+ score -= 20;
39
+ return score;
40
+ }
41
+ //# sourceMappingURL=requirements-ranking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requirements-ranking.js","sourceRoot":"","sources":["../../../src/lib/requirements/requirements-ranking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,eAAe,GAAG;IACtB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE;IAC/B,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE;IACtC,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE;IACvC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAC7B,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;IACjC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;CAC9B,CAAC;AAEF,MAAM,iBAAiB,GAAG;IACxB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;IAC/B,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;IAC9B,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE;CACxC,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,KAAe;IAClD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QACxC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7C,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;IAC7D,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;IACvE,CAAC;IAED,IAAI,SAAS,KAAK,WAAW;QAAE,KAAK,IAAI,EAAE,CAAC;IAE3C,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { LoadedRoutesConfig } from './routes-config.js';
2
+ export interface ResolveAiRoutesOptions {
3
+ routes: string[];
4
+ routesConfig: LoadedRoutesConfig | null;
5
+ aiPages?: string[];
6
+ yes: boolean;
7
+ prompt?: (message: string) => Promise<string>;
8
+ }
9
+ export declare function resolveAiRoutes(options: ResolveAiRoutesOptions): Promise<string[]>;
10
+ export declare function confirmAiRoutes(routes: string[], promptFn?: (message: string) => Promise<string>): Promise<string[]>;
@@ -0,0 +1,70 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { stdin, stdout } from 'node:process';
3
+ import { logger } from '../logger.js';
4
+ import { isInteractiveTty } from '../prompt/is-tty.js';
5
+ import { assertAiRoutesSubset, normalizeRouteList } from './normalize-route-path.js';
6
+ export async function resolveAiRoutes(options) {
7
+ const { routes, routesConfig } = options;
8
+ if (options.aiPages && options.aiPages.length > 0) {
9
+ const aiRoutes = normalizeRouteList(options.aiPages);
10
+ assertAiRoutesSubset(routes, aiRoutes);
11
+ return aiRoutes;
12
+ }
13
+ if (routesConfig?.aiRoutes) {
14
+ assertAiRoutesSubset(routes, routesConfig.aiRoutes);
15
+ return routesConfig.aiRoutes;
16
+ }
17
+ if (isInteractiveTty() && !options.yes) {
18
+ return confirmAiRoutes(routes, options.prompt);
19
+ }
20
+ return ['/'];
21
+ }
22
+ export async function confirmAiRoutes(routes, promptFn) {
23
+ const selected = new Set([findDefaultIndex(routes)]);
24
+ logger.info('');
25
+ logger.info(`发现 ${routes.length} 条路由:`);
26
+ printRouteList(routes, selected);
27
+ const prompt = promptFn ?? defaultPrompt;
28
+ const input = await prompt('请选择要生成 AI 标注的页面(逗号分隔序号,回车=当前勾选): ');
29
+ applySelectionInput(input, routes.length, selected);
30
+ printRouteList(routes, selected);
31
+ const aiRoutes = [...selected]
32
+ .sort((left, right) => left - right)
33
+ .map((index) => routes[index - 1])
34
+ .filter((route) => Boolean(route));
35
+ return aiRoutes.length > 0 ? aiRoutes : ['/'];
36
+ }
37
+ function findDefaultIndex(routes) {
38
+ const rootIndex = routes.findIndex((route) => route === '/');
39
+ return rootIndex >= 0 ? rootIndex + 1 : 1;
40
+ }
41
+ function printRouteList(routes, selected) {
42
+ routes.forEach((route, index) => {
43
+ const marker = selected.has(index + 1) ? 'x' : ' ';
44
+ logger.info(` [${marker}] ${index + 1}. ${route}`);
45
+ });
46
+ }
47
+ function applySelectionInput(input, routeCount, selected) {
48
+ const trimmed = input.trim();
49
+ if (!trimmed) {
50
+ return;
51
+ }
52
+ selected.clear();
53
+ for (const part of trimmed.split(',')) {
54
+ const index = Number.parseInt(part.trim(), 10);
55
+ if (Number.isNaN(index) || index < 1 || index > routeCount) {
56
+ throw new Error(`无效序号:${part.trim()}(有效范围 1-${routeCount})`);
57
+ }
58
+ selected.add(index);
59
+ }
60
+ }
61
+ async function defaultPrompt(message) {
62
+ const rl = createInterface({ input: stdin, output: stdout });
63
+ try {
64
+ return await rl.question(`${message} `);
65
+ }
66
+ finally {
67
+ rl.close();
68
+ }
69
+ }
70
+ //# sourceMappingURL=confirm-ai-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-ai-routes.js","sourceRoot":"","sources":["../../../src/lib/routes/confirm-ai-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Browser } from 'playwright';
2
+ export declare function crawlInternalLinks(browser: Browser, baseUrl: string, options?: {
3
+ maxPages?: number;
4
+ }): Promise<string[]>;
@@ -0,0 +1,42 @@
1
+ import { normalizeRouteList } from './normalize-route-path.js';
2
+ export async function crawlInternalLinks(browser, baseUrl, options = {}) {
3
+ const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
4
+ try {
5
+ await page.goto(`${trimTrailingSlash(baseUrl)}/`, { waitUntil: 'networkidle' });
6
+ const hrefs = await page.$$eval('a[href]', (anchors) => anchors.map((anchor) => anchor.getAttribute('href') ?? ''));
7
+ const origin = new URL(baseUrl).origin;
8
+ const discovered = ['/'];
9
+ for (const href of hrefs) {
10
+ const path = hrefToPath(href, origin);
11
+ if (path) {
12
+ discovered.push(path);
13
+ }
14
+ }
15
+ return normalizeRouteList(discovered, { maxPages: options.maxPages });
16
+ }
17
+ finally {
18
+ await page.close();
19
+ }
20
+ }
21
+ function hrefToPath(href, origin) {
22
+ const trimmed = href.trim();
23
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('mailto:') || trimmed.startsWith('javascript:')) {
24
+ return null;
25
+ }
26
+ try {
27
+ const url = trimmed.startsWith('/')
28
+ ? new URL(trimmed, origin)
29
+ : new URL(trimmed);
30
+ if (url.origin !== origin) {
31
+ return null;
32
+ }
33
+ return url.pathname + url.search;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ function trimTrailingSlash(url) {
40
+ return url.endsWith('/') ? url.slice(0, -1) : url;
41
+ }
42
+ //# sourceMappingURL=crawl-internal-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crawl-internal-links.js","sourceRoot":"","sources":["../../../src/lib/routes/crawl-internal-links.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAgB,EAChB,OAAe,EACf,UAAiC,EAAE;IAEnC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAEhF,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;QAEhF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CACrD,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAC3D,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QACvC,MAAM,UAAU,GAAa,CAAC,GAAG,CAAC,CAAC;QAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtC,IAAI,IAAI,EAAE,CAAC;gBACT,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,OAAO,kBAAkB,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxE,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,MAAc;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9G,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YACjC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC;YAC1B,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAErB,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACpD,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function normalizeRoutePath(input: string): string | null;
2
+ export declare function normalizeRouteList(routes: string[], options?: {
3
+ maxPages?: number;
4
+ }): string[];
5
+ export declare function assertAiRoutesSubset(routes: string[], aiRoutes: string[]): void;