jamdesk 1.1.89 → 1.1.90

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 (42) hide show
  1. package/dist/__tests__/integration/validate.integration.test.js +2 -1
  2. package/dist/__tests__/integration/validate.integration.test.js.map +1 -1
  3. package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts +2 -0
  4. package/dist/__tests__/unit/dev-workspace-symlinks.test.d.ts.map +1 -0
  5. package/dist/__tests__/unit/dev-workspace-symlinks.test.js +112 -0
  6. package/dist/__tests__/unit/dev-workspace-symlinks.test.js.map +1 -0
  7. package/dist/__tests__/unit/docs-config-discovery.test.d.ts +2 -0
  8. package/dist/__tests__/unit/docs-config-discovery.test.d.ts.map +1 -0
  9. package/dist/__tests__/unit/docs-config-discovery.test.js +190 -0
  10. package/dist/__tests__/unit/docs-config-discovery.test.js.map +1 -0
  11. package/dist/__tests__/unit/docs-config.test.js +2 -1
  12. package/dist/__tests__/unit/docs-config.test.js.map +1 -1
  13. package/dist/__tests__/unit/language-filter.test.d.ts +2 -0
  14. package/dist/__tests__/unit/language-filter.test.d.ts.map +1 -0
  15. package/dist/__tests__/unit/language-filter.test.js +166 -0
  16. package/dist/__tests__/unit/language-filter.test.js.map +1 -0
  17. package/dist/__tests__/unit/output.test.d.ts +2 -0
  18. package/dist/__tests__/unit/output.test.d.ts.map +1 -0
  19. package/dist/__tests__/unit/output.test.js +61 -0
  20. package/dist/__tests__/unit/output.test.js.map +1 -0
  21. package/dist/commands/dev.d.ts.map +1 -1
  22. package/dist/commands/dev.js +4 -1
  23. package/dist/commands/dev.js.map +1 -1
  24. package/dist/commands/doctor.d.ts.map +1 -1
  25. package/dist/commands/doctor.js +14 -12
  26. package/dist/commands/doctor.js.map +1 -1
  27. package/dist/commands/validate.d.ts.map +1 -1
  28. package/dist/commands/validate.js +14 -2
  29. package/dist/commands/validate.js.map +1 -1
  30. package/dist/lib/docs-config.d.ts +54 -3
  31. package/dist/lib/docs-config.d.ts.map +1 -1
  32. package/dist/lib/docs-config.js +126 -8
  33. package/dist/lib/docs-config.js.map +1 -1
  34. package/dist/lib/language-filter.d.ts +31 -0
  35. package/dist/lib/language-filter.d.ts.map +1 -0
  36. package/dist/lib/language-filter.js +14 -0
  37. package/dist/lib/language-filter.js.map +1 -0
  38. package/package.json +1 -1
  39. package/vendored/lib/build/error-parser.ts +38 -12
  40. package/vendored/lib/validate-config.ts +135 -8
  41. package/vendored/shared/status-reporter.ts +12 -0
  42. package/vendored/workspace-package-lock.json +9 -9
@@ -60,6 +60,10 @@ export interface ValidationResult {
60
60
  error?: string;
61
61
  errorType?: 'config_error';
62
62
  errorSuggestion?: string;
63
+ /** Populated only on missing-file failures when `repoRoot` was supplied. */
64
+ discovery?: DocsJsonDiscovery;
65
+ /** Prose remediation derived from discovery (e.g., "Did you mean docsPath=apps/docs?"). */
66
+ discoveryHint?: string;
63
67
  }
64
68
 
65
69
  type Schema = Record<string, unknown>;
@@ -297,12 +301,121 @@ export function formatValidationErrors(errors: ErrorObject[] | null | undefined)
297
301
  return messages.join('. ');
298
302
  }
299
303
 
304
+ /** Limits keep worst-case repos (huge monorepos, generated dirs) cheap on failure. */
305
+ const DISCOVER_MAX_DEPTH = 3;
306
+ const DISCOVER_MAX_ENTRIES = 500;
307
+ const DISCOVER_SKIP_DIRS = new Set([
308
+ 'node_modules', '.git', '.next', '.turbo', '.cache',
309
+ 'dist', 'build', 'out', '.vercel', 'coverage',
310
+ ]);
311
+
312
+ export interface DocsJsonDiscovery {
313
+ /** Repo-relative paths (POSIX separators), sorted, to docs.json files. */
314
+ foundAt: string[];
315
+ /** First-level entries at the repo root, sorted. */
316
+ rootEntries: string[];
317
+ /** True if the walk hit DISCOVER_MAX_ENTRIES before finishing. */
318
+ truncated: boolean;
319
+ }
320
+
321
+ /**
322
+ * Walk `repoRoot` looking for any `docs.json`. Used only on the failure path —
323
+ * gives ops a snapshot of what was cloned and lets us suggest the right docsPath.
324
+ *
325
+ * Documented behavior (covered by tests):
326
+ * - Case-sensitive filename match (`docs.json` only, not `Docs.json`). Matches Linux
327
+ * prod semantics — macOS dev might see different fs.existsSync behavior but discovery
328
+ * is consistent across platforms.
329
+ * - Skips directories whose name starts with `.` (so `.config/docs.json` is invisible).
330
+ * - Skips symlinks unconditionally (cycle defense; Windows junctions covered by the
331
+ * entry+depth caps as a backstop).
332
+ * - Output paths use POSIX separators on all platforms.
333
+ * - `rootEntries` is the raw, sorted listing of the repo's top-level entries — it is
334
+ * captured once at depth 0 and is NOT bounded by DISCOVER_MAX_ENTRIES. Persistence
335
+ * layers (Firestore writes, structured logs) slice it to a fixed cap on their side.
336
+ *
337
+ * Limits: DISCOVER_MAX_DEPTH=3, DISCOVER_MAX_ENTRIES=500.
338
+ */
339
+ export async function discoverDocsJson(repoRoot: string): Promise<DocsJsonDiscovery> {
340
+ const foundAt: string[] = [];
341
+ let rootEntries: string[] = [];
342
+ let seen = 0;
343
+ let truncated = false;
344
+
345
+ async function walk(absDir: string, relDir: string, depth: number): Promise<void> {
346
+ if (truncated || depth > DISCOVER_MAX_DEPTH) return;
347
+ let entries: fs.Dirent[];
348
+ try {
349
+ entries = await fs.promises.readdir(absDir, { withFileTypes: true });
350
+ } catch {
351
+ return;
352
+ }
353
+ if (depth === 0) {
354
+ rootEntries = entries.map(e => e.name).sort();
355
+ }
356
+ for (const entry of entries) {
357
+ if (entry.isSymbolicLink()) continue;
358
+ if (entry.isDirectory() && (DISCOVER_SKIP_DIRS.has(entry.name) || entry.name.startsWith('.'))) continue;
359
+ if (++seen > DISCOVER_MAX_ENTRIES) {
360
+ truncated = true;
361
+ return;
362
+ }
363
+ const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
364
+ if (entry.isDirectory()) {
365
+ await walk(path.join(absDir, entry.name), rel, depth + 1);
366
+ } else if (entry.isFile() && entry.name === 'docs.json') {
367
+ foundAt.push(rel);
368
+ }
369
+ }
370
+ }
371
+
372
+ await walk(repoRoot, '', 0);
373
+ foundAt.sort();
374
+ return { foundAt, rootEntries, truncated };
375
+ }
376
+
377
+ /**
378
+ * Build the prose remediation hint from a discovery snapshot. Pure function —
379
+ * separated from validateConfig so it can be unit-tested directly and so the
380
+ * hint phrasings live in one named place.
381
+ */
382
+ export function synthesizeDiscoveryHint(
383
+ foundAt: string[],
384
+ expectedRel: string,
385
+ docsPath?: string,
386
+ ): string {
387
+ const elsewhere = foundAt.filter(p => p !== expectedRel);
388
+ if (elsewhere.length === 1) {
389
+ // path.posix.dirname returns '.' for files at the root (e.g. 'docs.json' → '.').
390
+ const dir = path.posix.dirname(elsewhere[0]);
391
+ if (dir === '.') {
392
+ return docsPath
393
+ ? 'We found docs.json at the repository root. You can clear the docs path setting to use it.'
394
+ : 'We found docs.json at the repository root.';
395
+ }
396
+ return `We found docs.json at '${elsewhere[0]}'. Did you mean to set the docs path to '${dir}'?`;
397
+ }
398
+ if (elsewhere.length > 1) {
399
+ const list = elsewhere.slice(0, 3).map(p => `'${p}'`).join(', ');
400
+ const more = elsewhere.length > 3 ? ` and ${elsewhere.length - 3} more` : '';
401
+ return `We found docs.json at: ${list}${more}. Update the docs path setting to point at one of these.`;
402
+ }
403
+ return 'We could not find a docs.json file anywhere in this commit. '
404
+ + 'Check that you pushed the right branch and that docs.json is committed.';
405
+ }
406
+
300
407
  /**
301
- * Validate docs.json configuration
408
+ * Validate docs.json configuration.
302
409
  * @param configPath - Full path to docs.json
303
- * @param docsPath - Optional monorepo path for better error messages (e.g., "jamdesk")
410
+ * @param docsPath - Optional monorepo path for better error messages (e.g., "jamdesk")
411
+ * @param repoRoot - Optional repo root; when supplied, missing-file errors include
412
+ * a discovery snapshot and a remediation hint.
304
413
  */
305
- export async function validateConfig(configPath: string, docsPath?: string): Promise<ValidationResult> {
414
+ export async function validateConfig(
415
+ configPath: string,
416
+ docsPath?: string,
417
+ repoRoot?: string,
418
+ ): Promise<ValidationResult> {
306
419
  // Check file exists
307
420
  if (!fs.existsSync(configPath)) {
308
421
  // If `mint.json` sits where docs.json should be, the project is mid-migration
@@ -311,13 +424,27 @@ export async function validateConfig(configPath: string, docsPath?: string): Pro
311
424
  if (fs.existsSync(mintPath)) {
312
425
  return mintlifyMigrationError('Found `mint.json` but no `docs.json`.');
313
426
  }
314
- const pathHint = docsPath
427
+
428
+ const baseError = docsPath
315
429
  ? `Missing docs.json at '${docsPath}/docs.json'. Check that your monorepo path is correct.`
316
430
  : 'Missing docs.json configuration file. Your repository must have a docs.json file in the root directory.';
317
- return {
318
- valid: false,
319
- error: pathHint,
320
- };
431
+
432
+ if (!repoRoot) {
433
+ return { valid: false, error: baseError };
434
+ }
435
+
436
+ const discovery = await discoverDocsJson(repoRoot);
437
+
438
+ const normalizedDocsPath = docsPath
439
+ ? path.posix.normalize(docsPath.replace(/\\/g, '/').replace(/^\.\//, '')).replace(/\/$/, '')
440
+ : '';
441
+ const expectedRel = normalizedDocsPath
442
+ ? path.posix.join(normalizedDocsPath, 'docs.json')
443
+ : 'docs.json';
444
+
445
+ const discoveryHint = synthesizeDiscoveryHint(discovery.foundAt, expectedRel, docsPath);
446
+
447
+ return { valid: false, error: baseError, discovery, discoveryHint };
321
448
  }
322
449
 
323
450
  // Read and parse file
@@ -66,8 +66,20 @@ export interface FailureUpdate {
66
66
  failedPhase: string;
67
67
  timing: TimingSummary | null;
68
68
  memory?: MemoryStats;
69
+ /** docs.json discovery snapshot — populated only on missing-file validate failures. */
70
+ discovery?: {
71
+ foundAt: string[];
72
+ rootEntries: string[];
73
+ truncated: boolean;
74
+ };
69
75
  }
70
76
 
77
+ /**
78
+ * Cap applied when persisting `FailureUpdate.discovery.rootEntries` to keep
79
+ * Firestore docs and Cloud Run log payloads bounded on wide repos.
80
+ */
81
+ export const DISCOVERY_ROOT_ENTRIES_PERSIST_CAP = 30;
82
+
71
83
  export interface ErrorLogData {
72
84
  rawOutput: string;
73
85
  stderr: string;
@@ -2913,9 +2913,9 @@
2913
2913
  }
2914
2914
  },
2915
2915
  "node_modules/dompurify": {
2916
- "version": "3.4.2",
2917
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz",
2918
- "integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==",
2916
+ "version": "3.4.3",
2917
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.3.tgz",
2918
+ "integrity": "sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==",
2919
2919
  "license": "(MPL-2.0 OR Apache-2.0)",
2920
2920
  "optionalDependencies": {
2921
2921
  "@types/trusted-types": "^2.0.7"
@@ -2928,9 +2928,9 @@
2928
2928
  "license": "MIT"
2929
2929
  },
2930
2930
  "node_modules/electron-to-chromium": {
2931
- "version": "1.5.353",
2932
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.353.tgz",
2933
- "integrity": "sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==",
2931
+ "version": "1.5.354",
2932
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.354.tgz",
2933
+ "integrity": "sha512-JaBHwWcfIdmSAfWM5l3uwjGd431j8YEMikZ+K/2nXVuBqJKyZ0f+2h4n4JY5AyNiZmnY9qQr2RU3v9DxDmHMNg==",
2934
2934
  "license": "ISC"
2935
2935
  },
2936
2936
  "node_modules/enhanced-resolve": {
@@ -3739,9 +3739,9 @@
3739
3739
  }
3740
3740
  },
3741
3741
  "node_modules/katex": {
3742
- "version": "0.16.45",
3743
- "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.45.tgz",
3744
- "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==",
3742
+ "version": "0.16.46",
3743
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.46.tgz",
3744
+ "integrity": "sha512-WHy4Coo+bGZyH7NwJKHkS04YFsFcarWbAEOAC3EMndzdN6VSZqklLLIgfxzyaW9jDoeGYJX9SWbJPKpecox0Uw==",
3745
3745
  "funding": [
3746
3746
  "https://opencollective.com/katex",
3747
3747
  "https://github.com/sponsors/katex"