@latent-space-labs/open-auto-doc 0.3.9 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -273,7 +273,8 @@ async function createAndPushDocsRepo(params) {
273
273
  owner = selected;
274
274
  }
275
275
  const isOrg = owner !== username;
276
- const defaultName = config?.repos?.[0] ? `${config.repos[0].name}-docs` : "my-project-docs";
276
+ const slug = config?.projectName ? config.projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "") : config?.repos?.[0]?.name;
277
+ const defaultName = slug ? `${slug}-docs` : "my-project-docs";
277
278
  const repoName = await p3.text({
278
279
  message: "Name for the docs GitHub repo:",
279
280
  initialValue: defaultName,
@@ -1256,6 +1257,258 @@ ${EFFICIENCY_HINTS}`,
1256
1257
  maxTurns: 25
1257
1258
  });
1258
1259
  }
1260
+ var configOutputSchema = {
1261
+ type: "object",
1262
+ properties: {
1263
+ configItems: {
1264
+ type: "array",
1265
+ items: {
1266
+ type: "object",
1267
+ properties: {
1268
+ name: { type: "string", description: "Config variable or option name" },
1269
+ source: { type: "string", description: "Where this config is defined (e.g. .env, config.ts, process.env)" },
1270
+ type: { type: "string", description: "Data type (string, number, boolean, etc.)" },
1271
+ defaultValue: { type: "string", description: "Default value if any" },
1272
+ required: { type: "boolean", description: "Whether this config is required" },
1273
+ description: { type: "string", description: "What this config option does" },
1274
+ category: { type: "string", description: "Grouping category (e.g. Database, Auth, Feature Flags)" }
1275
+ },
1276
+ required: ["name", "source", "type", "required", "description"]
1277
+ }
1278
+ },
1279
+ configFiles: {
1280
+ type: "array",
1281
+ items: { type: "string" },
1282
+ description: "List of configuration file paths found in the project"
1283
+ },
1284
+ environmentVariables: {
1285
+ type: "array",
1286
+ items: { type: "string" },
1287
+ description: "List of environment variable names used in the project"
1288
+ }
1289
+ },
1290
+ required: ["configItems", "configFiles", "environmentVariables"]
1291
+ };
1292
+ async function analyzeConfiguration(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse) {
1293
+ const claudeMdContext = staticAnalysis.claudeMd.map((c) => c.content).join("\n\n");
1294
+ return runAgent({
1295
+ onAgentMessage,
1296
+ onToolUse,
1297
+ systemPrompt: `You are a configuration documentation expert. Your job is to find and document every configuration option, environment variable, and feature flag in a codebase.
1298
+ Your output must be valid JSON matching the provided schema. No markdown, no explanations outside the JSON.`,
1299
+ prompt: `Analyze this codebase and extract all configuration options and environment variables.
1300
+
1301
+ ## Architecture Context
1302
+ ${architecture.summary}
1303
+ Tech Stack: ${architecture.techStack.join(", ")}
1304
+ ${claudeMdContext ? `
1305
+ ## CLAUDE.md Context
1306
+ ${claudeMdContext}
1307
+ ` : ""}
1308
+
1309
+ ## Instructions
1310
+ 1. Use Glob to find config files: \`.env*\`, \`config/**\`, \`**/config.*\`, \`**/*.config.*\`, \`**/settings.*\`, \`**/.env.example\`
1311
+ 2. Use Grep to search for \`process.env\`, \`os.environ\`, \`ConfigService\`, \`@Value\`, \`getenv\`, \`ENV[\`, \`config.\` references
1312
+ 3. Use Read to examine config files, .env.example files, and files that reference environment variables
1313
+
1314
+ For each configuration item:
1315
+ - Identify the variable name and where it's defined
1316
+ - Determine its type and default value (if any)
1317
+ - Note whether it's required for the app to function
1318
+ - Write a clear description of what it controls
1319
+ - Assign a category (Database, Auth, API Keys, Feature Flags, Server, Logging, etc.)
1320
+
1321
+ Also list all config files found and all environment variable names.
1322
+ If no configuration is found, return empty arrays.
1323
+ ${EFFICIENCY_HINTS}`,
1324
+ cwd: repoPath,
1325
+ apiKey,
1326
+ model,
1327
+ outputSchema: configOutputSchema,
1328
+ maxTurns: 30
1329
+ });
1330
+ }
1331
+ var businessLogicSchema = {
1332
+ type: "object",
1333
+ properties: {
1334
+ domainConcepts: {
1335
+ type: "array",
1336
+ items: {
1337
+ type: "object",
1338
+ properties: {
1339
+ name: { type: "string", description: "Domain concept name (e.g. User, Order, Subscription)" },
1340
+ description: { type: "string", description: "What this concept represents in the domain" },
1341
+ relatedFiles: { type: "array", items: { type: "string" }, description: "Key files implementing this concept" }
1342
+ },
1343
+ required: ["name", "description", "relatedFiles"]
1344
+ }
1345
+ },
1346
+ businessRules: {
1347
+ type: "array",
1348
+ items: {
1349
+ type: "object",
1350
+ properties: {
1351
+ name: { type: "string", description: "Short name for the business rule" },
1352
+ description: { type: "string", description: "What the rule enforces or ensures" },
1353
+ sourceFiles: { type: "array", items: { type: "string" }, description: "Files containing this rule" },
1354
+ category: { type: "string", description: "Category (Validation, Authorization, Pricing, Workflow, etc.)" }
1355
+ },
1356
+ required: ["name", "description", "sourceFiles"]
1357
+ }
1358
+ },
1359
+ workflows: {
1360
+ type: "array",
1361
+ items: {
1362
+ type: "object",
1363
+ properties: {
1364
+ name: { type: "string", description: "Workflow name" },
1365
+ description: { type: "string", description: "What this workflow accomplishes" },
1366
+ steps: { type: "array", items: { type: "string" }, description: "Ordered steps in the workflow" },
1367
+ diagram: {
1368
+ type: "object",
1369
+ properties: {
1370
+ id: { type: "string" },
1371
+ title: { type: "string" },
1372
+ description: { type: "string" },
1373
+ mermaidSyntax: { type: "string" }
1374
+ },
1375
+ required: ["id", "title", "description", "mermaidSyntax"]
1376
+ }
1377
+ },
1378
+ required: ["name", "description", "steps"]
1379
+ }
1380
+ },
1381
+ keyInvariants: {
1382
+ type: "array",
1383
+ items: { type: "string" },
1384
+ description: "Key invariants or constraints the system maintains"
1385
+ }
1386
+ },
1387
+ required: ["domainConcepts", "businessRules", "workflows", "keyInvariants"]
1388
+ };
1389
+ async function analyzeBusinessLogic(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse) {
1390
+ const claudeMdContext = staticAnalysis.claudeMd.map((c) => c.content).join("\n\n");
1391
+ return runAgent({
1392
+ onAgentMessage,
1393
+ onToolUse,
1394
+ systemPrompt: `You are a domain analysis expert. Your job is to extract the "why" behind the code \u2014 the business rules, domain concepts, workflows, and invariants that shape how the software behaves.
1395
+ Focus on rules and logic, not implementation details. Your output must be valid JSON matching the provided schema. No markdown, no explanations outside the JSON.`,
1396
+ prompt: `Analyze this codebase and extract business logic, domain concepts, and workflows.
1397
+
1398
+ ## Architecture Context
1399
+ ${architecture.summary}
1400
+ Tech Stack: ${architecture.techStack.join(", ")}
1401
+ Modules: ${architecture.modules.map((m) => `${m.name}: ${m.description}`).join("\n")}
1402
+ ${claudeMdContext ? `
1403
+ ## CLAUDE.md Context
1404
+ ${claudeMdContext}
1405
+ ` : ""}
1406
+
1407
+ ## Instructions
1408
+ 1. Use Glob to find service, domain, and business logic files: \`**/services/**\`, \`**/domain/**\`, \`**/rules/**\`, \`**/validators/**\`, \`**/policies/**\`, \`**/workflows/**\`, \`**/middleware/**\`
1409
+ 2. Use Grep to find validation functions, guard clauses, authorization checks, state transitions, business rule comments
1410
+ 3. Use Read to examine key files and understand the domain logic
1411
+
1412
+ **Domain Concepts**: Identify the core entities/concepts of the domain (not just data models, but the ideas the software is built around). Explain what each represents.
1413
+
1414
+ **Business Rules**: Find rules encoded in the logic \u2014 validation rules, authorization policies, pricing logic, rate limits, state machine transitions. For each rule, explain what it enforces.
1415
+
1416
+ **Workflows**: Identify multi-step processes (e.g. user registration flow, order processing, deployment pipeline). List the steps and optionally generate a Mermaid \`stateDiagram-v2\` for the most important workflow.
1417
+
1418
+ **Key Invariants**: List constraints the system must always maintain (e.g. "every order must have a valid customer", "API keys must be hashed before storage").
1419
+
1420
+ If this is a library without clear business logic, focus on the design rules and constraints that guide how the library is used.
1421
+ ${EFFICIENCY_HINTS}`,
1422
+ cwd: repoPath,
1423
+ apiKey,
1424
+ model,
1425
+ outputSchema: businessLogicSchema,
1426
+ maxTurns: 35
1427
+ });
1428
+ }
1429
+ var errorHandlingSchema = {
1430
+ type: "object",
1431
+ properties: {
1432
+ errorCodes: {
1433
+ type: "array",
1434
+ items: {
1435
+ type: "object",
1436
+ properties: {
1437
+ code: { type: "string", description: "Error code identifier" },
1438
+ httpStatus: { type: "number", description: "Associated HTTP status code if applicable" },
1439
+ message: { type: "string", description: "Error message shown to users" },
1440
+ description: { type: "string", description: "Detailed explanation of when and why this error occurs" },
1441
+ sourceFile: { type: "string", description: "File where this error is defined" }
1442
+ },
1443
+ required: ["code", "message", "description"]
1444
+ }
1445
+ },
1446
+ commonErrors: {
1447
+ type: "array",
1448
+ items: {
1449
+ type: "object",
1450
+ properties: {
1451
+ error: { type: "string", description: "Error name or symptom" },
1452
+ cause: { type: "string", description: "What causes this error" },
1453
+ solution: { type: "string", description: "How to fix or resolve this error" },
1454
+ category: { type: "string", description: "Category (Setup, Runtime, Configuration, Authentication, etc.)" }
1455
+ },
1456
+ required: ["error", "cause", "solution"]
1457
+ }
1458
+ },
1459
+ errorClasses: {
1460
+ type: "array",
1461
+ items: { type: "string" },
1462
+ description: "Custom error class names defined in the codebase"
1463
+ },
1464
+ debuggingTips: {
1465
+ type: "array",
1466
+ items: { type: "string" },
1467
+ description: "General debugging tips and techniques for this project"
1468
+ }
1469
+ },
1470
+ required: ["errorCodes", "commonErrors", "errorClasses", "debuggingTips"]
1471
+ };
1472
+ async function analyzeErrorHandling(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse) {
1473
+ const claudeMdContext = staticAnalysis.claudeMd.map((c) => c.content).join("\n\n");
1474
+ return runAgent({
1475
+ onAgentMessage,
1476
+ onToolUse,
1477
+ systemPrompt: `You are an error handling documentation expert. Your job is to find and document all error patterns, error codes, custom error classes, and common failure modes in a codebase. Write troubleshooting guidance that helps developers diagnose and fix issues.
1478
+ Your output must be valid JSON matching the provided schema. No markdown, no explanations outside the JSON.`,
1479
+ prompt: `Analyze this codebase and document its error handling patterns and common errors.
1480
+
1481
+ ## Architecture Context
1482
+ ${architecture.summary}
1483
+ Tech Stack: ${architecture.techStack.join(", ")}
1484
+ ${claudeMdContext ? `
1485
+ ## CLAUDE.md Context
1486
+ ${claudeMdContext}
1487
+ ` : ""}
1488
+
1489
+ ## Instructions
1490
+ 1. Use Grep to find custom Error classes: \`extends Error\`, \`extends BaseError\`, \`class.*Error\`, \`class.*Exception\`
1491
+ 2. Use Grep to find error code constants: \`ERROR_\`, \`ERR_\`, \`error_code\`, HTTP status codes (\`400\`, \`401\`, \`403\`, \`404\`, \`500\`)
1492
+ 3. Use Grep to find error handling patterns: \`try.*catch\`, error middleware, \`.catch(\`, \`onError\`, \`handleError\`
1493
+ 4. Use Read to examine error handling files, middleware, and error class definitions
1494
+
1495
+ **Error Codes**: Document any defined error codes with their HTTP status (if applicable), user-facing message, and a detailed description of when they occur.
1496
+
1497
+ **Common Errors**: Identify errors developers commonly encounter when setting up, configuring, or using this project. For each, explain the cause and provide a clear solution.
1498
+
1499
+ **Error Classes**: List all custom error/exception classes defined in the project.
1500
+
1501
+ **Debugging Tips**: Write 3-8 practical debugging tips specific to this project (e.g. "Enable verbose logging by setting LOG_LEVEL=debug", "Check the /health endpoint for service status").
1502
+
1503
+ If no error handling patterns are found, return empty arrays with a few general debugging tips.
1504
+ ${EFFICIENCY_HINTS}`,
1505
+ cwd: repoPath,
1506
+ apiKey,
1507
+ model,
1508
+ outputSchema: errorHandlingSchema,
1509
+ maxTurns: 30
1510
+ });
1511
+ }
1259
1512
  var guideOutputSchema = {
1260
1513
  type: "object",
1261
1514
  properties: {
@@ -1417,6 +1670,25 @@ var SECTION_PATTERNS = {
1417
1670
  /setup/i,
1418
1671
  /contributing/i,
1419
1672
  /getting.?started/i
1673
+ ],
1674
+ configuration: [
1675
+ /\.env/i,
1676
+ /config\//i,
1677
+ /settings\//i,
1678
+ /\.config\.(ts|js|mjs|cjs)$/
1679
+ ],
1680
+ businessLogic: [
1681
+ /services?\//i,
1682
+ /domain\//i,
1683
+ /rules?\//i,
1684
+ /validators?\//i,
1685
+ /policies?\//i,
1686
+ /workflows?\//i
1687
+ ],
1688
+ errorHandling: [
1689
+ /errors?\//i,
1690
+ /exceptions?\//i,
1691
+ /middleware\//i
1420
1692
  ]
1421
1693
  };
1422
1694
  function computeDiff(repoPath, fromSha) {
@@ -1448,7 +1720,10 @@ function classifyChanges(entries, staticAnalysis) {
1448
1720
  "components",
1449
1721
  "dataModels",
1450
1722
  "features",
1451
- "gettingStarted"
1723
+ "gettingStarted",
1724
+ "configuration",
1725
+ "businessLogic",
1726
+ "errorHandling"
1452
1727
  ]),
1453
1728
  fullRegenRequired: true
1454
1729
  };
@@ -1510,21 +1785,30 @@ async function analyzeRepository(options) {
1510
1785
  onProgress?.("architecture", "Analyzing architecture with AI...");
1511
1786
  const architecture = await analyzeArchitecture(repoPath, staticAnalysis, apiKey, model, onAgentMessage, onToolUse);
1512
1787
  onProgress?.("architecture", `Identified ${architecture.modules.length} modules, ${architecture.diagrams.length} diagrams`);
1513
- onProgress?.("details", "Analyzing APIs, components, data models, and features...");
1514
- const [apiSettled, compSettled, modelSettled, featuresSettled] = await Promise.allSettled([
1788
+ onProgress?.("details", "Analyzing APIs, components, data models, features, config, business logic, errors...");
1789
+ const [apiSettled, compSettled, modelSettled, featuresSettled, configSettled, bizLogicSettled, errorSettled] = await Promise.allSettled([
1515
1790
  analyzeApiEndpoints(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse),
1516
1791
  analyzeComponents(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse),
1517
1792
  analyzeDataModels(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse),
1518
- analyzeFeatures(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse)
1793
+ analyzeFeatures(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse),
1794
+ analyzeConfiguration(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse),
1795
+ analyzeBusinessLogic(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse),
1796
+ analyzeErrorHandling(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse)
1519
1797
  ]);
1520
1798
  const apiResult = apiSettled.status === "fulfilled" ? apiSettled.value : null;
1521
1799
  const components = compSettled.status === "fulfilled" ? compSettled.value : [];
1522
1800
  const modelResult = modelSettled.status === "fulfilled" ? modelSettled.value : null;
1523
1801
  const features = featuresSettled.status === "fulfilled" ? featuresSettled.value : null;
1802
+ const configuration = configSettled.status === "fulfilled" ? configSettled.value : null;
1803
+ const businessLogic = bizLogicSettled.status === "fulfilled" ? bizLogicSettled.value : null;
1804
+ const errorHandling = errorSettled.status === "fulfilled" ? errorSettled.value : null;
1524
1805
  if (apiSettled.status === "rejected") onProgress?.("details", `API analysis failed (non-fatal): ${apiSettled.reason}`);
1525
1806
  if (compSettled.status === "rejected") onProgress?.("details", `Component analysis failed (non-fatal): ${compSettled.reason}`);
1526
1807
  if (modelSettled.status === "rejected") onProgress?.("details", `Data model analysis failed (non-fatal): ${modelSettled.reason}`);
1527
1808
  if (featuresSettled.status === "rejected") onProgress?.("details", `Features analysis failed (non-fatal): ${featuresSettled.reason}`);
1809
+ if (configSettled.status === "rejected") onProgress?.("details", `Configuration analysis failed (non-fatal): ${configSettled.reason}`);
1810
+ if (bizLogicSettled.status === "rejected") onProgress?.("details", `Business logic analysis failed (non-fatal): ${bizLogicSettled.reason}`);
1811
+ if (errorSettled.status === "rejected") onProgress?.("details", `Error handling analysis failed (non-fatal): ${errorSettled.reason}`);
1528
1812
  const apiEndpoints = apiResult?.endpoints ?? [];
1529
1813
  const dataModels = modelResult?.models ?? [];
1530
1814
  const diagrams = [
@@ -1532,6 +1816,11 @@ async function analyzeRepository(options) {
1532
1816
  ...apiResult?.diagram ? [apiResult.diagram] : [],
1533
1817
  ...modelResult?.diagram ? [modelResult.diagram] : []
1534
1818
  ];
1819
+ if (businessLogic) {
1820
+ for (const workflow of businessLogic.workflows) {
1821
+ if (workflow.diagram) diagrams.push(workflow.diagram);
1822
+ }
1823
+ }
1535
1824
  onProgress?.(
1536
1825
  "details",
1537
1826
  `Found ${apiEndpoints.length} endpoints, ${components.length} components, ${dataModels.length} models, ${diagrams.length} diagrams${features ? `, ${features.features.length} features` : ""}`
@@ -1557,7 +1846,10 @@ async function analyzeRepository(options) {
1557
1846
  components,
1558
1847
  dataModels,
1559
1848
  gettingStarted,
1560
- diagrams
1849
+ diagrams,
1850
+ configuration,
1851
+ businessLogic,
1852
+ errorHandling
1561
1853
  };
1562
1854
  }
1563
1855
  async function analyzeRepositoryIncremental(options) {
@@ -1619,8 +1911,12 @@ async function analyzeRepositoryIncremental(options) {
1619
1911
  let components = previousResult.components;
1620
1912
  let dataModels = previousResult.dataModels;
1621
1913
  let features = previousResult.features;
1914
+ let configuration = previousResult.configuration;
1915
+ let businessLogic = previousResult.businessLogic;
1916
+ let errorHandling = previousResult.errorHandling;
1622
1917
  let apiDiagram;
1623
1918
  let modelDiagram;
1919
+ const workflowDiagrams = [];
1624
1920
  const prevArchDiagramIds = new Set(previousResult.architecture.diagrams.map((d) => d.id));
1625
1921
  const prevDetailDiagrams = previousResult.diagrams.filter((d) => !prevArchDiagramIds.has(d.id));
1626
1922
  const promises = [];
@@ -1670,6 +1966,42 @@ async function analyzeRepositoryIncremental(options) {
1670
1966
  })
1671
1967
  );
1672
1968
  }
1969
+ if (affected.has("configuration")) {
1970
+ promises.push(
1971
+ analyzeConfiguration(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse).then(
1972
+ (result) => {
1973
+ configuration = result;
1974
+ }
1975
+ ).catch((err) => {
1976
+ onProgress?.("details", `Configuration re-analysis failed (non-fatal): ${err}`);
1977
+ })
1978
+ );
1979
+ }
1980
+ if (affected.has("businessLogic")) {
1981
+ promises.push(
1982
+ analyzeBusinessLogic(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse).then(
1983
+ (result) => {
1984
+ businessLogic = result;
1985
+ for (const workflow of result.workflows) {
1986
+ if (workflow.diagram) workflowDiagrams.push(workflow.diagram);
1987
+ }
1988
+ }
1989
+ ).catch((err) => {
1990
+ onProgress?.("details", `Business logic re-analysis failed (non-fatal): ${err}`);
1991
+ })
1992
+ );
1993
+ }
1994
+ if (affected.has("errorHandling")) {
1995
+ promises.push(
1996
+ analyzeErrorHandling(repoPath, staticAnalysis, architecture, apiKey, model, onAgentMessage, onToolUse).then(
1997
+ (result) => {
1998
+ errorHandling = result;
1999
+ }
2000
+ ).catch((err) => {
2001
+ onProgress?.("details", `Error handling re-analysis failed (non-fatal): ${err}`);
2002
+ })
2003
+ );
2004
+ }
1673
2005
  if (promises.length > 0) {
1674
2006
  onProgress?.("details", "Re-analyzing affected sections...");
1675
2007
  await Promise.all(promises);
@@ -1687,6 +2019,13 @@ async function analyzeRepositoryIncremental(options) {
1687
2019
  const prevModelDiag = prevDetailDiagrams.find((d) => d.id.includes("model") || d.id.includes("er"));
1688
2020
  if (prevModelDiag) diagrams.push(prevModelDiag);
1689
2021
  }
2022
+ if (affected.has("businessLogic")) {
2023
+ diagrams.push(...workflowDiagrams);
2024
+ } else if (businessLogic) {
2025
+ for (const workflow of businessLogic.workflows) {
2026
+ if (workflow.diagram) diagrams.push(workflow.diagram);
2027
+ }
2028
+ }
1690
2029
  let gettingStarted = previousResult.gettingStarted;
1691
2030
  if (affected.has("gettingStarted")) {
1692
2031
  onProgress?.("synthesis", "Re-writing getting started guide...");
@@ -1711,7 +2050,10 @@ async function analyzeRepositoryIncremental(options) {
1711
2050
  components,
1712
2051
  dataModels,
1713
2052
  gettingStarted,
1714
- diagrams
2053
+ diagrams,
2054
+ configuration,
2055
+ businessLogic,
2056
+ errorHandling
1715
2057
  };
1716
2058
  }
1717
2059
  var crossRepoSchema = {
@@ -1883,7 +2225,7 @@ Only edit files inside content/docs/.`,
1883
2225
  maxTurns: 35
1884
2226
  });
1885
2227
  }
1886
- var CACHE_VERSION = 2;
2228
+ var CACHE_VERSION = 3;
1887
2229
  function slugify(name) {
1888
2230
  return name.replace(/[^a-zA-Z0-9_-]/g, "_");
1889
2231
  }
@@ -1912,6 +2254,137 @@ function loadCache(cacheDir, repoSlug) {
1912
2254
  return null;
1913
2255
  }
1914
2256
  }
2257
+ function computeChangelog(previous, current, fromCommit, toCommit) {
2258
+ const added = [];
2259
+ const removed = [];
2260
+ const modified = [];
2261
+ diffByKey(
2262
+ previous.apiEndpoints,
2263
+ current.apiEndpoints,
2264
+ (e) => `${e.method} ${e.path}`,
2265
+ (e) => e.description,
2266
+ "API Endpoints",
2267
+ added,
2268
+ removed,
2269
+ modified
2270
+ );
2271
+ diffByKey(
2272
+ previous.components,
2273
+ current.components,
2274
+ (c) => c.name,
2275
+ (c) => c.description,
2276
+ "Components",
2277
+ added,
2278
+ removed,
2279
+ modified
2280
+ );
2281
+ diffByKey(
2282
+ previous.dataModels,
2283
+ current.dataModels,
2284
+ (m) => m.name,
2285
+ (m) => m.description,
2286
+ "Data Models",
2287
+ added,
2288
+ removed,
2289
+ modified
2290
+ );
2291
+ if (previous.configuration && current.configuration) {
2292
+ diffByKey(
2293
+ previous.configuration.configItems,
2294
+ current.configuration.configItems,
2295
+ (c) => c.name,
2296
+ (c) => c.description,
2297
+ "Configuration",
2298
+ added,
2299
+ removed,
2300
+ modified
2301
+ );
2302
+ } else if (current.configuration) {
2303
+ for (const item of current.configuration.configItems) {
2304
+ added.push({ name: item.name, description: item.description, section: "Configuration" });
2305
+ }
2306
+ }
2307
+ if (previous.errorHandling && current.errorHandling) {
2308
+ diffByKey(
2309
+ previous.errorHandling.errorCodes,
2310
+ current.errorHandling.errorCodes,
2311
+ (e) => e.code,
2312
+ (e) => e.description,
2313
+ "Error Codes",
2314
+ added,
2315
+ removed,
2316
+ modified
2317
+ );
2318
+ } else if (current.errorHandling) {
2319
+ for (const item of current.errorHandling.errorCodes) {
2320
+ added.push({ name: item.code, description: item.description, section: "Error Codes" });
2321
+ }
2322
+ }
2323
+ if (previous.businessLogic && current.businessLogic) {
2324
+ diffByKey(
2325
+ previous.businessLogic.domainConcepts,
2326
+ current.businessLogic.domainConcepts,
2327
+ (c) => c.name,
2328
+ (c) => c.description,
2329
+ "Domain Concepts",
2330
+ added,
2331
+ removed,
2332
+ modified
2333
+ );
2334
+ } else if (current.businessLogic) {
2335
+ for (const item of current.businessLogic.domainConcepts) {
2336
+ added.push({ name: item.name, description: item.description, section: "Domain Concepts" });
2337
+ }
2338
+ }
2339
+ if (previous.features && current.features) {
2340
+ diffByKey(
2341
+ previous.features.features,
2342
+ current.features.features,
2343
+ (f) => f.name,
2344
+ (f) => f.description,
2345
+ "Features",
2346
+ added,
2347
+ removed,
2348
+ modified
2349
+ );
2350
+ } else if (current.features) {
2351
+ for (const item of current.features.features) {
2352
+ added.push({ name: item.name, description: item.description, section: "Features" });
2353
+ }
2354
+ }
2355
+ const totalChanges = added.length + removed.length + modified.length;
2356
+ const parts = [];
2357
+ if (added.length > 0) parts.push(`${added.length} added`);
2358
+ if (removed.length > 0) parts.push(`${removed.length} removed`);
2359
+ if (modified.length > 0) parts.push(`${modified.length} modified`);
2360
+ const summary = totalChanges === 0 ? "No documentation changes detected." : `${totalChanges} changes: ${parts.join(", ")}.`;
2361
+ return {
2362
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2363
+ fromCommit,
2364
+ toCommit,
2365
+ added,
2366
+ removed,
2367
+ modified,
2368
+ summary
2369
+ };
2370
+ }
2371
+ function diffByKey(previous, current, getKey, getDescription, section, added, removed, modified) {
2372
+ const prevMap = new Map(previous.map((item) => [getKey(item), item]));
2373
+ const currMap = new Map(current.map((item) => [getKey(item), item]));
2374
+ for (const [key, item] of currMap) {
2375
+ const prev = prevMap.get(key);
2376
+ if (!prev) {
2377
+ added.push({ name: key, description: getDescription(item), section });
2378
+ } else if (getDescription(prev) !== getDescription(item)) {
2379
+ modified.push({ name: key, description: getDescription(item), section });
2380
+ }
2381
+ }
2382
+ for (const [key, item] of prevMap) {
2383
+ if (!currMap.has(key)) {
2384
+ removed.push({ name: key, description: getDescription(item), section });
2385
+ }
2386
+ }
2387
+ }
1915
2388
 
1916
2389
  // src/actions/build-check.ts
1917
2390
  function runBuild(docsDir) {
@@ -2536,7 +3009,7 @@ function loadTemplates() {
2536
3009
  `Template directory not found. __dirname=${__dirname}, searched: ${templateDirs.join(", ")}`
2537
3010
  );
2538
3011
  }
2539
- const templateFiles = ["overview", "features", "getting-started", "architecture", "api-endpoint", "component", "data-model", "diagrams", "cross-repo"];
3012
+ const templateFiles = ["overview", "features", "getting-started", "architecture", "api-endpoint", "component", "data-model", "diagrams", "cross-repo", "configuration", "business-logic", "error-handling", "changelog"];
2540
3013
  for (const name of templateFiles) {
2541
3014
  const filePath = path23.join(templateDir, `${name}.hbs`);
2542
3015
  if (fs23.existsSync(filePath)) {
@@ -2548,11 +3021,12 @@ function loadTemplates() {
2548
3021
  }
2549
3022
  templatesLoaded = true;
2550
3023
  }
2551
- async function writeContent(contentDir, results, crossRepo) {
3024
+ async function writeContent(contentDir, results, crossRepo, changelogs) {
2552
3025
  loadTemplates();
2553
3026
  await fs23.ensureDir(contentDir);
2554
3027
  if (results.length === 1) {
2555
- await writeRepoContent(contentDir, results[0]);
3028
+ const changelog = changelogs?.get(results[0].repoName);
3029
+ await writeRepoContent(contentDir, results[0], changelog);
2556
3030
  } else {
2557
3031
  await writeMultiRepoIndex(contentDir, results);
2558
3032
  if (crossRepo && templates["cross-repo"]) {
@@ -2563,7 +3037,8 @@ async function writeContent(contentDir, results, crossRepo) {
2563
3037
  }
2564
3038
  for (const result of results) {
2565
3039
  const repoDir = path23.join(contentDir, slugify2(result.repoName));
2566
- await writeRepoContent(repoDir, result);
3040
+ const changelog = changelogs?.get(result.repoName);
3041
+ await writeRepoContent(repoDir, result, changelog);
2567
3042
  }
2568
3043
  }
2569
3044
  }
@@ -2595,7 +3070,7 @@ ${repoCards}
2595
3070
  `;
2596
3071
  await fs23.writeFile(path23.join(contentDir, "index.mdx"), escapeMdxOutsideCode(mdx));
2597
3072
  }
2598
- async function writeRepoContent(dir, result) {
3073
+ async function writeRepoContent(dir, result, changelog) {
2599
3074
  await fs23.ensureDir(dir);
2600
3075
  const safeResult = result;
2601
3076
  if (templates["overview"]) {
@@ -2661,6 +3136,62 @@ async function writeRepoContent(dir, result) {
2661
3136
  renderTemplate("diagrams", safeResult)
2662
3137
  );
2663
3138
  }
3139
+ if (safeResult.configuration && safeResult.configuration.configItems.length > 0 && templates["configuration"]) {
3140
+ const configByCategory = {};
3141
+ for (const item of safeResult.configuration.configItems) {
3142
+ const cat = item.category || "General";
3143
+ if (!configByCategory[cat]) configByCategory[cat] = [];
3144
+ configByCategory[cat].push(item);
3145
+ }
3146
+ await fs23.writeFile(
3147
+ path23.join(dir, "configuration.mdx"),
3148
+ renderTemplate("configuration", {
3149
+ ...safeResult,
3150
+ configByCategory,
3151
+ configFiles: safeResult.configuration.configFiles,
3152
+ environmentVariables: safeResult.configuration.environmentVariables
3153
+ })
3154
+ );
3155
+ }
3156
+ if (safeResult.businessLogic && templates["business-logic"]) {
3157
+ const bl = safeResult.businessLogic;
3158
+ if (bl.domainConcepts.length > 0 || bl.businessRules.length > 0 || bl.workflows.length > 0) {
3159
+ await fs23.writeFile(
3160
+ path23.join(dir, "business-logic.mdx"),
3161
+ renderTemplate("business-logic", {
3162
+ ...safeResult,
3163
+ domainConcepts: bl.domainConcepts,
3164
+ businessRules: bl.businessRules,
3165
+ workflows: bl.workflows,
3166
+ keyInvariants: bl.keyInvariants
3167
+ })
3168
+ );
3169
+ }
3170
+ }
3171
+ if (safeResult.errorHandling && templates["error-handling"]) {
3172
+ const eh = safeResult.errorHandling;
3173
+ if (eh.errorCodes.length > 0 || eh.commonErrors.length > 0) {
3174
+ await fs23.writeFile(
3175
+ path23.join(dir, "error-handling.mdx"),
3176
+ renderTemplate("error-handling", {
3177
+ ...safeResult,
3178
+ errorCodes: eh.errorCodes,
3179
+ commonErrors: eh.commonErrors,
3180
+ errorClasses: eh.errorClasses,
3181
+ debuggingTips: eh.debuggingTips
3182
+ })
3183
+ );
3184
+ }
3185
+ }
3186
+ if (changelog && templates["changelog"]) {
3187
+ const hasChanges = changelog.added.length > 0 || changelog.removed.length > 0 || changelog.modified.length > 0;
3188
+ if (hasChanges) {
3189
+ await fs23.writeFile(
3190
+ path23.join(dir, "changelog.mdx"),
3191
+ renderTemplate("changelog", { ...safeResult, ...changelog })
3192
+ );
3193
+ }
3194
+ }
2664
3195
  }
2665
3196
  function renderTemplate(name, data) {
2666
3197
  const template = templates[name];
@@ -2786,9 +3317,10 @@ function sanitizeCodeBlocks(mdx) {
2786
3317
  function slugify2(name) {
2787
3318
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2788
3319
  }
2789
- async function writeMeta(contentDir, results, crossRepo) {
3320
+ async function writeMeta(contentDir, results, crossRepo, changelogs) {
2790
3321
  if (results.length === 1) {
2791
- await writeRepoMeta(contentDir, results[0]);
3322
+ const changelog = changelogs?.get(results[0].repoName);
3323
+ await writeRepoMeta(contentDir, results[0], changelog);
2792
3324
  } else {
2793
3325
  const pages = ["index"];
2794
3326
  if (crossRepo) pages.push("cross-repo");
@@ -2800,20 +3332,25 @@ async function writeMeta(contentDir, results, crossRepo) {
2800
3332
  );
2801
3333
  for (const result of results) {
2802
3334
  const repoDir = path33.join(contentDir, slugify22(result.repoName));
2803
- await writeRepoMeta(repoDir, result);
3335
+ const changelog = changelogs?.get(result.repoName);
3336
+ await writeRepoMeta(repoDir, result, changelog);
2804
3337
  }
2805
3338
  }
2806
3339
  }
2807
- async function writeRepoMeta(dir, result) {
3340
+ async function writeRepoMeta(dir, result, changelog) {
2808
3341
  await fs33.ensureDir(dir);
2809
3342
  const pages = ["index"];
2810
3343
  if (result.features && result.features.features.length > 0) pages.push("features");
2811
3344
  pages.push("getting-started");
3345
+ if (result.configuration && result.configuration.configItems.length > 0) pages.push("configuration");
3346
+ if (result.businessLogic && (result.businessLogic.domainConcepts.length > 0 || result.businessLogic.businessRules.length > 0 || result.businessLogic.workflows.length > 0)) pages.push("business-logic");
2812
3347
  pages.push("architecture");
2813
3348
  if (result.apiEndpoints.length > 0) pages.push("api");
2814
3349
  if (result.components.length > 0) pages.push("components");
2815
3350
  if (result.dataModels.length > 0) pages.push("data-models");
3351
+ if (result.errorHandling && (result.errorHandling.errorCodes.length > 0 || result.errorHandling.commonErrors.length > 0)) pages.push("error-handling");
2816
3352
  if (result.diagrams && result.diagrams.length > 0) pages.push("diagrams");
3353
+ if (changelog && (changelog.added.length > 0 || changelog.removed.length > 0 || changelog.modified.length > 0)) pages.push("changelog");
2817
3354
  const meta = {
2818
3355
  title: result.repoName,
2819
3356
  pages
@@ -3068,6 +3605,12 @@ function buildRepoSummary(result) {
3068
3605
  if (result.dataModels.length > 0) {
3069
3606
  parts.push(`${result.dataModels.length} model${result.dataModels.length === 1 ? "" : "s"}`);
3070
3607
  }
3608
+ if (result.configuration && result.configuration.configItems.length > 0) {
3609
+ parts.push(`${result.configuration.configItems.length} config${result.configuration.configItems.length === 1 ? "" : "s"}`);
3610
+ }
3611
+ if (result.errorHandling && result.errorHandling.errorCodes.length > 0) {
3612
+ parts.push(`${result.errorHandling.errorCodes.length} error code${result.errorHandling.errorCodes.length === 1 ? "" : "s"}`);
3613
+ }
3071
3614
  return parts.length > 0 ? parts.join(", ") : "Analysis complete";
3072
3615
  }
3073
3616
 
@@ -3094,6 +3637,21 @@ Try reinstalling: npm install -g @latent-space-labs/open-auto-doc`
3094
3637
  }
3095
3638
  const repos = await pickRepos(token);
3096
3639
  p6.log.info(`Selected ${repos.length} ${repos.length === 1 ? "repository" : "repositories"}`);
3640
+ let projectName;
3641
+ if (repos.length > 1) {
3642
+ const nameInput = await p6.text({
3643
+ message: "What would you like to name this project?",
3644
+ placeholder: "My Project",
3645
+ validate: (v) => {
3646
+ if (!v || v.trim().length === 0) return "Project name is required";
3647
+ }
3648
+ });
3649
+ if (p6.isCancel(nameInput)) {
3650
+ p6.cancel("Operation cancelled");
3651
+ process.exit(0);
3652
+ }
3653
+ projectName = nameInput;
3654
+ }
3097
3655
  let apiKey = getAnthropicKey();
3098
3656
  if (!apiKey) {
3099
3657
  const keyInput = await p6.text({
@@ -3203,7 +3761,9 @@ Try reinstalling: npm install -g @latent-space-labs/open-auto-doc`
3203
3761
  }
3204
3762
  }
3205
3763
  const outputDir = path9.resolve(options.output || "docs-site");
3206
- const projectName = results.length === 1 ? results[0].repoName : "My Project";
3764
+ if (!projectName) {
3765
+ projectName = results.length === 1 ? results[0].repoName : "My Project";
3766
+ }
3207
3767
  const genSpinner = p6.spinner();
3208
3768
  try {
3209
3769
  genSpinner.start("Scaffolding documentation site...");
@@ -3234,7 +3794,8 @@ Try reinstalling: npm install -g @latent-space-labs/open-auto-doc`
3234
3794
  cloneUrl: r.cloneUrl,
3235
3795
  htmlUrl: r.htmlUrl
3236
3796
  })),
3237
- outputDir
3797
+ outputDir,
3798
+ ...projectName !== results[0]?.repoName && { projectName }
3238
3799
  };
3239
3800
  try {
3240
3801
  saveConfig(config);
@@ -3455,6 +4016,7 @@ async function generateCommand(options) {
3455
4016
  const total = clones.length;
3456
4017
  const progressTable = new ProgressTable({ repos: clones.map((c) => c.info.name) });
3457
4018
  progressTable.start();
4019
+ const changelogs = /* @__PURE__ */ new Map();
3458
4020
  const analysisPromises = clones.map(async (cloned) => {
3459
4021
  const repo = config.repos.find((r) => r.name === cloned.info.name);
3460
4022
  const repoName = repo.name;
@@ -3467,8 +4029,8 @@ async function generateCommand(options) {
3467
4029
  progressTable.update(repoName, { status: "active", message: "Starting..." });
3468
4030
  try {
3469
4031
  let result;
4032
+ const cached = loadCache(cacheDir, repo.name);
3470
4033
  if (incremental) {
3471
- const cached = loadCache(cacheDir, repo.name);
3472
4034
  if (cached) {
3473
4035
  result = await analyzeRepositoryIncremental({
3474
4036
  repoPath: cloned.localPath,
@@ -3503,6 +4065,16 @@ async function generateCommand(options) {
3503
4065
  onToolUse
3504
4066
  });
3505
4067
  }
4068
+ if (cached) {
4069
+ try {
4070
+ const headSha = getHeadSha(cloned.localPath);
4071
+ const changelog = computeChangelog(cached.result, result, cached.commitSha, headSha);
4072
+ if (changelog.added.length > 0 || changelog.removed.length > 0 || changelog.modified.length > 0) {
4073
+ changelogs.set(repoName, changelog);
4074
+ }
4075
+ } catch {
4076
+ }
4077
+ }
3506
4078
  try {
3507
4079
  const headSha = getHeadSha(cloned.localPath);
3508
4080
  saveCache(cacheDir, repo.name, headSha, result);
@@ -3541,8 +4113,8 @@ async function generateCommand(options) {
3541
4113
  }
3542
4114
  }
3543
4115
  const contentDir = path10.join(config.outputDir, "content", "docs");
3544
- await writeContent(contentDir, results, crossRepo);
3545
- await writeMeta(contentDir, results, crossRepo);
4116
+ await writeContent(contentDir, results, crossRepo, changelogs.size > 0 ? changelogs : void 0);
4117
+ await writeMeta(contentDir, results, crossRepo, changelogs.size > 0 ? changelogs : void 0);
3546
4118
  try {
3547
4119
  await runBuildCheck({ docsDir: config.outputDir, apiKey, model });
3548
4120
  } catch (err) {
@@ -3682,7 +4254,7 @@ async function logoutCommand() {
3682
4254
 
3683
4255
  // src/index.ts
3684
4256
  var program = new Command();
3685
- program.name("open-auto-doc").description("Auto-generate beautiful documentation websites from GitHub repositories using AI").version("0.3.9");
4257
+ program.name("open-auto-doc").description("Auto-generate beautiful documentation websites from GitHub repositories using AI").version("0.4.1");
3686
4258
  program.command("init", { isDefault: true }).description("Initialize and generate documentation for your repositories").option("-o, --output <dir>", "Output directory", "docs-site").action(initCommand);
3687
4259
  program.command("generate").description("Regenerate documentation using existing configuration").option("--incremental", "Only re-analyze changed files (uses cached results)").option("--force", "Force full regeneration (ignore cache)").option("--repo <name>", "Only analyze this repo (uses cache for others)").action(generateCommand);
3688
4260
  program.command("deploy").description("Create a GitHub repo for docs and push (connect to Vercel for auto-deploy)").option("-d, --dir <path>", "Docs site directory").action(deployCommand);
@@ -0,0 +1,83 @@
1
+ ---
2
+ title: "Business Logic"
3
+ description: "Domain concepts, business rules, and workflows for {{repoName}}"
4
+ ---
5
+
6
+ # Business Logic & Domain Concepts
7
+
8
+ {{#if domainConcepts.length}}
9
+ ## Domain Concepts
10
+
11
+ {{#each domainConcepts}}
12
+ ### {{this.name}}
13
+
14
+ {{this.description}}
15
+
16
+ {{#if this.relatedFiles.length}}
17
+ <details>
18
+ <summary>Related files</summary>
19
+
20
+ {{#each this.relatedFiles}}
21
+ - `{{this}}`
22
+ {{/each}}
23
+
24
+ </details>
25
+ {{/if}}
26
+
27
+ {{/each}}
28
+ {{/if}}
29
+
30
+ {{#if businessRules.length}}
31
+ ## Business Rules
32
+
33
+ {{#each businessRules}}
34
+ ### {{this.name}}
35
+
36
+ {{this.description}}
37
+
38
+ {{#if this.category}}**Category:** {{this.category}}{{/if}}
39
+
40
+ {{#if this.sourceFiles.length}}
41
+ <details>
42
+ <summary>Source files</summary>
43
+
44
+ {{#each this.sourceFiles}}
45
+ - `{{this}}`
46
+ {{/each}}
47
+
48
+ </details>
49
+ {{/if}}
50
+
51
+ {{/each}}
52
+ {{/if}}
53
+
54
+ {{#if workflows.length}}
55
+ ## Workflows
56
+
57
+ {{#each workflows}}
58
+ ### {{this.name}}
59
+
60
+ {{this.description}}
61
+
62
+ {{#if this.steps.length}}
63
+ {{#each this.steps}}
64
+ {{@index}}. {{this}}
65
+ {{/each}}
66
+ {{/if}}
67
+
68
+ {{#if this.diagram}}
69
+ ```mermaid
70
+ {{{this.diagram.mermaidSyntax}}}
71
+ ```
72
+ {{/if}}
73
+
74
+ {{/each}}
75
+ {{/if}}
76
+
77
+ {{#if keyInvariants.length}}
78
+ ## Key Invariants
79
+
80
+ {{#each keyInvariants}}
81
+ - {{this}}
82
+ {{/each}}
83
+ {{/if}}
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: "What Changed"
3
+ description: "Documentation changelog for {{repoName}}"
4
+ ---
5
+
6
+ # What Changed
7
+
8
+ {{{summary}}}
9
+
10
+ **Commit range:** `{{fromCommit}}` → `{{toCommit}}`
11
+
12
+ **Generated:** {{generatedAt}}
13
+
14
+ {{#if added.length}}
15
+ ## Added
16
+
17
+ {{#each added}}
18
+ - **{{this.name}}** ({{this.section}}) — {{this.description}}
19
+ {{/each}}
20
+ {{/if}}
21
+
22
+ {{#if removed.length}}
23
+ ## Removed
24
+
25
+ {{#each removed}}
26
+ - **{{this.name}}** ({{this.section}}) — {{this.description}}
27
+ {{/each}}
28
+ {{/if}}
29
+
30
+ {{#if modified.length}}
31
+ ## Modified
32
+
33
+ {{#each modified}}
34
+ - **{{this.name}}** ({{this.section}}) — {{this.description}}
35
+ {{/each}}
36
+ {{/if}}
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: "Configuration Reference"
3
+ description: "Configuration options and environment variables for {{repoName}}"
4
+ ---
5
+
6
+ # Configuration Reference
7
+
8
+ {{#if configFiles.length}}
9
+ ## Configuration Files
10
+
11
+ {{#each configFiles}}
12
+ - `{{this}}`
13
+ {{/each}}
14
+ {{/if}}
15
+
16
+ {{#each configByCategory}}
17
+ ## {{@key}}
18
+
19
+ | Name | Source | Type | Default | Required | Description |
20
+ |------|--------|------|---------|----------|-------------|
21
+ {{#each this}}
22
+ | `{{this.name}}` | `{{pipeEscape this.source}}` | `{{pipeEscape this.type}}` | {{#if this.defaultValue}}`{{pipeEscape this.defaultValue}}`{{else}}-{{/if}} | {{#if this.required}}Yes{{else}}No{{/if}} | {{pipeEscape this.description}} |
23
+ {{/each}}
24
+
25
+ {{/each}}
26
+
27
+ {{#if environmentVariables.length}}
28
+ ## Environment Variables
29
+
30
+ {{#each environmentVariables}}
31
+ - `{{this}}`
32
+ {{/each}}
33
+ {{/if}}
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: "Error Handling"
3
+ description: "Error codes, troubleshooting, and debugging for {{repoName}}"
4
+ ---
5
+
6
+ # Error Handling & Troubleshooting
7
+
8
+ {{#if errorClasses.length}}
9
+ ## Error Classes
10
+
11
+ {{#each errorClasses}}
12
+ - `{{this}}`
13
+ {{/each}}
14
+ {{/if}}
15
+
16
+ {{#if errorCodes.length}}
17
+ ## Error Codes
18
+
19
+ | Code | HTTP Status | Message | Description |
20
+ |------|-------------|---------|-------------|
21
+ {{#each errorCodes}}
22
+ | `{{this.code}}` | {{#if this.httpStatus}}{{this.httpStatus}}{{else}}-{{/if}} | {{pipeEscape this.message}} | {{pipeEscape this.description}} |
23
+ {{/each}}
24
+ {{/if}}
25
+
26
+ {{#if commonErrors.length}}
27
+ ## Common Errors & Solutions
28
+
29
+ {{#each commonErrors}}
30
+ ### {{this.error}}
31
+
32
+ {{#if this.category}}**Category:** {{this.category}}{{/if}}
33
+
34
+ **Cause:** {{this.cause}}
35
+
36
+ **Solution:** {{this.solution}}
37
+
38
+ {{/each}}
39
+ {{/if}}
40
+
41
+ {{#if debuggingTips.length}}
42
+ ## Debugging Tips
43
+
44
+ {{#each debuggingTips}}
45
+ - {{this}}
46
+ {{/each}}
47
+ {{/if}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latent-space-labs/open-auto-doc",
3
- "version": "0.3.9",
3
+ "version": "0.4.1",
4
4
  "description": "Auto-generate beautiful documentation websites from GitHub repositories using AI",
5
5
  "type": "module",
6
6
  "bin": {