docspec 0.2.0 → 0.4.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 (80) hide show
  1. package/README.md +64 -142
  2. package/dist/__tests__/changed.test.d.ts +2 -0
  3. package/dist/__tests__/changed.test.d.ts.map +1 -0
  4. package/dist/__tests__/changed.test.js +98 -0
  5. package/dist/__tests__/changed.test.js.map +1 -0
  6. package/dist/__tests__/cli.test.js +48 -145
  7. package/dist/__tests__/cli.test.js.map +1 -1
  8. package/dist/__tests__/create.test.d.ts +2 -0
  9. package/dist/__tests__/create.test.d.ts.map +1 -0
  10. package/dist/__tests__/{generator.test.js → create.test.js} +31 -27
  11. package/dist/__tests__/create.test.js.map +1 -0
  12. package/dist/__tests__/generate.test.d.ts +2 -0
  13. package/dist/__tests__/generate.test.d.ts.map +1 -0
  14. package/dist/__tests__/generate.test.js +152 -0
  15. package/dist/__tests__/generate.test.js.map +1 -0
  16. package/dist/__tests__/path-utils.test.d.ts +2 -0
  17. package/dist/__tests__/path-utils.test.d.ts.map +1 -0
  18. package/dist/__tests__/path-utils.test.js +49 -0
  19. package/dist/__tests__/path-utils.test.js.map +1 -0
  20. package/dist/__tests__/template.test.d.ts +2 -0
  21. package/dist/__tests__/template.test.d.ts.map +1 -0
  22. package/dist/__tests__/template.test.js +95 -0
  23. package/dist/__tests__/template.test.js.map +1 -0
  24. package/dist/changed.d.ts +25 -0
  25. package/dist/changed.d.ts.map +1 -0
  26. package/dist/changed.js +209 -0
  27. package/dist/changed.js.map +1 -0
  28. package/dist/cli.js +89 -72
  29. package/dist/cli.js.map +1 -1
  30. package/dist/constants.d.ts +2 -0
  31. package/dist/constants.d.ts.map +1 -1
  32. package/dist/constants.js +118 -15
  33. package/dist/constants.js.map +1 -1
  34. package/dist/create.d.ts +14 -0
  35. package/dist/create.d.ts.map +1 -0
  36. package/dist/create.js +97 -0
  37. package/dist/create.js.map +1 -0
  38. package/dist/generate.d.ts +26 -0
  39. package/dist/generate.d.ts.map +1 -0
  40. package/dist/generate.js +176 -0
  41. package/dist/generate.js.map +1 -0
  42. package/dist/index.d.ts +8 -4
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +16 -7
  45. package/dist/index.js.map +1 -1
  46. package/dist/logger.d.ts +40 -0
  47. package/dist/logger.d.ts.map +1 -0
  48. package/dist/logger.js +74 -0
  49. package/dist/logger.js.map +1 -0
  50. package/dist/path-utils.d.ts +17 -0
  51. package/dist/path-utils.d.ts.map +1 -0
  52. package/dist/path-utils.js +76 -0
  53. package/dist/path-utils.js.map +1 -0
  54. package/dist/{format-parser.d.ts → template.d.ts} +5 -8
  55. package/dist/template.d.ts.map +1 -0
  56. package/dist/{format-parser.js → template.js} +33 -57
  57. package/dist/template.js.map +1 -0
  58. package/package.json +1 -1
  59. package/README.docspec.md +0 -180
  60. package/dist/__tests__/generator.test.d.ts +0 -2
  61. package/dist/__tests__/generator.test.d.ts.map +0 -1
  62. package/dist/__tests__/generator.test.js.map +0 -1
  63. package/dist/__tests__/validator.test.d.ts +0 -2
  64. package/dist/__tests__/validator.test.d.ts.map +0 -1
  65. package/dist/__tests__/validator.test.js +0 -331
  66. package/dist/__tests__/validator.test.js.map +0 -1
  67. package/dist/format-parser.d.ts.map +0 -1
  68. package/dist/format-parser.js.map +0 -1
  69. package/dist/generator.d.ts +0 -11
  70. package/dist/generator.d.ts.map +0 -1
  71. package/dist/generator.js +0 -66
  72. package/dist/generator.js.map +0 -1
  73. package/dist/types.d.ts +0 -16
  74. package/dist/types.d.ts.map +0 -1
  75. package/dist/types.js +0 -3
  76. package/dist/types.js.map +0 -1
  77. package/dist/validator.d.ts +0 -7
  78. package/dist/validator.d.ts.map +0 -1
  79. package/dist/validator.js +0 -178
  80. package/dist/validator.js.map +0 -1
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildDocspecChangedPrompt = buildDocspecChangedPrompt;
37
+ const fs = __importStar(require("fs/promises"));
38
+ const fsSync = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const child_process_1 = require("child_process");
41
+ const path_utils_1 = require("./path-utils");
42
+ const DEFAULT_MAX_DOCSPECS = 10;
43
+ const DEFAULT_MAX_DIFF_CHARS = 120000;
44
+ /**
45
+ * List changed files via git diff --name-only base...merge
46
+ */
47
+ function listChangedFiles(base, merge, repoRoot) {
48
+ const out = (0, child_process_1.execSync)(`git diff --name-only ${base}...${merge}`, {
49
+ encoding: "utf-8",
50
+ cwd: repoRoot,
51
+ }).trim();
52
+ return out ? out.split("\n").map((line) => line.trim()).filter(Boolean) : [];
53
+ }
54
+ /**
55
+ * Get diff text via git diff base...merge, truncated if needed.
56
+ */
57
+ function getDiffText(base, merge, repoRoot, maxChars) {
58
+ let diff;
59
+ try {
60
+ diff = (0, child_process_1.execSync)(`git diff ${base}...${merge}`, { encoding: "utf-8", cwd: repoRoot });
61
+ }
62
+ catch {
63
+ return "";
64
+ }
65
+ if (diff.length > maxChars) {
66
+ diff = diff.slice(0, maxChars) + "\n\n[DIFF TRUNCATED]\n";
67
+ }
68
+ return diff;
69
+ }
70
+ /**
71
+ * Find all docspec paths under .docspec/ in the repo.
72
+ */
73
+ async function findAllDocspecPaths(docspecDir) {
74
+ const files = [];
75
+ try {
76
+ const entries = await fs.readdir(docspecDir, { withFileTypes: true });
77
+ for (const entry of entries) {
78
+ const full = path.join(docspecDir, entry.name);
79
+ if (entry.isDirectory()) {
80
+ files.push(...(await findAllDocspecPaths(full)));
81
+ }
82
+ else if (entry.isFile() && entry.name.endsWith(".docspec.md")) {
83
+ files.push(full);
84
+ }
85
+ }
86
+ }
87
+ catch (e) {
88
+ if (e.code !== "ENOENT")
89
+ throw e;
90
+ }
91
+ return files;
92
+ }
93
+ /**
94
+ * Find candidate docspec files to process given changed files.
95
+ * Strategy:
96
+ * 1) Changed files that are under .docspec/ and end with .docspec.md are included.
97
+ * 2) For each other changed file, walk up from its directory to repo root; at each level,
98
+ * include docspecs whose target markdown lives in that directory.
99
+ */
100
+ function findCandidateDocspecs(repoRoot, docspecPaths, changedFiles, maxDocspecs) {
101
+ const candidates = [];
102
+ const seen = new Set();
103
+ const add = (p) => {
104
+ const norm = path.normalize(p).replace(/\\/g, "/");
105
+ if (!seen.has(norm)) {
106
+ seen.add(norm);
107
+ candidates.push(p);
108
+ }
109
+ };
110
+ // 1) Directly changed docspecs (under .docspec/)
111
+ for (const f of changedFiles) {
112
+ const normalized = path.normalize(f).replace(/\\/g, "/");
113
+ if ((0, path_utils_1.isDocspecPath)(normalized)) {
114
+ const full = path.join(repoRoot, f);
115
+ add(full);
116
+ }
117
+ }
118
+ // 2) For each changed file, walk up directory and include docspecs whose target markdown is in that directory
119
+ for (const f of changedFiles) {
120
+ const normalized = path.normalize(f).replace(/\\/g, "/");
121
+ if (normalized.startsWith(".docspec/"))
122
+ continue; // already handled
123
+ const fullPath = path.join(repoRoot, f);
124
+ let dir = path.dirname(fullPath);
125
+ while (true) {
126
+ const relDir = path.relative(repoRoot, dir).replace(/\\/g, "/") || ".";
127
+ for (const { docspecPath, targetMdPath } of docspecPaths) {
128
+ const targetDir = path.dirname(targetMdPath).replace(/\\/g, "/") || ".";
129
+ if (targetDir === relDir) {
130
+ add(docspecPath);
131
+ }
132
+ }
133
+ const parent = path.dirname(dir);
134
+ if (parent === dir || path.relative(repoRoot, parent).startsWith(".."))
135
+ break;
136
+ dir = parent;
137
+ }
138
+ // Include if the changed file is the target markdown
139
+ for (const { docspecPath, targetMdPath } of docspecPaths) {
140
+ if (path.normalize(f).replace(/\\/g, "/") === path.normalize(targetMdPath).replace(/\\/g, "/")) {
141
+ add(docspecPath);
142
+ }
143
+ }
144
+ }
145
+ return candidates.slice(0, maxDocspecs);
146
+ }
147
+ /**
148
+ * Build the changed prompt (sync markdown with docspecs from PR changes) and return it.
149
+ * If options.outputPath is set, writes the prompt to that file.
150
+ */
151
+ async function buildDocspecChangedPrompt(options) {
152
+ const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
153
+ const docspecDir = path.join(repoRoot, ".docspec");
154
+ let changedFiles = options.changedFiles ?? [];
155
+ let diffText = "";
156
+ if (changedFiles.length === 0 && options.base && options.merge) {
157
+ changedFiles = listChangedFiles(options.base, options.merge, repoRoot);
158
+ diffText = getDiffText(options.base, options.merge, repoRoot, options.maxDiffChars ?? DEFAULT_MAX_DIFF_CHARS);
159
+ }
160
+ else if (options.changedFiles && options.changedFiles.length > 0 && options.base && options.merge) {
161
+ diffText = getDiffText(options.base, options.merge, repoRoot, options.maxDiffChars ?? DEFAULT_MAX_DIFF_CHARS);
162
+ }
163
+ const allDocspecPaths = await findAllDocspecPaths(docspecDir);
164
+ const docspecWithTargets = allDocspecPaths
165
+ .map((p) => {
166
+ const rel = path.relative(repoRoot, p).replace(/\\/g, "/");
167
+ const targetMd = (0, path_utils_1.docspecToMarkdownPath)(rel);
168
+ return { docspecPath: p, targetMdPath: targetMd };
169
+ })
170
+ .filter(({ docspecPath }) => fsSync.existsSync(docspecPath));
171
+ const candidates = findCandidateDocspecs(repoRoot, docspecWithTargets, changedFiles, options.maxDocspecs ?? DEFAULT_MAX_DOCSPECS);
172
+ const parts = [
173
+ "Merged PR diff (context):",
174
+ "<diff>",
175
+ diffText || "(no diff available)",
176
+ "</diff>",
177
+ "",
178
+ "The following docspec files were discovered based on the PR changes. For each docspec, check if its target markdown file needs to be updated based on the code changes:",
179
+ "",
180
+ ];
181
+ let added = 0;
182
+ for (const docspecPath of candidates) {
183
+ const relDocspec = path.relative(repoRoot, docspecPath).replace(/\\/g, "/");
184
+ const targetMdPath = (0, path_utils_1.docspecToMarkdownPath)(relDocspec);
185
+ const targetFull = path.join(repoRoot, targetMdPath);
186
+ try {
187
+ await fs.access(targetFull);
188
+ }
189
+ catch {
190
+ continue;
191
+ }
192
+ const docspecContent = await fs.readFile(docspecPath, "utf-8");
193
+ const mdContent = await fs.readFile(targetFull, "utf-8");
194
+ parts.push(`## Docspec: ${relDocspec}`, `Target markdown: ${targetMdPath}`, "", "<docspec>", docspecContent, "</docspec>", "", "<markdown>", mdContent, "</markdown>", "");
195
+ added++;
196
+ }
197
+ if (added === 0) {
198
+ return { prompt: "", outputPath: null };
199
+ }
200
+ parts.push("Task:", "1. Explore the repository using your available tools to understand the codebase context", "2. Understand how the code changes in the diff relate to each docspec's requirements", "3. For each markdown file listed above, check if it already satisfies its docspec given the code changes", "4. Only update markdown files if changes are actually necessary to satisfy their docspecs - avoid making unnecessary changes", "5. Use the Edit tool to modify markdown files directly if changes are needed", "6. Do not provide any text output - files are modified directly using tools");
201
+ const prompt = parts.join("\n");
202
+ const outPath = options.outputPath ? path.resolve(repoRoot, options.outputPath) : null;
203
+ if (outPath && prompt) {
204
+ await fs.mkdir(path.dirname(outPath), { recursive: true });
205
+ await fs.writeFile(outPath, prompt, "utf-8");
206
+ }
207
+ return { prompt, outputPath: outPath };
208
+ }
209
+ //# sourceMappingURL=changed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changed.js","sourceRoot":"","sources":["../src/changed.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -35,99 +35,116 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  const commander_1 = require("commander");
38
- const fs = __importStar(require("fs/promises"));
39
38
  const path = __importStar(require("path"));
40
- const validator_1 = require("./validator");
41
- const generator_1 = require("./generator");
39
+ const create_1 = require("./create");
40
+ const logger_1 = require("./logger");
41
+ const path_utils_1 = require("./path-utils");
42
+ const changed_1 = require("./changed");
43
+ const generate_1 = require("./generate");
42
44
  const program = new commander_1.Command();
43
45
  program
44
46
  .name("docspec")
45
- .description("Generate and validate docspec files (*.docspec.md)")
46
- .version("0.1.0");
47
- program
48
- .command("validate")
49
- .description("Validate docspec files")
50
- .argument("[paths...]", "Paths to docspec files (if not provided, finds all *.docspec.md files)")
51
- .action(async (filePaths) => {
52
- let filesToValidate = [];
53
- if (filePaths.length > 0) {
54
- // Use provided file paths (from pre-commit or user)
55
- filesToValidate = filePaths;
47
+ .description("Generate docspec files and prompts under .docspec/")
48
+ .version("0.3.0")
49
+ .option("-v, --verbose", "Enable verbose output with detailed logging")
50
+ .argument("[markdown_path]", "Path to markdown file (creates .docspec/<path>.docspec.md)")
51
+ .action(async (markdownPath) => {
52
+ if (!markdownPath)
53
+ return;
54
+ const opts = program.opts();
55
+ logger_1.logger.setVerbose(opts.verbose || false);
56
+ try {
57
+ const resolved = path.resolve(process.cwd(), markdownPath).replace(/\\/g, "/");
58
+ const cwd = process.cwd().replace(/\\/g, "/");
59
+ const relativeMd = resolved.startsWith(cwd)
60
+ ? path.relative(cwd, resolved).replace(/\\/g, "/")
61
+ : markdownPath;
62
+ await (0, create_1.generateDocspec)(relativeMd);
63
+ logger_1.logger.success(`Generated docspec file: ${(0, path_utils_1.markdownToDocspecPath)(relativeMd)}`);
56
64
  }
57
- else {
58
- // Find all *.docspec.md files in current directory tree
59
- filesToValidate = await findDocspecFiles(process.cwd());
65
+ catch (error) {
66
+ logger_1.logger.error(`Failed to generate docspec file: ${error instanceof Error ? error.message : String(error)}`);
67
+ process.exit(1);
60
68
  }
61
- if (filesToValidate.length === 0) {
62
- console.log("No docspec files found to validate.");
63
- process.exit(0);
69
+ });
70
+ program
71
+ .command("changed")
72
+ .description("Generate a prompt to sync markdown files with their docspecs based on changed files (for use with an external LLM)")
73
+ .option("--changed-files <paths>", "Comma-separated list of changed file paths (or omit and use --base/--merge for git diff)")
74
+ .option("--base <sha>", "Base SHA for git diff (e.g. PR base)")
75
+ .option("--merge <sha>", "Merge SHA for git diff (e.g. PR merge commit)")
76
+ .option("--output <file>", "Write prompt to this file", "prompt.txt")
77
+ .option("--max-docspecs <n>", "Max docspecs to include", "10")
78
+ .option("--max-diff-chars <n>", "Max characters of diff to include", "120000")
79
+ .action(async function () {
80
+ const opts = program.opts();
81
+ logger_1.logger.setVerbose(opts.verbose || false);
82
+ const cmdOpts = this.opts();
83
+ const changedFiles = cmdOpts.changedFiles
84
+ ? String(cmdOpts.changedFiles).split(",").map((s) => s.trim()).filter(Boolean)
85
+ : undefined;
86
+ const base = cmdOpts.base;
87
+ const merge = cmdOpts.merge;
88
+ if (!changedFiles?.length && (!base || !merge)) {
89
+ logger_1.logger.error("Either provide --changed-files or both --base and --merge for git diff.");
90
+ process.exit(1);
64
91
  }
65
- let hasErrors = false;
66
- for (const filePath of filesToValidate) {
67
- const result = await (0, validator_1.validateDocspec)(filePath);
68
- if (!result.valid) {
69
- hasErrors = true;
70
- console.error(`\n❌ ${filePath}:`);
71
- for (const error of result.errors) {
72
- console.error(` - ${error}`);
73
- }
92
+ try {
93
+ const { prompt, outputPath } = await (0, changed_1.buildDocspecChangedPrompt)({
94
+ changedFiles,
95
+ base,
96
+ merge,
97
+ outputPath: cmdOpts.output || "prompt.txt",
98
+ maxDocspecs: parseInt(String(cmdOpts.maxDocspecs), 10),
99
+ maxDiffChars: parseInt(String(cmdOpts.maxDiffChars), 10),
100
+ });
101
+ if (!prompt) {
102
+ logger_1.logger.info("No relevant docspec files found; no prompt written.");
103
+ process.exit(0);
74
104
  }
75
- else {
76
- console.log(`✅ ${filePath}`);
105
+ if (outputPath) {
106
+ logger_1.logger.success(`Prompt written to ${outputPath}`);
107
+ console.log(outputPath);
77
108
  }
78
109
  }
79
- if (hasErrors) {
110
+ catch (error) {
111
+ logger_1.logger.error(error instanceof Error ? error.message : String(error));
80
112
  process.exit(1);
81
113
  }
82
114
  });
83
115
  program
84
116
  .command("generate")
85
- .description("Generate a new docspec file")
86
- .argument("<path>", "Path where the docspec file should be created (must end with .docspec.md)")
87
- .action(async (filePath) => {
117
+ .description("Generate a new docspec for a markdown file and output a prompt for an external LLM to fill/improve it")
118
+ .argument("<markdown_path>", "Path to the markdown file (e.g. README.md, docs/deploy.md)")
119
+ .option("--overwrite", "Overwrite existing docspec file")
120
+ .option("--output-prompt <file>", "Write implementation prompt to this file", "prompt.txt")
121
+ .option("--output-plan <file>", "Write plan prompt to this file (optional)")
122
+ .action(async function (markdownPath) {
123
+ const opts = program.opts();
124
+ logger_1.logger.setVerbose(opts.verbose || false);
125
+ const cmdOpts = this.opts();
126
+ const resolvedMd = path.resolve(process.cwd(), markdownPath).replace(/\\/g, "/");
127
+ const cwd = process.cwd().replace(/\\/g, "/");
128
+ const relativeMd = resolvedMd.startsWith(cwd)
129
+ ? path.relative(cwd, resolvedMd).replace(/\\/g, "/")
130
+ : markdownPath;
88
131
  try {
89
- // Ensure the path ends with .docspec.md
90
- if (!filePath.endsWith(".docspec.md")) {
91
- filePath = filePath + ".docspec.md";
132
+ const result = await (0, generate_1.buildDocspecGeneratePrompts)({
133
+ markdownPath: relativeMd,
134
+ overwrite: cmdOpts.overwrite === true,
135
+ outputPromptPath: cmdOpts.outputPrompt || "prompt.txt",
136
+ outputPlanPath: cmdOpts.outputPlan,
137
+ });
138
+ logger_1.logger.success(`Docspec written to ${(0, path_utils_1.markdownToDocspecPath)(relativeMd)}`);
139
+ if (result.outputPromptPath) {
140
+ logger_1.logger.success(`Prompt written to ${result.outputPromptPath}`);
141
+ console.log(result.outputPromptPath);
92
142
  }
93
- await (0, generator_1.generateDocspec)(filePath);
94
- console.log(`✅ Generated docspec file: ${filePath}`);
95
143
  }
96
144
  catch (error) {
97
- console.error(`❌ Failed to generate docspec file: ${error instanceof Error ? error.message : String(error)}`);
145
+ logger_1.logger.error(error instanceof Error ? error.message : String(error));
98
146
  process.exit(1);
99
147
  }
100
148
  });
101
- // Parse command line arguments
102
149
  program.parse();
103
- /**
104
- * Recursively find all *.docspec.md files in a directory
105
- */
106
- async function findDocspecFiles(dir) {
107
- const files = [];
108
- try {
109
- const entries = await fs.readdir(dir, { withFileTypes: true });
110
- for (const entry of entries) {
111
- const fullPath = path.join(dir, entry.name);
112
- // Skip node_modules and .git directories
113
- if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist") {
114
- continue;
115
- }
116
- if (entry.isDirectory()) {
117
- const subFiles = await findDocspecFiles(fullPath);
118
- files.push(...subFiles);
119
- }
120
- else if (entry.isFile() && entry.name.endsWith(".docspec.md")) {
121
- files.push(fullPath);
122
- }
123
- }
124
- }
125
- catch (error) {
126
- // Ignore permission errors
127
- if (error instanceof Error && "code" in error && error.code !== "EACCES") {
128
- throw error;
129
- }
130
- }
131
- return files;
132
- }
133
150
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAAoC;AACpC,gDAAkC;AAClC,2CAA6B;AAC7B,2CAA8C;AAC9C,2CAA8C;AAE9C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,wBAAwB,CAAC;KACrC,QAAQ,CAAC,YAAY,EAAE,wEAAwE,CAAC;KAChG,MAAM,CAAC,KAAK,EAAE,SAAmB,EAAE,EAAE;IACpC,IAAI,eAAe,GAAa,EAAE,CAAC;IAEnC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,oDAAoD;QACpD,eAAe,GAAG,SAAS,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,wDAAwD;QACxD,eAAe,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,IAAA,2BAAe,EAAC,QAAQ,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,SAAS,GAAG,IAAI,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,OAAO,QAAQ,GAAG,CAAC,CAAC;YAClC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,QAAQ,CAAC,QAAQ,EAAE,2EAA2E,CAAC;KAC/F,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;IACjC,IAAI,CAAC;QACH,wCAAwC;QACxC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACtC,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;QACtC,CAAC;QAED,MAAM,IAAA,2BAAe,EAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,6BAA6B,QAAQ,EAAE,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,+BAA+B;AAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;AAEhB;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,GAAW;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAE5C,yCAAyC;YACzC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACpF,SAAS;YACX,CAAC;YAED,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;gBAClD,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;YAC1B,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBAChE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2BAA2B;QAC3B,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * Required section headers for docspec files
3
+ * Lazily loaded on first access to ensure logger is configured
3
4
  */
4
5
  export declare const REQUIRED_SECTIONS: readonly string[];
5
6
  /**
6
7
  * Boilerplate template text for each section
8
+ * Lazily loaded on first access to ensure logger is configured
7
9
  */
8
10
  export declare const SECTION_BOILERPLATE: Record<string, string>;
9
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAwBA;;GAEG;AACH,eAAO,MAAM,iBAAiB,mBAG1B,CAAC;AAEL;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOnD,CAAC;AAEL;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CA0BjE"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAyDA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EA8CxB,SAAS,MAAM,EAAE,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAwBrD,CAAC;AAEH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAmCjE"}
package/dist/constants.js CHANGED
@@ -2,66 +2,169 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SECTION_BOILERPLATE = exports.REQUIRED_SECTIONS = void 0;
4
4
  exports.getDocspecTemplate = getDocspecTemplate;
5
- const format_parser_1 = require("./format-parser");
5
+ const template_1 = require("./template");
6
+ const logger_1 = require("./logger");
6
7
  let cachedFormat = null;
8
+ let cachedRequiredSections = null;
9
+ let cachedSectionBoilerplate = null;
7
10
  /**
8
11
  * Load and cache the format definition
9
12
  */
10
13
  function loadFormat() {
11
14
  if (cachedFormat) {
15
+ logger_1.logger.debug("Using cached format definition");
12
16
  return cachedFormat;
13
17
  }
14
18
  try {
15
- const formatPath = (0, format_parser_1.getFormatFilePath)();
16
- cachedFormat = (0, format_parser_1.parseFormatFile)(formatPath);
19
+ logger_1.logger.debug("Loading format definition");
20
+ const formatPath = (0, template_1.getFormatFilePath)();
21
+ logger_1.logger.debug(`Format file path: ${formatPath}`);
22
+ cachedFormat = (0, template_1.parseFormatFile)(formatPath);
23
+ logger_1.logger.debug(`Format loaded: ${cachedFormat.sections.length} section(s) found`);
17
24
  return cachedFormat;
18
25
  }
19
26
  catch (error) {
27
+ logger_1.logger.debug(`Error loading format: ${error instanceof Error ? error.message : String(error)}`);
20
28
  throw new Error(`Failed to load docspec format file: ${error instanceof Error ? error.message : String(error)}\n` +
21
- `Make sure docspec-format.md exists in the project root.`);
29
+ `The template is at .docspec/docspec.md (it is seeded from the default on first run).`);
22
30
  }
23
31
  }
32
+ /**
33
+ * Get required sections (lazy-loaded)
34
+ */
35
+ function getRequiredSections() {
36
+ if (cachedRequiredSections === null) {
37
+ const format = loadFormat();
38
+ cachedRequiredSections = format.sections.map(s => s.name);
39
+ }
40
+ return cachedRequiredSections;
41
+ }
42
+ /**
43
+ * Get section boilerplate (lazy-loaded)
44
+ */
45
+ function getSectionBoilerplate() {
46
+ if (cachedSectionBoilerplate === null) {
47
+ const format = loadFormat();
48
+ cachedSectionBoilerplate = {};
49
+ for (const section of format.sections) {
50
+ cachedSectionBoilerplate[section.name] = section.boilerplate;
51
+ }
52
+ }
53
+ return cachedSectionBoilerplate;
54
+ }
24
55
  /**
25
56
  * Required section headers for docspec files
57
+ * Lazily loaded on first access to ensure logger is configured
26
58
  */
27
- exports.REQUIRED_SECTIONS = (() => {
28
- const format = loadFormat();
29
- return format.sections.map(s => s.name);
30
- })();
59
+ exports.REQUIRED_SECTIONS = new Proxy([], {
60
+ get(target, prop) {
61
+ const sections = getRequiredSections();
62
+ if (typeof prop === 'string') {
63
+ const index = parseInt(prop, 10);
64
+ if (!isNaN(index)) {
65
+ return sections[index];
66
+ }
67
+ if (prop === 'length') {
68
+ return sections.length;
69
+ }
70
+ if (prop === 'forEach' || prop === 'map' || prop === 'filter' || prop === 'includes' || prop === 'indexOf' || prop === 'slice' || prop === 'join') {
71
+ return sections[prop].bind(sections);
72
+ }
73
+ }
74
+ return sections[prop];
75
+ },
76
+ ownKeys() {
77
+ return Object.keys(getRequiredSections());
78
+ },
79
+ getOwnPropertyDescriptor(target, prop) {
80
+ const sections = getRequiredSections();
81
+ if (typeof prop === 'string') {
82
+ const index = parseInt(prop, 10);
83
+ if (!isNaN(index) && index >= 0 && index < sections.length) {
84
+ return { enumerable: true, configurable: true, value: sections[index] };
85
+ }
86
+ if (prop === 'length') {
87
+ return { enumerable: false, configurable: false, value: sections.length };
88
+ }
89
+ }
90
+ return undefined;
91
+ },
92
+ has(target, prop) {
93
+ const sections = getRequiredSections();
94
+ if (typeof prop === 'string') {
95
+ const index = parseInt(prop, 10);
96
+ if (!isNaN(index) && index >= 0 && index < sections.length) {
97
+ return true;
98
+ }
99
+ if (prop === 'length') {
100
+ return true;
101
+ }
102
+ }
103
+ return prop in sections;
104
+ }
105
+ });
31
106
  /**
32
107
  * Boilerplate template text for each section
108
+ * Lazily loaded on first access to ensure logger is configured
33
109
  */
34
- exports.SECTION_BOILERPLATE = (() => {
35
- const format = loadFormat();
36
- const boilerplate = {};
37
- for (const section of format.sections) {
38
- boilerplate[section.name] = section.boilerplate;
110
+ exports.SECTION_BOILERPLATE = new Proxy({}, {
111
+ get(target, prop) {
112
+ const boilerplate = getSectionBoilerplate();
113
+ return boilerplate[prop];
114
+ },
115
+ set(target, prop, value) {
116
+ const boilerplate = getSectionBoilerplate();
117
+ boilerplate[prop] = value;
118
+ return true;
119
+ },
120
+ ownKeys() {
121
+ return Object.keys(getSectionBoilerplate());
122
+ },
123
+ getOwnPropertyDescriptor(target, prop) {
124
+ const boilerplate = getSectionBoilerplate();
125
+ if (prop in boilerplate) {
126
+ return { enumerable: true, configurable: true, value: boilerplate[prop] };
127
+ }
128
+ return undefined;
129
+ },
130
+ has(target, prop) {
131
+ const boilerplate = getSectionBoilerplate();
132
+ return prop in boilerplate;
39
133
  }
40
- return boilerplate;
41
- })();
134
+ });
42
135
  /**
43
136
  * Generate the full docspec template
44
137
  * @param targetFilePath The path to the target markdown file (e.g., "README.md")
45
138
  */
46
139
  function getDocspecTemplate(targetFilePath) {
140
+ logger_1.logger.debug(`Generating template for target file: ${targetFilePath}`);
47
141
  const format = loadFormat();
48
142
  // Replace {{TARGET_FILE}} in template
49
143
  let template = format.template.replace(/\{\{TARGET_FILE\}\}/g, targetFilePath);
144
+ logger_1.logger.debug("Replaced {{TARGET_FILE}} placeholder in template");
50
145
  // Handle agent instructions if present
51
146
  let agentInstructionsSection = "";
52
147
  if (format.agentInstructions) {
148
+ logger_1.logger.debug("Agent instructions found, including in template");
53
149
  // Replace {{TARGET_FILE}} in agent instructions
54
150
  const agentContent = format.agentInstructions.replace(/\{\{TARGET_FILE\}\}/g, targetFilePath);
55
151
  agentInstructionsSection = `## AGENT INSTRUCTIONS\n\n${agentContent}\n\n`;
56
152
  }
153
+ else {
154
+ logger_1.logger.debug("No agent instructions found");
155
+ }
57
156
  // Replace {{AGENT_INSTRUCTIONS}} placeholder
58
157
  template = template.replace(/\{\{AGENT_INSTRUCTIONS\}\}/g, agentInstructionsSection);
158
+ logger_1.logger.debug("Replaced {{AGENT_INSTRUCTIONS}} placeholder");
59
159
  // Generate sections
160
+ logger_1.logger.debug(`Generating ${format.sections.length} section(s)`);
60
161
  const sections = format.sections.map((section) => {
61
162
  return `## ${section.number}. ${section.name}\n\n${section.boilerplate}`;
62
163
  }).join("\n\n");
63
164
  // Replace {{SECTIONS}} placeholder
64
165
  template = template.replace(/\{\{SECTIONS\}\}/g, sections);
166
+ logger_1.logger.debug("Replaced {{SECTIONS}} placeholder");
167
+ logger_1.logger.debug(`Template generation complete: ${template.length} characters`);
65
168
  return template;
66
169
  }
67
170
  //# sourceMappingURL=constants.js.map