@eldrforge/kodrdriv 0.0.13 → 0.0.15

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 (51) hide show
  1. package/.kodrdriv/context/content.md +7 -1
  2. package/RELEASE_NOTES.md +14 -0
  3. package/dist/arguments.js +332 -9
  4. package/dist/arguments.js.map +1 -1
  5. package/dist/commands/audio-commit.js +666 -0
  6. package/dist/commands/audio-commit.js.map +1 -0
  7. package/dist/commands/audio-review.js +677 -0
  8. package/dist/commands/audio-review.js.map +1 -0
  9. package/dist/commands/clean.js +36 -0
  10. package/dist/commands/clean.js.map +1 -0
  11. package/dist/commands/commit.js +32 -7
  12. package/dist/commands/commit.js.map +1 -1
  13. package/dist/commands/publish.js +15 -7
  14. package/dist/commands/publish.js.map +1 -1
  15. package/dist/commands/release.js +31 -3
  16. package/dist/commands/release.js.map +1 -1
  17. package/dist/commands/review.js +152 -0
  18. package/dist/commands/review.js.map +1 -0
  19. package/dist/constants.js +90 -59
  20. package/dist/constants.js.map +1 -1
  21. package/dist/content/diff.js +155 -1
  22. package/dist/content/diff.js.map +1 -1
  23. package/dist/content/issues.js +240 -0
  24. package/dist/content/issues.js.map +1 -0
  25. package/dist/content/releaseNotes.js +90 -0
  26. package/dist/content/releaseNotes.js.map +1 -0
  27. package/dist/main.js +23 -10
  28. package/dist/main.js.map +1 -1
  29. package/dist/prompt/instructions/commit.md +18 -15
  30. package/dist/prompt/instructions/release.md +6 -5
  31. package/dist/prompt/instructions/review.md +108 -0
  32. package/dist/prompt/personas/reviewer.md +29 -0
  33. package/dist/prompt/prompts.js +110 -13
  34. package/dist/prompt/prompts.js.map +1 -1
  35. package/dist/types.js +36 -1
  36. package/dist/types.js.map +1 -1
  37. package/dist/util/general.js +35 -2
  38. package/dist/util/general.js.map +1 -1
  39. package/dist/util/github.js +54 -1
  40. package/dist/util/github.js.map +1 -1
  41. package/dist/util/openai.js +68 -4
  42. package/dist/util/openai.js.map +1 -1
  43. package/dist/util/stdin.js +61 -0
  44. package/dist/util/stdin.js.map +1 -0
  45. package/dist/util/storage.js +20 -1
  46. package/dist/util/storage.js.map +1 -1
  47. package/docs/public/commands.md +20 -0
  48. package/output/kodrdriv/250702-0552-release-notes.md +3 -0
  49. package/package.json +7 -6
  50. package/pnpm-workspace.yaml +2 -0
  51. package/vitest.config.ts +4 -4
@@ -1 +1,7 @@
1
- KodrDriv is a tool that is designed to help automate the creation of commit messages and release notes. It is also a tool that has been designed to support an opinionated approach to organizing related projects and conducting structured releases with Git. This initial version focuses on pnpm and GitHub, but there are plans to expand coverage over time.
1
+ KodrDriv is a tool that is designed to help automate the creation of commit messages and release notes. It is also a tool that has been designed to support an opinionated approach to organizing related projects and conducting structured releases with Git. This initial version focuses on pnpm and GitHub, but there are plans to expand coverage over time.
2
+
3
+ KodrDriv is available as an module on npmjs.org under @eldrforge/kodrdriv
4
+
5
+ The name sometimes sounds like "Coder Driv" or "Coder Riv" but that should be corrected to "KodrDriv"
6
+
7
+ Same with the name of the scope "Elder Forge" or "Elderforth" should be corrected to "Edlrforge"
@@ -0,0 +1,14 @@
1
+ This release updates workspace management and CI deployment for projects using pnpm with an opinionated structure. The changes restore explicit workspace scoping and local package link overrides, improving multi-package development while streamlining documentation deployment.
2
+
3
+ **Improvements**
4
+
5
+ * Restored exclusions for the `docs` directory and local dependency overrides in `pnpm-workspace.yaml` to clarify project boundaries and enable local development workflows for core packages.
6
+ * Simplified the `deploy-docs.yml` workflow by removing temporary renaming of the workspace file; documentation builds and deployments now work directly with the refined workspace configuration.
7
+
8
+ **Why these changes matter:**
9
+
10
+ * Empower clearer separation between core packages and documentation in the monorepo setup.
11
+ * Align local development processes and CI deployment behavior.
12
+ * Reduce special-casing and ad-hoc workarounds in documentation workflows.
13
+
14
+ _No breaking changes or new features are introduced for end users._
package/dist/arguments.js CHANGED
@@ -3,6 +3,7 @@ import { z } from 'zod';
3
3
  import { PROGRAM_NAME, VERSION, KODRDRIV_DEFAULTS, ALLOWED_COMMANDS, DEFAULT_COMMAND, DEFAULT_CHARACTER_ENCODING, DEFAULT_INSTRUCTIONS_DIR } from './constants.js';
4
4
  import { getLogger } from './logging.js';
5
5
  import { create } from './util/storage.js';
6
+ import { readStdin } from './util/stdin.js';
6
7
 
7
8
  z.object({
8
9
  dryRun: z.boolean().optional(),
@@ -16,6 +17,7 @@ z.object({
16
17
  contextDirectories: z.array(z.string()).optional(),
17
18
  instructions: z.string().optional(),
18
19
  configDir: z.string().optional(),
20
+ outputDir: z.string().optional(),
19
21
  cached: z.boolean().optional(),
20
22
  add: z.boolean().optional(),
21
23
  sendit: z.boolean().optional(),
@@ -23,6 +25,8 @@ z.object({
23
25
  to: z.string().optional(),
24
26
  excludedPatterns: z.array(z.string()).optional(),
25
27
  context: z.string().optional(),
28
+ note: z.string().optional(),
29
+ direction: z.string().optional(),
26
30
  messageLimit: z.number().optional(),
27
31
  mergeMethod: z.enum([
28
32
  'merge',
@@ -30,7 +34,16 @@ z.object({
30
34
  'rebase'
31
35
  ]).optional(),
32
36
  scopeRoots: z.string().optional(),
33
- workspaceFile: z.string().optional()
37
+ workspaceFile: z.string().optional(),
38
+ includeCommitHistory: z.boolean().optional(),
39
+ includeRecentDiffs: z.boolean().optional(),
40
+ includeReleaseNotes: z.boolean().optional(),
41
+ includeGithubIssues: z.boolean().optional(),
42
+ commitHistoryLimit: z.number().optional(),
43
+ diffHistoryLimit: z.number().optional(),
44
+ releaseNotesLimit: z.number().optional(),
45
+ githubIssuesLimit: z.number().optional(),
46
+ selectAudioDevice: z.boolean().optional()
34
47
  });
35
48
  // Function to transform flat CLI args into nested Config structure
36
49
  const transformCliArgs = (finalCliArgs)=>{
@@ -45,6 +58,8 @@ const transformCliArgs = (finalCliArgs)=>{
45
58
  if (finalCliArgs.instructions !== undefined) transformedCliArgs.instructions = finalCliArgs.instructions;
46
59
  // Map configDir (CLI) to configDirectory (Cardigantime standard)
47
60
  if (finalCliArgs.configDir !== undefined) transformedCliArgs.configDirectory = finalCliArgs.configDir;
61
+ // Map outputDir (CLI) to outputDirectory (Config standard)
62
+ if (finalCliArgs.outputDir !== undefined) transformedCliArgs.outputDirectory = finalCliArgs.outputDir;
48
63
  // Nested mappings for 'commit' options
49
64
  if (finalCliArgs.cached !== undefined || finalCliArgs.sendit !== undefined || finalCliArgs.add !== undefined) {
50
65
  transformedCliArgs.commit = {};
@@ -53,6 +68,12 @@ const transformCliArgs = (finalCliArgs)=>{
53
68
  if (finalCliArgs.sendit !== undefined) transformedCliArgs.commit.sendit = finalCliArgs.sendit;
54
69
  if (finalCliArgs.messageLimit !== undefined) transformedCliArgs.commit.messageLimit = finalCliArgs.messageLimit;
55
70
  if (finalCliArgs.context !== undefined) transformedCliArgs.commit.context = finalCliArgs.context;
71
+ if (finalCliArgs.direction !== undefined) transformedCliArgs.commit.direction = finalCliArgs.direction;
72
+ }
73
+ // Nested mappings for 'audioCommit' options
74
+ if (finalCliArgs.selectAudioDevice !== undefined) {
75
+ transformedCliArgs.audioCommit = {};
76
+ transformedCliArgs.audioCommit.selectAudioDevice = finalCliArgs.selectAudioDevice;
56
77
  }
57
78
  // Nested mappings for 'release' options
58
79
  if (finalCliArgs.from !== undefined || finalCliArgs.to !== undefined) {
@@ -73,13 +94,43 @@ const transformCliArgs = (finalCliArgs)=>{
73
94
  if (finalCliArgs.scopeRoots !== undefined) {
74
95
  try {
75
96
  transformedCliArgs.link.scopeRoots = JSON.parse(finalCliArgs.scopeRoots);
76
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
77
97
  } catch (error) {
78
98
  throw new Error(`Invalid JSON for scope-roots: ${finalCliArgs.scopeRoots}`);
79
99
  }
80
100
  }
81
101
  if (finalCliArgs.workspaceFile !== undefined) transformedCliArgs.link.workspaceFile = finalCliArgs.workspaceFile;
82
102
  }
103
+ // Nested mappings for 'audio-review' options
104
+ if (finalCliArgs.includeCommitHistory !== undefined || finalCliArgs.includeRecentDiffs !== undefined || finalCliArgs.includeReleaseNotes !== undefined || finalCliArgs.includeGithubIssues !== undefined || finalCliArgs.commitHistoryLimit !== undefined || finalCliArgs.diffHistoryLimit !== undefined || finalCliArgs.releaseNotesLimit !== undefined || finalCliArgs.githubIssuesLimit !== undefined) {
105
+ transformedCliArgs.audioReview = {};
106
+ if (finalCliArgs.includeCommitHistory !== undefined) transformedCliArgs.audioReview.includeCommitHistory = finalCliArgs.includeCommitHistory;
107
+ if (finalCliArgs.includeRecentDiffs !== undefined) transformedCliArgs.audioReview.includeRecentDiffs = finalCliArgs.includeRecentDiffs;
108
+ if (finalCliArgs.includeReleaseNotes !== undefined) transformedCliArgs.audioReview.includeReleaseNotes = finalCliArgs.includeReleaseNotes;
109
+ if (finalCliArgs.includeGithubIssues !== undefined) transformedCliArgs.audioReview.includeGithubIssues = finalCliArgs.includeGithubIssues;
110
+ if (finalCliArgs.commitHistoryLimit !== undefined) transformedCliArgs.audioReview.commitHistoryLimit = finalCliArgs.commitHistoryLimit;
111
+ if (finalCliArgs.diffHistoryLimit !== undefined) transformedCliArgs.audioReview.diffHistoryLimit = finalCliArgs.diffHistoryLimit;
112
+ if (finalCliArgs.releaseNotesLimit !== undefined) transformedCliArgs.audioReview.releaseNotesLimit = finalCliArgs.releaseNotesLimit;
113
+ if (finalCliArgs.githubIssuesLimit !== undefined) transformedCliArgs.audioReview.githubIssuesLimit = finalCliArgs.githubIssuesLimit;
114
+ // Only add context and sendit if we already have an audioReview object from the specific properties above
115
+ if (finalCliArgs.context !== undefined) transformedCliArgs.audioReview.context = finalCliArgs.context;
116
+ if (finalCliArgs.sendit !== undefined) transformedCliArgs.audioReview.sendit = finalCliArgs.sendit;
117
+ }
118
+ // Nested mappings for 'review' options
119
+ if (finalCliArgs.includeCommitHistory !== undefined || finalCliArgs.includeRecentDiffs !== undefined || finalCliArgs.includeReleaseNotes !== undefined || finalCliArgs.includeGithubIssues !== undefined || finalCliArgs.commitHistoryLimit !== undefined || finalCliArgs.diffHistoryLimit !== undefined || finalCliArgs.releaseNotesLimit !== undefined || finalCliArgs.githubIssuesLimit !== undefined || finalCliArgs.context !== undefined || finalCliArgs.sendit !== undefined || finalCliArgs.note !== undefined) {
120
+ transformedCliArgs.review = {};
121
+ if (finalCliArgs.note !== undefined) transformedCliArgs.review.note = finalCliArgs.note;
122
+ // Include optional review configuration options if specified
123
+ if (finalCliArgs.includeCommitHistory !== undefined) transformedCliArgs.review.includeCommitHistory = finalCliArgs.includeCommitHistory;
124
+ if (finalCliArgs.includeRecentDiffs !== undefined) transformedCliArgs.review.includeRecentDiffs = finalCliArgs.includeRecentDiffs;
125
+ if (finalCliArgs.includeReleaseNotes !== undefined) transformedCliArgs.review.includeReleaseNotes = finalCliArgs.includeReleaseNotes;
126
+ if (finalCliArgs.includeGithubIssues !== undefined) transformedCliArgs.review.includeGithubIssues = finalCliArgs.includeGithubIssues;
127
+ if (finalCliArgs.commitHistoryLimit !== undefined) transformedCliArgs.review.commitHistoryLimit = finalCliArgs.commitHistoryLimit;
128
+ if (finalCliArgs.diffHistoryLimit !== undefined) transformedCliArgs.review.diffHistoryLimit = finalCliArgs.diffHistoryLimit;
129
+ if (finalCliArgs.releaseNotesLimit !== undefined) transformedCliArgs.review.releaseNotesLimit = finalCliArgs.releaseNotesLimit;
130
+ if (finalCliArgs.githubIssuesLimit !== undefined) transformedCliArgs.review.githubIssuesLimit = finalCliArgs.githubIssuesLimit;
131
+ if (finalCliArgs.context !== undefined) transformedCliArgs.review.context = finalCliArgs.context;
132
+ if (finalCliArgs.sendit !== undefined) transformedCliArgs.review.sendit = finalCliArgs.sendit;
133
+ }
83
134
  if (finalCliArgs.excludedPatterns !== undefined) transformedCliArgs.excludedPatterns = finalCliArgs.excludedPatterns;
84
135
  // Note: finalCliArgs.openaiApiKey is intentionally omitted here as it belongs to SecureConfig
85
136
  return transformedCliArgs;
@@ -137,7 +188,7 @@ const configure = async (cardigantime)=>{
137
188
  ];
138
189
  }
139
190
  // Get CLI arguments using the new function
140
- const [finalCliArgs, commandConfig] = getCliConfig(program);
191
+ const [finalCliArgs, commandConfig] = await getCliConfig(program);
141
192
  logger.silly('Loaded Command Line Options: %s', JSON.stringify(finalCliArgs, null, 2));
142
193
  // Transform the flat CLI args using the new function
143
194
  const transformedCliArgs = transformCliArgs(finalCliArgs);
@@ -167,6 +218,7 @@ const configure = async (cardigantime)=>{
167
218
  logger.verbose(` Debug: ${config.debug}`);
168
219
  logger.verbose(` Verbose: ${config.verbose}`);
169
220
  logger.verbose(` Config directory: ${config.configDirectory}`);
221
+ logger.verbose(` Output directory: ${config.outputDirectory}`);
170
222
  logger.verbose(` Context directories: ${((_config_contextDirectories = config.contextDirectories) === null || _config_contextDirectories === void 0 ? void 0 : _config_contextDirectories.join(', ')) || 'none'}`);
171
223
  if (config.excludedPatterns && config.excludedPatterns.length > 0) {
172
224
  logger.verbose(` Excluded patterns: ${config.excludedPatterns.join(', ')}`);
@@ -183,17 +235,97 @@ const configure = async (cardigantime)=>{
183
235
  ];
184
236
  };
185
237
  // Function to handle CLI argument parsing and processing
186
- function getCliConfig(program) {
238
+ async function getCliConfig(program) {
187
239
  const addSharedOptions = (command)=>{
188
240
  command.option('--dry-run', 'perform a dry run without saving files') // Removed default, will be handled by merging
189
241
  .option('--verbose', 'enable verbose logging').option('--debug', 'enable debug logging').option('--overrides', 'enable overrides').option('--model <model>', 'OpenAI model to use').option('-d, --context-directories [contextDirectories...]', 'directories to scan for context').option('-i, --instructions <file>', 'instructions for the AI').option('--config-dir <configDir>', 'configuration directory') // Keep config-dir for specifying location
190
- .option('--excluded-paths [excludedPatterns...]', 'paths to exclude from the diff');
242
+ .option('--output-dir <outputDir>', 'output directory for generated files').option('--excluded-paths [excludedPatterns...]', 'paths to exclude from the diff');
191
243
  };
192
244
  // Add global options to the main program
193
245
  // (cardigantime already adds most global options like --verbose, --debug, --config-dir)
194
246
  // Add subcommands
195
- const commitCommand = program.command('commit').option('--cached', 'use cached diff').option('--add', 'add all changes before committing').option('--sendit', 'Commit with the message generated. No review.').option('--context <context>', 'context for the commit message').option('--message-limit <messageLimit>', 'limit the number of messages to generate').description('Generate commit notes');
247
+ const commitCommand = program.command('commit').argument('[direction]', 'direction or guidance for the commit message').description('Generate commit notes').option('--context <context>', 'context for the commit message').option('--cached', 'use cached diff').option('--add', 'add all changes before committing').option('--sendit', 'Commit with the message generated. No review.').option('--message-limit <messageLimit>', 'limit the number of messages to generate');
248
+ // Add shared options to commit command
196
249
  addSharedOptions(commitCommand);
250
+ // Customize help output for commit command
251
+ commitCommand.configureHelp({
252
+ formatHelp: (cmd, helper)=>{
253
+ const nameAndVersion = `${helper.commandUsage(cmd)}\n\n${helper.commandDescription(cmd)}\n`;
254
+ const commitOptions = [
255
+ [
256
+ '--context <context>',
257
+ 'context for the commit message'
258
+ ]
259
+ ];
260
+ const behavioralOptions = [
261
+ [
262
+ '--cached',
263
+ 'use cached diff'
264
+ ],
265
+ [
266
+ '--add',
267
+ 'add all changes before committing'
268
+ ],
269
+ [
270
+ '--sendit',
271
+ 'Commit with the message generated. No review.'
272
+ ],
273
+ [
274
+ '--message-limit <messageLimit>',
275
+ 'limit the number of messages to generate'
276
+ ]
277
+ ];
278
+ const globalOptions = [
279
+ [
280
+ '--dry-run',
281
+ 'perform a dry run without saving files'
282
+ ],
283
+ [
284
+ '--verbose',
285
+ 'enable verbose logging'
286
+ ],
287
+ [
288
+ '--debug',
289
+ 'enable debug logging'
290
+ ],
291
+ [
292
+ '--overrides',
293
+ 'enable overrides'
294
+ ],
295
+ [
296
+ '--model <model>',
297
+ 'OpenAI model to use'
298
+ ],
299
+ [
300
+ '-d, --context-directories [contextDirectories...]',
301
+ 'directories to scan for context'
302
+ ],
303
+ [
304
+ '-i, --instructions <file>',
305
+ 'instructions for the AI'
306
+ ],
307
+ [
308
+ '--config-dir <configDir>',
309
+ 'configuration directory'
310
+ ],
311
+ [
312
+ '--excluded-paths [excludedPatterns...]',
313
+ 'paths to exclude from the diff'
314
+ ],
315
+ [
316
+ '-h, --help',
317
+ 'display help for command'
318
+ ]
319
+ ];
320
+ const formatOptionsSection = (title, options)=>{
321
+ const maxWidth = Math.max(...options.map(([flag])=>flag.length));
322
+ return `${title}:\n` + options.map(([flag, desc])=>` ${flag.padEnd(maxWidth + 2)} ${desc}`).join('\n') + '\n';
323
+ };
324
+ return nameAndVersion + '\n' + formatOptionsSection('Commit Message Options', commitOptions) + '\n' + formatOptionsSection('Behavioral Options', behavioralOptions) + '\n' + formatOptionsSection('Global Options', globalOptions);
325
+ }
326
+ });
327
+ const audioCommitCommand = program.command('audio-commit').option('--cached', 'use cached diff').option('--add', 'add all changes before committing').option('--sendit', 'Commit with the message generated. No review.').option('--direction <direction>', 'direction or guidance for the commit message').option('--message-limit <messageLimit>', 'limit the number of messages to generate').option('--select-audio-device', 'interactively select audio device and save to configuration').description('Record audio to provide context, then generate and optionally commit with AI-generated message');
328
+ addSharedOptions(audioCommitCommand);
197
329
  const releaseCommand = program.command('release').option('--from <from>', 'branch to generate release notes from').option('--to <to>', 'branch to generate release notes to').option('--context <context>', 'context for the commit message').description('Generate release notes');
198
330
  addSharedOptions(releaseCommand);
199
331
  const publishCommand = program.command('publish').option('--merge-method <method>', 'method to merge PR (merge, squash, rebase)', 'squash').description('Publish a release');
@@ -202,6 +334,137 @@ function getCliConfig(program) {
202
334
  addSharedOptions(linkCommand);
203
335
  const unlinkCommand = program.command('unlink').option('--scope-roots <scopeRoots>', 'JSON mapping of scopes to root directories (e.g., \'{"@company": "../"}\')').option('--workspace-file <workspaceFile>', 'path to workspace file', 'pnpm-workspace.yaml').description('Remove pnpm workspace links and rebuild dependencies');
204
336
  addSharedOptions(unlinkCommand);
337
+ const audioReviewCommand = program.command('audio-review').option('--include-commit-history', 'include recent commit log messages in context (default: true)').option('--no-include-commit-history', 'exclude commit log messages from context').option('--include-recent-diffs', 'include recent commit diffs in context (default: true)').option('--no-include-recent-diffs', 'exclude recent diffs from context').option('--include-release-notes', 'include recent release notes in context (default: false)').option('--no-include-release-notes', 'exclude release notes from context').option('--include-github-issues', 'include open GitHub issues in context (default: true)').option('--no-include-github-issues', 'exclude GitHub issues from context').option('--commit-history-limit <limit>', 'number of recent commits to include', parseInt).option('--diff-history-limit <limit>', 'number of recent commit diffs to include', parseInt).option('--release-notes-limit <limit>', 'number of recent release notes to include', parseInt).option('--github-issues-limit <limit>', 'number of open GitHub issues to include (max 20)', parseInt).option('--context <context>', 'additional context for the audio review').option('--sendit', 'Create GitHub issues automatically without confirmation').description('Record audio, transcribe with Whisper, and analyze for project issues using AI');
338
+ addSharedOptions(audioReviewCommand);
339
+ const reviewCommand = program.command('review').argument('[note]', 'review note to analyze for project issues').option('--include-commit-history', 'include recent commit log messages in context (default: true)').option('--no-include-commit-history', 'exclude commit log messages from context').option('--include-recent-diffs', 'include recent commit diffs in context (default: true)').option('--no-include-recent-diffs', 'exclude recent diffs from context').option('--include-release-notes', 'include recent release notes in context (default: false)').option('--no-include-release-notes', 'exclude release notes from context').option('--include-github-issues', 'include open GitHub issues in context (default: true)').option('--no-include-github-issues', 'exclude GitHub issues from context').option('--commit-history-limit <limit>', 'number of recent commits to include', parseInt).option('--diff-history-limit <limit>', 'number of recent commit diffs to include', parseInt).option('--release-notes-limit <limit>', 'number of recent release notes to include', parseInt).option('--github-issues-limit <limit>', 'number of open GitHub issues to include (max 20)', parseInt).option('--context <context>', 'additional context for the review').option('--sendit', 'Create GitHub issues automatically without confirmation').description('Analyze review note for project issues using AI');
340
+ addSharedOptions(reviewCommand);
341
+ // Customize help output for review command
342
+ reviewCommand.configureHelp({
343
+ formatHelp: (cmd, helper)=>{
344
+ const nameAndVersion = `kodrdriv review [note] [options]\n\nAnalyze review note for project issues using AI\n`;
345
+ const argumentsSection = [
346
+ [
347
+ 'note',
348
+ 'review note to analyze for project issues (can also be piped via STDIN)'
349
+ ]
350
+ ];
351
+ const reviewOptions = [
352
+ [
353
+ '--context <context>',
354
+ 'additional context for the review'
355
+ ]
356
+ ];
357
+ const gitContextOptions = [
358
+ [
359
+ '--include-commit-history',
360
+ 'include recent commit log messages in context (default: true)'
361
+ ],
362
+ [
363
+ '--no-include-commit-history',
364
+ 'exclude commit log messages from context'
365
+ ],
366
+ [
367
+ '--include-recent-diffs',
368
+ 'include recent commit diffs in context (default: true)'
369
+ ],
370
+ [
371
+ '--no-include-recent-diffs',
372
+ 'exclude recent diffs from context'
373
+ ],
374
+ [
375
+ '--include-release-notes',
376
+ 'include recent release notes in context (default: false)'
377
+ ],
378
+ [
379
+ '--no-include-release-notes',
380
+ 'exclude release notes from context'
381
+ ],
382
+ [
383
+ '--include-github-issues',
384
+ 'include open GitHub issues in context (default: true)'
385
+ ],
386
+ [
387
+ '--no-include-github-issues',
388
+ 'exclude GitHub issues from context'
389
+ ],
390
+ [
391
+ '--commit-history-limit <limit>',
392
+ 'number of recent commits to include'
393
+ ],
394
+ [
395
+ '--diff-history-limit <limit>',
396
+ 'number of recent commit diffs to include'
397
+ ],
398
+ [
399
+ '--release-notes-limit <limit>',
400
+ 'number of recent release notes to include'
401
+ ],
402
+ [
403
+ '--github-issues-limit <limit>',
404
+ 'number of open GitHub issues to include (max 20)'
405
+ ]
406
+ ];
407
+ const behavioralOptions = [
408
+ [
409
+ '--sendit',
410
+ 'Create GitHub issues automatically without confirmation'
411
+ ]
412
+ ];
413
+ const globalOptions = [
414
+ [
415
+ '--dry-run',
416
+ 'perform a dry run without saving files'
417
+ ],
418
+ [
419
+ '--verbose',
420
+ 'enable verbose logging'
421
+ ],
422
+ [
423
+ '--debug',
424
+ 'enable debug logging'
425
+ ],
426
+ [
427
+ '--overrides',
428
+ 'enable overrides'
429
+ ],
430
+ [
431
+ '--model <model>',
432
+ 'OpenAI model to use'
433
+ ],
434
+ [
435
+ '-d, --context-directories [contextDirectories...]',
436
+ 'directories to scan for context'
437
+ ],
438
+ [
439
+ '-i, --instructions <file>',
440
+ 'instructions for the AI'
441
+ ],
442
+ [
443
+ '--config-dir <configDir>',
444
+ 'configuration directory'
445
+ ],
446
+ [
447
+ '--output-dir <outputDir>',
448
+ 'output directory for generated files'
449
+ ],
450
+ [
451
+ '--excluded-paths [excludedPatterns...]',
452
+ 'paths to exclude from the diff'
453
+ ],
454
+ [
455
+ '-h, --help',
456
+ 'display help for command'
457
+ ]
458
+ ];
459
+ const formatOptionsSection = (title, options)=>{
460
+ const maxWidth = Math.max(...options.map(([flag])=>flag.length));
461
+ return `${title}:\n` + options.map(([flag, desc])=>` ${flag.padEnd(maxWidth + 2)} ${desc}`).join('\n') + '\n';
462
+ };
463
+ return nameAndVersion + '\n' + formatOptionsSection('Arguments', argumentsSection) + '\n' + formatOptionsSection('Options', reviewOptions) + '\n' + formatOptionsSection('Git Context Parameters', gitContextOptions) + '\n' + formatOptionsSection('Behavioral Options', behavioralOptions) + '\n' + formatOptionsSection('Global Options', globalOptions);
464
+ }
465
+ });
466
+ const cleanCommand = program.command('clean').description('Remove the output directory and all generated files');
467
+ addSharedOptions(cleanCommand);
205
468
  program.parse();
206
469
  const cliArgs = program.opts(); // Get all opts initially
207
470
  // Determine which command is being run
@@ -215,6 +478,18 @@ function getCliConfig(program) {
215
478
  if (ALLOWED_COMMANDS.includes(commandName)) {
216
479
  if (commandName === 'commit' && commitCommand.opts) {
217
480
  commandOptions = commitCommand.opts();
481
+ // Handle positional argument for direction
482
+ const args = commitCommand.args;
483
+ if (args && args.length > 0 && args[0]) {
484
+ commandOptions.direction = args[0];
485
+ }
486
+ // Check for STDIN input for direction (takes precedence over positional argument)
487
+ const stdinInput = await readStdin();
488
+ if (stdinInput) {
489
+ commandOptions.direction = stdinInput;
490
+ }
491
+ } else if (commandName === 'audio-commit' && audioCommitCommand.opts) {
492
+ commandOptions = audioCommitCommand.opts();
218
493
  } else if (commandName === 'release' && releaseCommand.opts) {
219
494
  commandOptions = releaseCommand.opts();
220
495
  } else if (commandName === 'publish' && publishCommand.opts) {
@@ -223,6 +498,22 @@ function getCliConfig(program) {
223
498
  commandOptions = linkCommand.opts();
224
499
  } else if (commandName === 'unlink' && unlinkCommand.opts) {
225
500
  commandOptions = unlinkCommand.opts();
501
+ } else if (commandName === 'audio-review' && audioReviewCommand.opts) {
502
+ commandOptions = audioReviewCommand.opts();
503
+ } else if (commandName === 'review' && reviewCommand.opts) {
504
+ commandOptions = reviewCommand.opts();
505
+ // Handle positional argument for note
506
+ const args = reviewCommand.args;
507
+ if (args && args.length > 0 && args[0]) {
508
+ commandOptions.note = args[0];
509
+ }
510
+ // Check for STDIN input for note (takes precedence over positional argument)
511
+ const stdinInput = await readStdin();
512
+ if (stdinInput) {
513
+ commandOptions.note = stdinInput;
514
+ }
515
+ } else if (commandName === 'clean' && cleanCommand.opts) {
516
+ commandOptions = cleanCommand.opts();
226
517
  }
227
518
  }
228
519
  // Include command name in CLI args for merging
@@ -254,12 +545,12 @@ async function validateAndProcessSecureOptions() {
254
545
  }
255
546
  // Renamed validation function to reflect its broader role
256
547
  async function validateAndProcessOptions(options) {
257
- var _options_commit, _options_commit1, _options_commit2, _options_commit3, _options_commit4, _options_release, _options_release1, _options_release2, _options_release3, _options_publish, _options_publish1, _options_publish2, _options_link, _options_link1, _options_link2;
548
+ var _options_commit, _options_commit1, _options_commit2, _options_commit3, _options_commit4, _options_commit5, _options_audioCommit, _options_audioCommit1, _options_audioCommit2, _options_release, _options_release1, _options_release2, _options_release3, _options_audioReview, _options_audioReview1, _options_audioReview2, _options_audioReview3, _options_audioReview4, _options_audioReview5, _options_audioReview6, _options_audioReview7, _options_audioReview8, _options_audioReview9, _options_review, _options_review1, _options_review2, _options_review3, _options_review4, _options_review5, _options_review6, _options_review7, _options_review8, _options_review9, _options_review10, _options_publish, _options_publish1, _options_publish2, _options_link, _options_link1, _options_link2;
258
549
  const contextDirectories = await validateContextDirectories(options.contextDirectories || KODRDRIV_DEFAULTS.contextDirectories);
259
550
  const instructionsPathOrContent = options.instructions || KODRDRIV_DEFAULTS.instructions;
260
551
  const instructions = await validateAndReadInstructions(instructionsPathOrContent);
261
552
  const configDir = options.configDirectory || KODRDRIV_DEFAULTS.configDirectory;
262
- var _options_dryRun, _options_verbose, _options_debug, _options_overrides, _options_model, _options_commit_add, _options_commit_cached, _options_commit_sendit, _options_commit_messageLimit, _options_release_from, _options_release_to, _options_release_messageLimit, _options_publish_mergeMethod, _options_publish_requiredEnvVars, _options_link_scopeRoots, _options_link_workspaceFile, _options_link_dryRun, _options_excludedPatterns;
553
+ var _options_dryRun, _options_verbose, _options_debug, _options_overrides, _options_model, _options_outputDirectory, _options_commit_add, _options_commit_cached, _options_commit_sendit, _options_commit_messageLimit, _options_audioCommit_maxRecordingTime, _options_audioCommit_audioDevice, _options_release_from, _options_release_to, _options_release_messageLimit, _options_audioReview_includeCommitHistory, _options_audioReview_includeRecentDiffs, _options_audioReview_includeReleaseNotes, _options_audioReview_includeGithubIssues, _options_audioReview_commitHistoryLimit, _options_audioReview_diffHistoryLimit, _options_audioReview_releaseNotesLimit, _options_audioReview_githubIssuesLimit, _options_audioReview_sendit, _options_review_includeCommitHistory, _options_review_includeRecentDiffs, _options_review_includeReleaseNotes, _options_review_includeGithubIssues, _options_review_commitHistoryLimit, _options_review_diffHistoryLimit, _options_review_releaseNotesLimit, _options_review_githubIssuesLimit, _options_review_sendit, _options_publish_mergeMethod, _options_publish_requiredEnvVars, _options_link_scopeRoots, _options_link_workspaceFile, _options_link_dryRun, _options_excludedPatterns;
263
554
  // Skip config directory validation since Cardigantime handles hierarchical lookup
264
555
  // Ensure all required fields are present and have correct types after merging
265
556
  const finalConfig = {
@@ -271,13 +562,20 @@ async function validateAndProcessOptions(options) {
271
562
  instructions: instructions,
272
563
  contextDirectories: contextDirectories,
273
564
  configDirectory: configDir,
565
+ outputDirectory: (_options_outputDirectory = options.outputDirectory) !== null && _options_outputDirectory !== void 0 ? _options_outputDirectory : KODRDRIV_DEFAULTS.outputDirectory,
274
566
  // Command-specific options with defaults
275
567
  commit: {
276
568
  add: (_options_commit_add = (_options_commit = options.commit) === null || _options_commit === void 0 ? void 0 : _options_commit.add) !== null && _options_commit_add !== void 0 ? _options_commit_add : KODRDRIV_DEFAULTS.commit.add,
277
569
  cached: (_options_commit_cached = (_options_commit1 = options.commit) === null || _options_commit1 === void 0 ? void 0 : _options_commit1.cached) !== null && _options_commit_cached !== void 0 ? _options_commit_cached : KODRDRIV_DEFAULTS.commit.cached,
278
570
  sendit: (_options_commit_sendit = (_options_commit2 = options.commit) === null || _options_commit2 === void 0 ? void 0 : _options_commit2.sendit) !== null && _options_commit_sendit !== void 0 ? _options_commit_sendit : KODRDRIV_DEFAULTS.commit.sendit,
279
571
  messageLimit: (_options_commit_messageLimit = (_options_commit3 = options.commit) === null || _options_commit3 === void 0 ? void 0 : _options_commit3.messageLimit) !== null && _options_commit_messageLimit !== void 0 ? _options_commit_messageLimit : KODRDRIV_DEFAULTS.commit.messageLimit,
280
- context: (_options_commit4 = options.commit) === null || _options_commit4 === void 0 ? void 0 : _options_commit4.context
572
+ context: (_options_commit4 = options.commit) === null || _options_commit4 === void 0 ? void 0 : _options_commit4.context,
573
+ direction: (_options_commit5 = options.commit) === null || _options_commit5 === void 0 ? void 0 : _options_commit5.direction
574
+ },
575
+ audioCommit: {
576
+ maxRecordingTime: (_options_audioCommit_maxRecordingTime = (_options_audioCommit = options.audioCommit) === null || _options_audioCommit === void 0 ? void 0 : _options_audioCommit.maxRecordingTime) !== null && _options_audioCommit_maxRecordingTime !== void 0 ? _options_audioCommit_maxRecordingTime : KODRDRIV_DEFAULTS.audioCommit.maxRecordingTime,
577
+ audioDevice: (_options_audioCommit_audioDevice = (_options_audioCommit1 = options.audioCommit) === null || _options_audioCommit1 === void 0 ? void 0 : _options_audioCommit1.audioDevice) !== null && _options_audioCommit_audioDevice !== void 0 ? _options_audioCommit_audioDevice : KODRDRIV_DEFAULTS.audioCommit.audioDevice,
578
+ selectAudioDevice: (_options_audioCommit2 = options.audioCommit) === null || _options_audioCommit2 === void 0 ? void 0 : _options_audioCommit2.selectAudioDevice
281
579
  },
282
580
  release: {
283
581
  from: (_options_release_from = (_options_release = options.release) === null || _options_release === void 0 ? void 0 : _options_release.from) !== null && _options_release_from !== void 0 ? _options_release_from : KODRDRIV_DEFAULTS.release.from,
@@ -285,6 +583,31 @@ async function validateAndProcessOptions(options) {
285
583
  messageLimit: (_options_release_messageLimit = (_options_release2 = options.release) === null || _options_release2 === void 0 ? void 0 : _options_release2.messageLimit) !== null && _options_release_messageLimit !== void 0 ? _options_release_messageLimit : KODRDRIV_DEFAULTS.release.messageLimit,
286
584
  context: (_options_release3 = options.release) === null || _options_release3 === void 0 ? void 0 : _options_release3.context
287
585
  },
586
+ audioReview: {
587
+ includeCommitHistory: (_options_audioReview_includeCommitHistory = (_options_audioReview = options.audioReview) === null || _options_audioReview === void 0 ? void 0 : _options_audioReview.includeCommitHistory) !== null && _options_audioReview_includeCommitHistory !== void 0 ? _options_audioReview_includeCommitHistory : KODRDRIV_DEFAULTS.audioReview.includeCommitHistory,
588
+ includeRecentDiffs: (_options_audioReview_includeRecentDiffs = (_options_audioReview1 = options.audioReview) === null || _options_audioReview1 === void 0 ? void 0 : _options_audioReview1.includeRecentDiffs) !== null && _options_audioReview_includeRecentDiffs !== void 0 ? _options_audioReview_includeRecentDiffs : KODRDRIV_DEFAULTS.audioReview.includeRecentDiffs,
589
+ includeReleaseNotes: (_options_audioReview_includeReleaseNotes = (_options_audioReview2 = options.audioReview) === null || _options_audioReview2 === void 0 ? void 0 : _options_audioReview2.includeReleaseNotes) !== null && _options_audioReview_includeReleaseNotes !== void 0 ? _options_audioReview_includeReleaseNotes : KODRDRIV_DEFAULTS.audioReview.includeReleaseNotes,
590
+ includeGithubIssues: (_options_audioReview_includeGithubIssues = (_options_audioReview3 = options.audioReview) === null || _options_audioReview3 === void 0 ? void 0 : _options_audioReview3.includeGithubIssues) !== null && _options_audioReview_includeGithubIssues !== void 0 ? _options_audioReview_includeGithubIssues : KODRDRIV_DEFAULTS.audioReview.includeGithubIssues,
591
+ commitHistoryLimit: (_options_audioReview_commitHistoryLimit = (_options_audioReview4 = options.audioReview) === null || _options_audioReview4 === void 0 ? void 0 : _options_audioReview4.commitHistoryLimit) !== null && _options_audioReview_commitHistoryLimit !== void 0 ? _options_audioReview_commitHistoryLimit : KODRDRIV_DEFAULTS.audioReview.commitHistoryLimit,
592
+ diffHistoryLimit: (_options_audioReview_diffHistoryLimit = (_options_audioReview5 = options.audioReview) === null || _options_audioReview5 === void 0 ? void 0 : _options_audioReview5.diffHistoryLimit) !== null && _options_audioReview_diffHistoryLimit !== void 0 ? _options_audioReview_diffHistoryLimit : KODRDRIV_DEFAULTS.audioReview.diffHistoryLimit,
593
+ releaseNotesLimit: (_options_audioReview_releaseNotesLimit = (_options_audioReview6 = options.audioReview) === null || _options_audioReview6 === void 0 ? void 0 : _options_audioReview6.releaseNotesLimit) !== null && _options_audioReview_releaseNotesLimit !== void 0 ? _options_audioReview_releaseNotesLimit : KODRDRIV_DEFAULTS.audioReview.releaseNotesLimit,
594
+ githubIssuesLimit: (_options_audioReview_githubIssuesLimit = (_options_audioReview7 = options.audioReview) === null || _options_audioReview7 === void 0 ? void 0 : _options_audioReview7.githubIssuesLimit) !== null && _options_audioReview_githubIssuesLimit !== void 0 ? _options_audioReview_githubIssuesLimit : KODRDRIV_DEFAULTS.audioReview.githubIssuesLimit,
595
+ context: (_options_audioReview8 = options.audioReview) === null || _options_audioReview8 === void 0 ? void 0 : _options_audioReview8.context,
596
+ sendit: (_options_audioReview_sendit = (_options_audioReview9 = options.audioReview) === null || _options_audioReview9 === void 0 ? void 0 : _options_audioReview9.sendit) !== null && _options_audioReview_sendit !== void 0 ? _options_audioReview_sendit : KODRDRIV_DEFAULTS.audioReview.sendit
597
+ },
598
+ review: {
599
+ includeCommitHistory: (_options_review_includeCommitHistory = (_options_review = options.review) === null || _options_review === void 0 ? void 0 : _options_review.includeCommitHistory) !== null && _options_review_includeCommitHistory !== void 0 ? _options_review_includeCommitHistory : KODRDRIV_DEFAULTS.review.includeCommitHistory,
600
+ includeRecentDiffs: (_options_review_includeRecentDiffs = (_options_review1 = options.review) === null || _options_review1 === void 0 ? void 0 : _options_review1.includeRecentDiffs) !== null && _options_review_includeRecentDiffs !== void 0 ? _options_review_includeRecentDiffs : KODRDRIV_DEFAULTS.review.includeRecentDiffs,
601
+ includeReleaseNotes: (_options_review_includeReleaseNotes = (_options_review2 = options.review) === null || _options_review2 === void 0 ? void 0 : _options_review2.includeReleaseNotes) !== null && _options_review_includeReleaseNotes !== void 0 ? _options_review_includeReleaseNotes : KODRDRIV_DEFAULTS.review.includeReleaseNotes,
602
+ includeGithubIssues: (_options_review_includeGithubIssues = (_options_review3 = options.review) === null || _options_review3 === void 0 ? void 0 : _options_review3.includeGithubIssues) !== null && _options_review_includeGithubIssues !== void 0 ? _options_review_includeGithubIssues : KODRDRIV_DEFAULTS.review.includeGithubIssues,
603
+ commitHistoryLimit: (_options_review_commitHistoryLimit = (_options_review4 = options.review) === null || _options_review4 === void 0 ? void 0 : _options_review4.commitHistoryLimit) !== null && _options_review_commitHistoryLimit !== void 0 ? _options_review_commitHistoryLimit : KODRDRIV_DEFAULTS.review.commitHistoryLimit,
604
+ diffHistoryLimit: (_options_review_diffHistoryLimit = (_options_review5 = options.review) === null || _options_review5 === void 0 ? void 0 : _options_review5.diffHistoryLimit) !== null && _options_review_diffHistoryLimit !== void 0 ? _options_review_diffHistoryLimit : KODRDRIV_DEFAULTS.review.diffHistoryLimit,
605
+ releaseNotesLimit: (_options_review_releaseNotesLimit = (_options_review6 = options.review) === null || _options_review6 === void 0 ? void 0 : _options_review6.releaseNotesLimit) !== null && _options_review_releaseNotesLimit !== void 0 ? _options_review_releaseNotesLimit : KODRDRIV_DEFAULTS.review.releaseNotesLimit,
606
+ githubIssuesLimit: (_options_review_githubIssuesLimit = (_options_review7 = options.review) === null || _options_review7 === void 0 ? void 0 : _options_review7.githubIssuesLimit) !== null && _options_review_githubIssuesLimit !== void 0 ? _options_review_githubIssuesLimit : KODRDRIV_DEFAULTS.review.githubIssuesLimit,
607
+ context: (_options_review8 = options.review) === null || _options_review8 === void 0 ? void 0 : _options_review8.context,
608
+ sendit: (_options_review_sendit = (_options_review9 = options.review) === null || _options_review9 === void 0 ? void 0 : _options_review9.sendit) !== null && _options_review_sendit !== void 0 ? _options_review_sendit : KODRDRIV_DEFAULTS.review.sendit,
609
+ note: (_options_review10 = options.review) === null || _options_review10 === void 0 ? void 0 : _options_review10.note
610
+ },
288
611
  publish: {
289
612
  mergeMethod: (_options_publish_mergeMethod = (_options_publish = options.publish) === null || _options_publish === void 0 ? void 0 : _options_publish.mergeMethod) !== null && _options_publish_mergeMethod !== void 0 ? _options_publish_mergeMethod : KODRDRIV_DEFAULTS.publish.mergeMethod,
290
613
  dependencyUpdatePatterns: (_options_publish1 = options.publish) === null || _options_publish1 === void 0 ? void 0 : _options_publish1.dependencyUpdatePatterns,