@grunnverk/kodrdriv 1.3.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 (84) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.cursor/rules/no-local-dependencies.md +6 -0
  3. package/.gitignore~ +23 -0
  4. package/.kodrdriv-example-branch-targeting.yaml +71 -0
  5. package/BUG_TREE_PUBLISH_CONFIG_DIR.md +79 -0
  6. package/LICENSE +190 -0
  7. package/README.md +218 -0
  8. package/dist/application.js +228 -0
  9. package/dist/application.js.map +1 -0
  10. package/dist/arguments.js +1307 -0
  11. package/dist/arguments.js.map +1 -0
  12. package/dist/constants.js +255 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/logging.js +176 -0
  15. package/dist/logging.js.map +1 -0
  16. package/dist/main.js +24 -0
  17. package/dist/main.js.map +1 -0
  18. package/dist/mcp/prompts/check_development.md +169 -0
  19. package/dist/mcp/prompts/dependency_update.md +62 -0
  20. package/dist/mcp/prompts/fix_and_commit.md +53 -0
  21. package/dist/mcp/prompts/publish.md +100 -0
  22. package/dist/mcp/prompts/tree_fix_and_commit.md +102 -0
  23. package/dist/mcp/prompts/tree_publish.md +118 -0
  24. package/dist/mcp-server.js +15601 -0
  25. package/dist/mcp-server.js.map +7 -0
  26. package/dist/types.js +303 -0
  27. package/dist/types.js.map +1 -0
  28. package/guide/ai-system.md +522 -0
  29. package/guide/architecture.md +349 -0
  30. package/guide/commands.md +383 -0
  31. package/guide/configuration.md +516 -0
  32. package/guide/debugging.md +587 -0
  33. package/guide/development.md +632 -0
  34. package/guide/index.md +224 -0
  35. package/guide/integration.md +510 -0
  36. package/guide/monorepo.md +533 -0
  37. package/guide/quickstart.md +249 -0
  38. package/guide/testing.md +463 -0
  39. package/guide/tree-operations.md +621 -0
  40. package/guide/usage.md +578 -0
  41. package/input/250509-kodrdriv-library-rules.m4a +0 -0
  42. package/package.json +105 -0
  43. package/packages/components/package.json +7 -0
  44. package/packages/tools/package.json +7 -0
  45. package/packages/utils/package.json +7 -0
  46. package/processed/250705-kodrdriv-confirm-editor-for-commit-and-release.m4a +0 -0
  47. package/processed/250705-kodrdriv-confirm-flag-release.m4a +0 -0
  48. package/processed/250705-kodrdriv-context-for-review.m4a +0 -0
  49. package/processed/250705-kodrdriv-feedback-on-publish-pipeline.m4a +0 -0
  50. package/processed/250705-kodrdriv-intelligent-eslint-style.m4a +0 -0
  51. package/processed/250705-kodrdriv-make-review-less-strict.m4a +0 -0
  52. package/processed/250705-kodrdriv-multilevel-transcription.m4a +0 -0
  53. package/processed/250705-kodrdriv-opinionated-review.m4a +0 -0
  54. package/processed/250705-kodrdriv-publish-next-version.m4a +0 -0
  55. package/processed/250705-kodrdriv-release-branches-and-milestones.m4a +0 -0
  56. package/processed/250705-kodrdriv-scope-check-fix-or-ignore.m4a +0 -0
  57. package/processed/250705-kodrdriv-scope-checker.m4a +0 -0
  58. package/processed/250705-kodrdriv-specify-a-release-note-for-publish.m4a +0 -0
  59. package/scripts/build-mcp.js +111 -0
  60. package/scripts/pre-commit-hook.sh +52 -0
  61. package/scripts/test-get-version-tool.js +102 -0
  62. package/scripts/test-mcp-compliance.js +254 -0
  63. package/scripts/update-test-log-assertions.js +73 -0
  64. package/temp-dist/arguments.js +817 -0
  65. package/temp-dist/constants.js +202 -0
  66. package/temp-dist/logging.js +130 -0
  67. package/temp-dist/types.js +112 -0
  68. package/temp-dist/util/stdin.js +132 -0
  69. package/temp-dist/util/storage.js +149 -0
  70. package/temp-dist/util/validation.js +110 -0
  71. package/test-external-unlink/package.json +16 -0
  72. package/test-externals/package.json +8 -0
  73. package/test-increment.js +0 -0
  74. package/test-multiline/cli/package.json +8 -0
  75. package/test-multiline/core/package.json +5 -0
  76. package/test-multiline/mobile/package.json +8 -0
  77. package/test-multiline/web/package.json +8 -0
  78. package/test-project/package-lock.json +21 -0
  79. package/test-project/package.json +1 -0
  80. package/test-review-flow.sh +15 -0
  81. package/test-sort-files/alpha.md +3 -0
  82. package/test-sort-files/middle.txt +3 -0
  83. package/test-sort-files/zebra.txt +3 -0
  84. package/test_output.txt +161 -0
@@ -0,0 +1,1307 @@
1
+ import { Command } from 'commander';
2
+ import path from 'path';
3
+ import { z } from 'zod';
4
+ import { PROGRAM_NAME, VERSION, BUILD_HOSTNAME, BUILD_TIMESTAMP, KODRDRIV_DEFAULTS, ALLOWED_COMMANDS, DEFAULT_COMMAND } from './constants.js';
5
+ import { getLogger } from './logging.js';
6
+ import { readStdin, createStorage } from '@grunnverk/shared';
7
+ import { safeJsonParse } from '@grunnverk/git-tools';
8
+
9
+ z.object({
10
+ dryRun: z.boolean().optional(),
11
+ verbose: z.boolean().optional(),
12
+ debug: z.boolean().optional(),
13
+ overrides: z.boolean().optional(),
14
+ checkConfig: z.boolean().optional(),
15
+ initConfig: z.boolean().optional(),
16
+ model: z.string().optional(),
17
+ openaiReasoning: z.enum([
18
+ 'low',
19
+ 'medium',
20
+ 'high'
21
+ ]).optional(),
22
+ openaiMaxOutputTokens: z.number().optional(),
23
+ contextDirectories: z.array(z.string()).optional(),
24
+ configDir: z.string().optional(),
25
+ outputDir: z.string().optional(),
26
+ preferencesDir: z.string().optional(),
27
+ cached: z.boolean().optional(),
28
+ add: z.boolean().optional(),
29
+ sendit: z.boolean().optional(),
30
+ interactive: z.boolean().optional(),
31
+ amend: z.boolean().optional(),
32
+ from: z.string().optional(),
33
+ to: z.string().optional(),
34
+ targetVersion: z.string().optional(),
35
+ skipAlreadyPublished: z.boolean().optional(),
36
+ forceRepublish: z.boolean().optional(),
37
+ skipLinkCleanup: z.boolean().optional(),
38
+ excludedPatterns: z.array(z.string()).optional(),
39
+ excludedPaths: z.array(z.string()).optional(),
40
+ exclude: z.array(z.string()).optional(),
41
+ context: z.string().optional(),
42
+ contextFiles: z.array(z.string()).optional(),
43
+ note: z.string().optional(),
44
+ direction: z.string().optional(),
45
+ messageLimit: z.number().optional(),
46
+ skipFileCheck: z.boolean().optional(),
47
+ maxDiffBytes: z.number().optional(),
48
+ mergeMethod: z.enum([
49
+ 'merge',
50
+ 'squash',
51
+ 'rebase'
52
+ ]).optional(),
53
+ syncTarget: z.boolean().optional(),
54
+ scopeRoots: z.string().optional(),
55
+ workspaceFile: z.string().optional(),
56
+ cleanNodeModules: z.boolean().optional(),
57
+ startFrom: z.string().optional(),
58
+ stopAt: z.string().optional(),
59
+ script: z.string().optional(),
60
+ cmd: z.string().optional(),
61
+ publish: z.boolean().optional(),
62
+ parallel: z.boolean().optional(),
63
+ continue: z.boolean().optional(),
64
+ status: z.boolean().optional(),
65
+ includeCommitHistory: z.boolean().optional(),
66
+ includeRecentDiffs: z.boolean().optional(),
67
+ editorTimeout: z.number().optional(),
68
+ includeReleaseNotes: z.boolean().optional(),
69
+ includeGithubIssues: z.boolean().optional(),
70
+ commitHistoryLimit: z.number().optional(),
71
+ diffHistoryLimit: z.number().optional(),
72
+ releaseNotesLimit: z.number().optional(),
73
+ githubIssuesLimit: z.number().optional(),
74
+ file: z.string().optional(),
75
+ directory: z.string().optional(),
76
+ directories: z.array(z.string()).optional(),
77
+ externals: z.array(z.string()).optional(),
78
+ keepTemp: z.boolean().optional(),
79
+ noMilestones: z.boolean().optional(),
80
+ subcommand: z.string().optional(),
81
+ scope: z.string().optional(),
82
+ tagWorkingBranch: z.boolean().optional(),
83
+ createRetroactiveTags: z.boolean().optional(),
84
+ workingTagPrefix: z.string().optional(),
85
+ updateDeps: z.string().optional(),
86
+ interProject: z.boolean().optional(),
87
+ report: z.boolean().optional(),
88
+ analyze: z.boolean().optional(),
89
+ strategy: z.enum([
90
+ 'latest',
91
+ 'conservative',
92
+ 'compatible'
93
+ ]).optional(),
94
+ selfReflection: z.boolean().optional(),
95
+ maxAgenticIterations: z.number().optional(),
96
+ // Pull command options
97
+ remote: z.string().optional(),
98
+ branch: z.string().optional(),
99
+ autoStash: z.boolean().optional(),
100
+ autoResolve: z.boolean().optional(),
101
+ // Precommit command options
102
+ fix: z.boolean().optional()
103
+ });
104
+ // Function to transform flat CLI args into nested Config structure
105
+ const transformCliArgs = (finalCliArgs, commandName)=>{
106
+ const transformedCliArgs = {};
107
+ // Root-level properties
108
+ if (finalCliArgs.dryRun !== undefined) transformedCliArgs.dryRun = finalCliArgs.dryRun;
109
+ if (finalCliArgs.verbose !== undefined) transformedCliArgs.verbose = finalCliArgs.verbose;
110
+ if (finalCliArgs.debug !== undefined) transformedCliArgs.debug = finalCliArgs.debug;
111
+ if (finalCliArgs.model !== undefined) transformedCliArgs.model = finalCliArgs.model;
112
+ if (finalCliArgs.outputDir !== undefined) transformedCliArgs.outputDirectory = finalCliArgs.outputDir;
113
+ if (finalCliArgs.preferencesDir !== undefined) transformedCliArgs.preferencesDirectory = finalCliArgs.preferencesDir;
114
+ if (finalCliArgs.configDir !== undefined) transformedCliArgs.configDirectory = finalCliArgs.configDir;
115
+ if (finalCliArgs.overrides !== undefined) transformedCliArgs.overrides = finalCliArgs.overrides;
116
+ if (finalCliArgs.contextDirectories !== undefined) transformedCliArgs.contextDirectories = finalCliArgs.contextDirectories;
117
+ if (finalCliArgs.openaiReasoning !== undefined) transformedCliArgs.openaiReasoning = finalCliArgs.openaiReasoning;
118
+ if (finalCliArgs.openaiMaxOutputTokens !== undefined) transformedCliArgs.openaiMaxOutputTokens = finalCliArgs.openaiMaxOutputTokens;
119
+ // Nested mappings for 'commit' options
120
+ if (finalCliArgs.add !== undefined || finalCliArgs.cached !== undefined || finalCliArgs.sendit !== undefined || finalCliArgs.skipFileCheck !== undefined || finalCliArgs.maxDiffBytes !== undefined || finalCliArgs.messageLimit !== undefined || finalCliArgs.openaiReasoning !== undefined || finalCliArgs.openaiMaxOutputTokens !== undefined || finalCliArgs.amend !== undefined || finalCliArgs.context !== undefined || finalCliArgs.direction !== undefined || commandName === 'commit' && finalCliArgs.interactive !== undefined || finalCliArgs.push !== undefined) {
121
+ transformedCliArgs.commit = {};
122
+ if (finalCliArgs.add !== undefined) transformedCliArgs.commit.add = finalCliArgs.add;
123
+ if (finalCliArgs.cached !== undefined) transformedCliArgs.commit.cached = finalCliArgs.cached;
124
+ if (finalCliArgs.sendit !== undefined) transformedCliArgs.commit.sendit = finalCliArgs.sendit;
125
+ if (finalCliArgs.skipFileCheck !== undefined) transformedCliArgs.commit.skipFileCheck = finalCliArgs.skipFileCheck;
126
+ if (finalCliArgs.maxDiffBytes !== undefined) transformedCliArgs.commit.maxDiffBytes = finalCliArgs.maxDiffBytes;
127
+ if (finalCliArgs.messageLimit !== undefined) transformedCliArgs.commit.messageLimit = finalCliArgs.messageLimit;
128
+ if (finalCliArgs.amend !== undefined) transformedCliArgs.commit.amend = finalCliArgs.amend;
129
+ if (finalCliArgs.push !== undefined) transformedCliArgs.commit.push = finalCliArgs.push;
130
+ if (finalCliArgs.context !== undefined) transformedCliArgs.commit.context = finalCliArgs.context;
131
+ if (finalCliArgs.direction !== undefined) transformedCliArgs.commit.direction = finalCliArgs.direction;
132
+ if (commandName === 'commit' && finalCliArgs.interactive !== undefined) transformedCliArgs.commit.interactive = finalCliArgs.interactive;
133
+ if (finalCliArgs.openaiReasoning !== undefined) transformedCliArgs.commit.openaiReasoning = finalCliArgs.openaiReasoning;
134
+ if (finalCliArgs.openaiMaxOutputTokens !== undefined) transformedCliArgs.commit.openaiMaxOutputTokens = finalCliArgs.openaiMaxOutputTokens;
135
+ }
136
+ // Nested mappings for 'audioCommit' options
137
+ if (finalCliArgs.file !== undefined || finalCliArgs.keepTemp !== undefined || finalCliArgs.openaiReasoning !== undefined || finalCliArgs.openaiMaxOutputTokens !== undefined) {
138
+ transformedCliArgs.audioCommit = {};
139
+ if (finalCliArgs.file !== undefined) transformedCliArgs.audioCommit.file = finalCliArgs.file;
140
+ if (finalCliArgs.keepTemp !== undefined) transformedCliArgs.audioCommit.keepTemp = finalCliArgs.keepTemp;
141
+ if (finalCliArgs.openaiReasoning !== undefined) transformedCliArgs.audioCommit.openaiReasoning = finalCliArgs.openaiReasoning;
142
+ if (finalCliArgs.openaiMaxOutputTokens !== undefined) transformedCliArgs.audioCommit.openaiMaxOutputTokens = finalCliArgs.openaiMaxOutputTokens;
143
+ }
144
+ // Nested mappings for 'release' options (only when it's NOT a publish command)
145
+ if (commandName !== 'publish') {
146
+ if (finalCliArgs.from !== undefined || finalCliArgs.to !== undefined || finalCliArgs.maxDiffBytes !== undefined || finalCliArgs.interactive !== undefined || finalCliArgs.noMilestones !== undefined || finalCliArgs.openaiReasoning !== undefined || finalCliArgs.openaiMaxOutputTokens !== undefined || finalCliArgs.selfReflection !== undefined || finalCliArgs.maxAgenticIterations !== undefined) {
147
+ transformedCliArgs.release = {};
148
+ if (finalCliArgs.from !== undefined) transformedCliArgs.release.from = finalCliArgs.from;
149
+ if (finalCliArgs.to !== undefined) transformedCliArgs.release.to = finalCliArgs.to;
150
+ if ((commandName === 'release' || finalCliArgs.from !== undefined || finalCliArgs.to !== undefined) && finalCliArgs.context !== undefined) transformedCliArgs.release.context = finalCliArgs.context;
151
+ if (finalCliArgs.interactive !== undefined) transformedCliArgs.release.interactive = finalCliArgs.interactive;
152
+ if ((commandName === 'release' || finalCliArgs.from !== undefined || finalCliArgs.to !== undefined) && finalCliArgs.messageLimit !== undefined) transformedCliArgs.release.messageLimit = finalCliArgs.messageLimit;
153
+ if (finalCliArgs.maxDiffBytes !== undefined) transformedCliArgs.release.maxDiffBytes = finalCliArgs.maxDiffBytes;
154
+ if (finalCliArgs.noMilestones !== undefined) transformedCliArgs.release.noMilestones = finalCliArgs.noMilestones;
155
+ if (finalCliArgs.openaiReasoning !== undefined) transformedCliArgs.release.openaiReasoning = finalCliArgs.openaiReasoning;
156
+ if (finalCliArgs.openaiMaxOutputTokens !== undefined) transformedCliArgs.release.openaiMaxOutputTokens = finalCliArgs.openaiMaxOutputTokens;
157
+ if (finalCliArgs.selfReflection !== undefined) transformedCliArgs.release.selfReflection = finalCliArgs.selfReflection;
158
+ if (finalCliArgs.maxAgenticIterations !== undefined) transformedCliArgs.release.maxAgenticIterations = finalCliArgs.maxAgenticIterations;
159
+ }
160
+ }
161
+ // Nested mappings for 'publish' options – map whenever publish-specific options are provided
162
+ if (finalCliArgs.mergeMethod !== undefined || finalCliArgs.targetVersion !== undefined || finalCliArgs.interactive !== undefined || finalCliArgs.syncTarget !== undefined || finalCliArgs.skipAlreadyPublished !== undefined || finalCliArgs.forceRepublish !== undefined || commandName === 'publish' && (finalCliArgs.from !== undefined || finalCliArgs.noMilestones !== undefined || finalCliArgs.selfReflection !== undefined || finalCliArgs.maxAgenticIterations !== undefined)) {
163
+ transformedCliArgs.publish = {};
164
+ if (finalCliArgs.mergeMethod !== undefined) transformedCliArgs.publish.mergeMethod = finalCliArgs.mergeMethod;
165
+ if ((commandName === 'publish' || finalCliArgs.mergeMethod !== undefined || finalCliArgs.targetVersion !== undefined || finalCliArgs.syncTarget !== undefined || finalCliArgs.interactive !== undefined || finalCliArgs.skipAlreadyPublished !== undefined || finalCliArgs.forceRepublish !== undefined) && finalCliArgs.from !== undefined) transformedCliArgs.publish.from = finalCliArgs.from;
166
+ if (finalCliArgs.targetVersion !== undefined) transformedCliArgs.publish.targetVersion = finalCliArgs.targetVersion;
167
+ if (finalCliArgs.interactive !== undefined) transformedCliArgs.publish.interactive = finalCliArgs.interactive;
168
+ if (finalCliArgs.syncTarget !== undefined) transformedCliArgs.publish.syncTarget = finalCliArgs.syncTarget;
169
+ if (finalCliArgs.skipAlreadyPublished !== undefined) transformedCliArgs.publish.skipAlreadyPublished = finalCliArgs.skipAlreadyPublished;
170
+ if (finalCliArgs.forceRepublish !== undefined) transformedCliArgs.publish.forceRepublish = finalCliArgs.forceRepublish;
171
+ if (finalCliArgs.skipLinkCleanup !== undefined) transformedCliArgs.publish.skipLinkCleanup = finalCliArgs.skipLinkCleanup;
172
+ if ((commandName === 'publish' || finalCliArgs.mergeMethod !== undefined || finalCliArgs.targetVersion !== undefined || finalCliArgs.syncTarget !== undefined || finalCliArgs.interactive !== undefined || finalCliArgs.skipAlreadyPublished !== undefined || finalCliArgs.forceRepublish !== undefined) && finalCliArgs.noMilestones !== undefined) transformedCliArgs.publish.noMilestones = finalCliArgs.noMilestones;
173
+ if (finalCliArgs.updateDeps !== undefined) transformedCliArgs.publish.updateDeps = finalCliArgs.updateDeps;
174
+ // Map release-related flags from publish command into release config (only if any are set)
175
+ if (commandName === 'publish' && (finalCliArgs.selfReflection !== undefined || finalCliArgs.maxAgenticIterations !== undefined)) {
176
+ transformedCliArgs.release = {
177
+ ...transformedCliArgs.release || {},
178
+ ...finalCliArgs.selfReflection !== undefined ? {
179
+ selfReflection: finalCliArgs.selfReflection
180
+ } : {},
181
+ ...finalCliArgs.maxAgenticIterations !== undefined ? {
182
+ maxAgenticIterations: finalCliArgs.maxAgenticIterations
183
+ } : {}
184
+ };
185
+ }
186
+ }
187
+ // Nested mappings for 'development' options
188
+ if (commandName === 'development' && (finalCliArgs.targetVersion !== undefined || finalCliArgs.noMilestones !== undefined || finalCliArgs.tagWorkingBranch !== undefined || finalCliArgs.createRetroactiveTags !== undefined || finalCliArgs.workingTagPrefix !== undefined)) {
189
+ transformedCliArgs.development = {};
190
+ if (finalCliArgs.targetVersion !== undefined) transformedCliArgs.development.targetVersion = finalCliArgs.targetVersion;
191
+ if (finalCliArgs.noMilestones !== undefined) transformedCliArgs.development.noMilestones = finalCliArgs.noMilestones;
192
+ if (finalCliArgs.tagWorkingBranch !== undefined) transformedCliArgs.development.tagWorkingBranch = finalCliArgs.tagWorkingBranch;
193
+ if (finalCliArgs.createRetroactiveTags !== undefined) transformedCliArgs.development.createRetroactiveTags = finalCliArgs.createRetroactiveTags;
194
+ if (finalCliArgs.workingTagPrefix !== undefined) transformedCliArgs.development.workingTagPrefix = finalCliArgs.workingTagPrefix;
195
+ // Mirror targetVersion into publish; mirror noMilestones into publish and release to match test expectations
196
+ transformedCliArgs.publish = {
197
+ ...transformedCliArgs.publish || {},
198
+ ...finalCliArgs.targetVersion !== undefined ? {
199
+ targetVersion: finalCliArgs.targetVersion
200
+ } : {},
201
+ ...finalCliArgs.noMilestones !== undefined ? {
202
+ noMilestones: finalCliArgs.noMilestones
203
+ } : {}
204
+ };
205
+ transformedCliArgs.release = {
206
+ ...transformedCliArgs.release || {},
207
+ ...finalCliArgs.noMilestones !== undefined ? {
208
+ noMilestones: finalCliArgs.noMilestones
209
+ } : {}
210
+ };
211
+ }
212
+ // Nested mappings for 'link' and 'unlink' options
213
+ const linkPackageArgument = finalCliArgs.packageArgument;
214
+ if ((commandName === 'link' || commandName === undefined) && (finalCliArgs.scopeRoots !== undefined || linkPackageArgument !== undefined)) {
215
+ transformedCliArgs.link = {};
216
+ if (finalCliArgs.scopeRoots !== undefined) {
217
+ try {
218
+ transformedCliArgs.link.scopeRoots = safeJsonParse(finalCliArgs.scopeRoots, 'scopeRoots CLI argument');
219
+ } catch (error) {
220
+ throw new Error(`Invalid JSON for scope-roots: ${finalCliArgs.scopeRoots}`);
221
+ }
222
+ }
223
+ if (linkPackageArgument !== undefined) {
224
+ transformedCliArgs.link.packageArgument = linkPackageArgument;
225
+ }
226
+ }
227
+ // Nested mappings for 'unlink' options
228
+ const unlinkPackageArgument = finalCliArgs.packageArgument;
229
+ if (commandName === 'unlink' && (finalCliArgs.scopeRoots !== undefined || unlinkPackageArgument !== undefined || finalCliArgs.workspaceFile !== undefined || finalCliArgs.cleanNodeModules !== undefined)) {
230
+ transformedCliArgs.unlink = {};
231
+ if (finalCliArgs.scopeRoots !== undefined) {
232
+ try {
233
+ transformedCliArgs.unlink.scopeRoots = safeJsonParse(finalCliArgs.scopeRoots, 'scopeRoots CLI argument');
234
+ } catch (error) {
235
+ throw new Error(`Invalid JSON for scope-roots: ${finalCliArgs.scopeRoots}`);
236
+ }
237
+ }
238
+ if (finalCliArgs.workspaceFile !== undefined) transformedCliArgs.unlink.workspaceFile = finalCliArgs.workspaceFile;
239
+ if (finalCliArgs.cleanNodeModules !== undefined) transformedCliArgs.unlink.cleanNodeModules = finalCliArgs.cleanNodeModules;
240
+ if (unlinkPackageArgument !== undefined) {
241
+ transformedCliArgs.unlink.packageArgument = unlinkPackageArgument;
242
+ }
243
+ }
244
+ // Nested mappings for 'audio-review' options (only when it's not a tree command)
245
+ if (commandName !== 'tree' && (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.file !== undefined || finalCliArgs.directories !== undefined || finalCliArgs.keepTemp !== undefined || finalCliArgs.openaiReasoning !== undefined || finalCliArgs.openaiMaxOutputTokens !== undefined)) {
246
+ transformedCliArgs.audioReview = {};
247
+ if (finalCliArgs.includeCommitHistory !== undefined) transformedCliArgs.audioReview.includeCommitHistory = finalCliArgs.includeCommitHistory;
248
+ if (finalCliArgs.includeRecentDiffs !== undefined) transformedCliArgs.audioReview.includeRecentDiffs = finalCliArgs.includeRecentDiffs;
249
+ if (finalCliArgs.includeReleaseNotes !== undefined) transformedCliArgs.audioReview.includeReleaseNotes = finalCliArgs.includeReleaseNotes;
250
+ if (finalCliArgs.includeGithubIssues !== undefined) transformedCliArgs.audioReview.includeGithubIssues = finalCliArgs.includeGithubIssues;
251
+ if (finalCliArgs.commitHistoryLimit !== undefined) transformedCliArgs.audioReview.commitHistoryLimit = finalCliArgs.commitHistoryLimit;
252
+ if (finalCliArgs.diffHistoryLimit !== undefined) transformedCliArgs.audioReview.diffHistoryLimit = finalCliArgs.diffHistoryLimit;
253
+ if (finalCliArgs.releaseNotesLimit !== undefined) transformedCliArgs.audioReview.releaseNotesLimit = finalCliArgs.releaseNotesLimit;
254
+ if (finalCliArgs.githubIssuesLimit !== undefined) transformedCliArgs.audioReview.githubIssuesLimit = finalCliArgs.githubIssuesLimit;
255
+ if (finalCliArgs.context !== undefined) transformedCliArgs.audioReview.context = finalCliArgs.context;
256
+ if (finalCliArgs.sendit !== undefined) transformedCliArgs.audioReview.sendit = finalCliArgs.sendit;
257
+ if (finalCliArgs.file !== undefined) transformedCliArgs.audioReview.file = finalCliArgs.file;
258
+ if (finalCliArgs.directory !== undefined) transformedCliArgs.audioReview.directory = finalCliArgs.directory;
259
+ if (finalCliArgs.keepTemp !== undefined) transformedCliArgs.audioReview.keepTemp = finalCliArgs.keepTemp;
260
+ if (finalCliArgs.openaiReasoning !== undefined) transformedCliArgs.audioReview.openaiReasoning = finalCliArgs.openaiReasoning;
261
+ if (finalCliArgs.openaiMaxOutputTokens !== undefined) transformedCliArgs.audioReview.openaiMaxOutputTokens = finalCliArgs.openaiMaxOutputTokens;
262
+ }
263
+ // Nested mappings for 'precommit' options
264
+ if (finalCliArgs.fix !== undefined) {
265
+ transformedCliArgs.precommit = {};
266
+ transformedCliArgs.precommit.fix = finalCliArgs.fix;
267
+ }
268
+ // Nested mappings for 'review' options
269
+ 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 || finalCliArgs.openaiReasoning !== undefined || finalCliArgs.openaiMaxOutputTokens !== undefined || commandName === 'review' && (finalCliArgs.file !== undefined || finalCliArgs.directory !== undefined)) {
270
+ transformedCliArgs.review = {};
271
+ if (finalCliArgs.note !== undefined) transformedCliArgs.review.note = finalCliArgs.note;
272
+ if (commandName === 'review' && finalCliArgs.file !== undefined) transformedCliArgs.review.file = finalCliArgs.file;
273
+ if (commandName === 'review' && finalCliArgs.directory !== undefined) transformedCliArgs.review.directory = finalCliArgs.directory;
274
+ // Include optional review configuration options if specified
275
+ if (finalCliArgs.includeCommitHistory !== undefined) transformedCliArgs.review.includeCommitHistory = finalCliArgs.includeCommitHistory;
276
+ if (finalCliArgs.includeRecentDiffs !== undefined) transformedCliArgs.review.includeRecentDiffs = finalCliArgs.includeRecentDiffs;
277
+ if (finalCliArgs.includeReleaseNotes !== undefined) transformedCliArgs.review.includeReleaseNotes = finalCliArgs.includeReleaseNotes;
278
+ if (finalCliArgs.includeGithubIssues !== undefined) transformedCliArgs.review.includeGithubIssues = finalCliArgs.includeGithubIssues;
279
+ if (finalCliArgs.commitHistoryLimit !== undefined) transformedCliArgs.review.commitHistoryLimit = finalCliArgs.commitHistoryLimit;
280
+ if (finalCliArgs.diffHistoryLimit !== undefined) transformedCliArgs.review.diffHistoryLimit = finalCliArgs.diffHistoryLimit;
281
+ if (finalCliArgs.releaseNotesLimit !== undefined) transformedCliArgs.review.releaseNotesLimit = finalCliArgs.releaseNotesLimit;
282
+ if (finalCliArgs.githubIssuesLimit !== undefined) transformedCliArgs.review.githubIssuesLimit = finalCliArgs.githubIssuesLimit;
283
+ if (finalCliArgs.context !== undefined) transformedCliArgs.review.context = finalCliArgs.context;
284
+ if (finalCliArgs.sendit !== undefined) transformedCliArgs.review.sendit = finalCliArgs.sendit;
285
+ if (finalCliArgs.editorTimeout !== undefined) transformedCliArgs.review.editorTimeout = finalCliArgs.editorTimeout;
286
+ if (finalCliArgs.openaiReasoning !== undefined) transformedCliArgs.review.openaiReasoning = finalCliArgs.openaiReasoning;
287
+ if (finalCliArgs.openaiMaxOutputTokens !== undefined) transformedCliArgs.review.openaiMaxOutputTokens = finalCliArgs.openaiMaxOutputTokens;
288
+ }
289
+ // Nested mappings for 'tree' options (add when relevant args present)
290
+ if (commandName === 'tree') {
291
+ const builtInCommand = finalCliArgs.builtInCommand;
292
+ const packageArgument = finalCliArgs.packageArgument;
293
+ // Map command-specific options to nested configs for tree operations
294
+ // When tree commit/release/publish is run, these options get forwarded
295
+ if (builtInCommand === 'commit' && finalCliArgs.contextFiles !== undefined) {
296
+ if (!transformedCliArgs.commit) transformedCliArgs.commit = {};
297
+ transformedCliArgs.commit.contextFiles = finalCliArgs.contextFiles;
298
+ }
299
+ if (builtInCommand === 'commit' && finalCliArgs.selfReflection !== undefined) {
300
+ if (!transformedCliArgs.commit) transformedCliArgs.commit = {};
301
+ transformedCliArgs.commit.selfReflection = finalCliArgs.selfReflection;
302
+ }
303
+ if (builtInCommand === 'commit' && finalCliArgs.maxAgenticIterations !== undefined) {
304
+ if (!transformedCliArgs.commit) transformedCliArgs.commit = {};
305
+ transformedCliArgs.commit.maxAgenticIterations = finalCliArgs.maxAgenticIterations;
306
+ }
307
+ if ((builtInCommand === 'release' || builtInCommand === 'publish') && finalCliArgs.contextFiles !== undefined) {
308
+ if (!transformedCliArgs.release) transformedCliArgs.release = {};
309
+ transformedCliArgs.release.contextFiles = finalCliArgs.contextFiles;
310
+ }
311
+ if ((builtInCommand === 'release' || builtInCommand === 'publish') && finalCliArgs.selfReflection !== undefined) {
312
+ if (!transformedCliArgs.release) transformedCliArgs.release = {};
313
+ transformedCliArgs.release.selfReflection = finalCliArgs.selfReflection;
314
+ }
315
+ if ((builtInCommand === 'release' || builtInCommand === 'publish') && finalCliArgs.maxAgenticIterations !== undefined) {
316
+ if (!transformedCliArgs.release) transformedCliArgs.release = {};
317
+ transformedCliArgs.release.maxAgenticIterations = finalCliArgs.maxAgenticIterations;
318
+ }
319
+ // Only create tree object if there are actual tree-specific options
320
+ const cliArgs = finalCliArgs;
321
+ if (finalCliArgs.directories !== undefined || finalCliArgs.directory !== undefined || finalCliArgs.startFrom !== undefined || finalCliArgs.stopAt !== undefined || finalCliArgs.cmd !== undefined || builtInCommand !== undefined || finalCliArgs.continue !== undefined || packageArgument !== undefined || finalCliArgs.cleanNodeModules !== undefined || finalCliArgs.externals !== undefined || cliArgs.statusParallel !== undefined || cliArgs.auditBranches !== undefined || cliArgs.parallel !== undefined || cliArgs.markCompleted !== undefined || cliArgs.skip !== undefined || cliArgs.retryFailed !== undefined || cliArgs.skipFailed !== undefined || cliArgs.validateState !== undefined || cliArgs.order !== undefined) {
322
+ transformedCliArgs.tree = {};
323
+ if (finalCliArgs.directories !== undefined) transformedCliArgs.tree.directories = finalCliArgs.directories;
324
+ else if (finalCliArgs.directory !== undefined) transformedCliArgs.tree.directories = [
325
+ finalCliArgs.directory
326
+ ];
327
+ if (finalCliArgs.startFrom !== undefined) transformedCliArgs.tree.startFrom = finalCliArgs.startFrom;
328
+ if (finalCliArgs.stopAt !== undefined) transformedCliArgs.tree.stopAt = finalCliArgs.stopAt;
329
+ if (finalCliArgs.cmd !== undefined) transformedCliArgs.tree.cmd = finalCliArgs.cmd;
330
+ // Note: parallel property is not part of the tree config type
331
+ if (builtInCommand !== undefined) transformedCliArgs.tree.builtInCommand = builtInCommand;
332
+ if (finalCliArgs.continue !== undefined) transformedCliArgs.tree.continue = finalCliArgs.continue;
333
+ if (finalCliArgs.status !== undefined) transformedCliArgs.tree.status = finalCliArgs.status;
334
+ if (packageArgument !== undefined) transformedCliArgs.tree.packageArgument = packageArgument;
335
+ if (finalCliArgs.cleanNodeModules !== undefined) transformedCliArgs.tree.cleanNodeModules = finalCliArgs.cleanNodeModules;
336
+ if (finalCliArgs.externals !== undefined) transformedCliArgs.tree.externals = finalCliArgs.externals;
337
+ // Parallel execution options
338
+ if (cliArgs.parallel !== undefined) transformedCliArgs.tree.parallel = cliArgs.parallel;
339
+ if (cliArgs.maxConcurrency !== undefined) transformedCliArgs.tree.maxConcurrency = cliArgs.maxConcurrency;
340
+ if (cliArgs.maxRetries !== undefined || cliArgs.retryDelay !== undefined) {
341
+ transformedCliArgs.tree.retry = {
342
+ maxAttempts: cliArgs.maxRetries || 3,
343
+ initialDelayMs: cliArgs.retryDelay || 5000,
344
+ maxDelayMs: 60000,
345
+ backoffMultiplier: 2
346
+ };
347
+ }
348
+ // Recovery options
349
+ if (cliArgs.statusParallel !== undefined) transformedCliArgs.tree.statusParallel = cliArgs.statusParallel;
350
+ if (cliArgs.auditBranches !== undefined) transformedCliArgs.tree.auditBranches = cliArgs.auditBranches;
351
+ if (cliArgs.markCompleted !== undefined) {
352
+ transformedCliArgs.tree.markCompleted = cliArgs.markCompleted.split(',').map((s)=>s.trim());
353
+ }
354
+ if (cliArgs.skip !== undefined) {
355
+ transformedCliArgs.tree.skipPackages = cliArgs.skip.split(',').map((s)=>s.trim());
356
+ }
357
+ if (cliArgs.retryFailed !== undefined) transformedCliArgs.tree.retryFailed = cliArgs.retryFailed;
358
+ if (cliArgs.skipFailed !== undefined) transformedCliArgs.tree.skipFailed = cliArgs.skipFailed;
359
+ if (cliArgs.validateState !== undefined) transformedCliArgs.tree.validateState = cliArgs.validateState;
360
+ if (cliArgs.order !== undefined) transformedCliArgs.tree.order = cliArgs.order;
361
+ }
362
+ }
363
+ // Nested mappings for 'development' options
364
+ if (commandName === 'development' && (finalCliArgs.targetVersion !== undefined || finalCliArgs.noMilestones !== undefined || finalCliArgs.tagWorkingBranch !== undefined || finalCliArgs.createRetroactiveTags !== undefined || finalCliArgs.workingTagPrefix !== undefined)) {
365
+ transformedCliArgs.development = {};
366
+ if (finalCliArgs.targetVersion !== undefined) transformedCliArgs.development.targetVersion = finalCliArgs.targetVersion;
367
+ if (finalCliArgs.noMilestones !== undefined) transformedCliArgs.development.noMilestones = finalCliArgs.noMilestones;
368
+ if (finalCliArgs.tagWorkingBranch !== undefined) transformedCliArgs.development.tagWorkingBranch = finalCliArgs.tagWorkingBranch;
369
+ if (finalCliArgs.createRetroactiveTags !== undefined) transformedCliArgs.development.createRetroactiveTags = finalCliArgs.createRetroactiveTags;
370
+ if (finalCliArgs.workingTagPrefix !== undefined) transformedCliArgs.development.workingTagPrefix = finalCliArgs.workingTagPrefix;
371
+ }
372
+ // Nested mappings for 'versions' options
373
+ if (commandName === 'versions' && (finalCliArgs.subcommand !== undefined || finalCliArgs.directories !== undefined)) {
374
+ transformedCliArgs.versions = {};
375
+ if (finalCliArgs.subcommand !== undefined) transformedCliArgs.versions.subcommand = finalCliArgs.subcommand;
376
+ if (finalCliArgs.directories !== undefined) transformedCliArgs.versions.directories = finalCliArgs.directories;
377
+ }
378
+ // Nested mappings for 'updates' options
379
+ if (commandName === 'updates' && (finalCliArgs.scope !== undefined || finalCliArgs.directories !== undefined || finalCliArgs.interProject !== undefined || finalCliArgs.report !== undefined || finalCliArgs.analyze !== undefined || finalCliArgs.strategy !== undefined)) {
380
+ transformedCliArgs.updates = {};
381
+ if (finalCliArgs.scope !== undefined) transformedCliArgs.updates.scope = finalCliArgs.scope;
382
+ if (finalCliArgs.directories !== undefined) transformedCliArgs.updates.directories = finalCliArgs.directories;
383
+ if (finalCliArgs.interProject !== undefined) transformedCliArgs.updates.interProject = finalCliArgs.interProject;
384
+ if (finalCliArgs.report !== undefined) transformedCliArgs.updates.report = finalCliArgs.report;
385
+ if (finalCliArgs.analyze !== undefined) transformedCliArgs.updates.analyze = finalCliArgs.analyze;
386
+ if (finalCliArgs.strategy !== undefined) transformedCliArgs.updates.strategy = finalCliArgs.strategy;
387
+ }
388
+ // Nested mappings for 'pull' options
389
+ if (commandName === 'pull' && (finalCliArgs.remote !== undefined || finalCliArgs.branch !== undefined || finalCliArgs.autoStash !== undefined || finalCliArgs.autoResolve !== undefined)) {
390
+ transformedCliArgs.pull = {};
391
+ if (finalCliArgs.remote !== undefined) transformedCliArgs.pull.remote = finalCliArgs.remote;
392
+ if (finalCliArgs.branch !== undefined) transformedCliArgs.pull.branch = finalCliArgs.branch;
393
+ if (finalCliArgs.autoStash !== undefined) transformedCliArgs.pull.autoStash = finalCliArgs.autoStash;
394
+ if (finalCliArgs.autoResolve !== undefined) transformedCliArgs.pull.autoResolve = finalCliArgs.autoResolve;
395
+ }
396
+ // Handle excluded patterns (Commander.js converts --excluded-paths to excludedPaths)
397
+ // Also handle exclude as alias for excludedPatterns
398
+ const excludedPatterns = finalCliArgs.excludedPatterns || finalCliArgs.exclude || finalCliArgs.excludedPaths;
399
+ if (excludedPatterns !== undefined) {
400
+ if (commandName === 'tree') {
401
+ // For tree command, map to both root level excludedPatterns AND tree.exclude
402
+ transformedCliArgs.excludedPatterns = excludedPatterns;
403
+ if (!transformedCliArgs.tree) {
404
+ transformedCliArgs.tree = {};
405
+ }
406
+ transformedCliArgs.tree.exclude = excludedPatterns;
407
+ } else {
408
+ // For non-tree commands, map to root level excludedPatterns
409
+ transformedCliArgs.excludedPatterns = excludedPatterns;
410
+ }
411
+ }
412
+ // Handle externals - map to appropriate command objects based on command type
413
+ if (finalCliArgs.externals !== undefined) {
414
+ if (commandName === 'link') {
415
+ if (!transformedCliArgs.link) {
416
+ transformedCliArgs.link = {};
417
+ }
418
+ transformedCliArgs.link.externals = finalCliArgs.externals;
419
+ } else if (commandName === 'unlink') {
420
+ if (!transformedCliArgs.unlink) {
421
+ transformedCliArgs.unlink = {};
422
+ }
423
+ transformedCliArgs.unlink.externals = finalCliArgs.externals;
424
+ } else if (commandName === 'tree') {
425
+ if (!transformedCliArgs.tree) {
426
+ transformedCliArgs.tree = {};
427
+ }
428
+ transformedCliArgs.tree.externals = finalCliArgs.externals;
429
+ }
430
+ }
431
+ // Note: openaiApiKey is handled separately via environment variable only
432
+ return transformedCliArgs;
433
+ };
434
+ // Update configure signature to accept cardigantime
435
+ const configure = async (cardigantime)=>{
436
+ var _config_contextDirectories, _config_link;
437
+ const logger = getLogger();
438
+ let program = new Command();
439
+ // Configure program basics with custom version string
440
+ const versionString = `${VERSION}\nBuilt on: ${BUILD_HOSTNAME}\nBuild time: ${BUILD_TIMESTAMP}`;
441
+ program.name(PROGRAM_NAME).summary('Create Intelligent Release Notes or Change Logs from Git').description('Create Intelligent Release Notes or Change Logs from Git').version(versionString, '-V, --version', 'Display version information');
442
+ // Let cardigantime add its arguments first
443
+ program = await cardigantime.configure(program);
444
+ // Check if --check-config is in process.argv early
445
+ if (process.argv.includes('--check-config')) {
446
+ // For check-config, use CardiganTime's built-in checkConfig method
447
+ program.parse();
448
+ const cliArgs = program.opts();
449
+ // Transform the flat CLI args
450
+ const transformedCliArgs = transformCliArgs(cliArgs);
451
+ // Use CardiganTime's built-in checkConfig method which displays
452
+ // hierarchical configuration information in a well-formatted way
453
+ await cardigantime.checkConfig(transformedCliArgs);
454
+ // Return minimal config for consistency, but main processing is done
455
+ const config = await validateAndProcessOptions({});
456
+ const secureConfig = await validateAndProcessSecureOptions();
457
+ const commandConfig = {
458
+ commandName: 'check-config'
459
+ };
460
+ return [
461
+ config,
462
+ secureConfig,
463
+ commandConfig
464
+ ];
465
+ }
466
+ // Check if --init-config is in process.argv early
467
+ if (process.argv.includes('--init-config')) {
468
+ // For init-config, use CardiganTime's built-in generateConfig method
469
+ program.parse();
470
+ const cliArgs = program.opts();
471
+ // Transform the flat CLI args
472
+ const transformedCliArgs = transformCliArgs(cliArgs);
473
+ // Use CardiganTime's built-in generateConfig method
474
+ const configDir = transformedCliArgs.configDirectory || KODRDRIV_DEFAULTS.configDirectory;
475
+ const absoluteConfigDir = path.isAbsolute(configDir) ? configDir : path.resolve(process.cwd(), configDir);
476
+ await cardigantime.generateConfig(absoluteConfigDir);
477
+ // Return minimal config for consistency, but main processing is done
478
+ const config = await validateAndProcessOptions({});
479
+ const secureConfig = await validateAndProcessSecureOptions();
480
+ const commandConfig = {
481
+ commandName: 'init-config'
482
+ };
483
+ return [
484
+ config,
485
+ secureConfig,
486
+ commandConfig
487
+ ];
488
+ }
489
+ // Get CLI arguments using the new function
490
+ const [finalCliArgs, commandConfig] = await getCliConfig(program);
491
+ logger.silly('Loaded Command Line Options: %s', JSON.stringify(finalCliArgs, null, 2));
492
+ // Transform the flat CLI args using the new function
493
+ const transformedCliArgs = transformCliArgs(finalCliArgs, commandConfig.commandName);
494
+ logger.silly('Transformed CLI Args for merging: %s', JSON.stringify(transformedCliArgs, null, 2));
495
+ // Get values from config file using Cardigantime's hierarchical configuration
496
+ const fileValues = await cardigantime.read(transformedCliArgs);
497
+ // Merge configurations: Defaults -> File -> CLI
498
+ // Properly merge nested sections to preserve config file values when CLI args are partial
499
+ const mergedLink = {
500
+ ...KODRDRIV_DEFAULTS.link,
501
+ ...fileValues.link,
502
+ ...transformedCliArgs.link
503
+ };
504
+ const mergedCommit = {
505
+ ...KODRDRIV_DEFAULTS.commit,
506
+ ...fileValues.commit,
507
+ ...transformedCliArgs.commit
508
+ };
509
+ const mergedRelease = {
510
+ ...KODRDRIV_DEFAULTS.release,
511
+ ...fileValues.release,
512
+ ...transformedCliArgs.release
513
+ };
514
+ const mergedPublish = {
515
+ ...KODRDRIV_DEFAULTS.publish,
516
+ ...fileValues.publish,
517
+ ...transformedCliArgs.publish
518
+ };
519
+ const mergedAudioCommit = {
520
+ ...KODRDRIV_DEFAULTS.audioCommit,
521
+ ...fileValues.audioCommit,
522
+ ...transformedCliArgs.audioCommit
523
+ };
524
+ const mergedAudioReview = {
525
+ ...KODRDRIV_DEFAULTS.audioReview,
526
+ ...fileValues.audioReview,
527
+ ...transformedCliArgs.audioReview
528
+ };
529
+ const mergedReview = {
530
+ ...KODRDRIV_DEFAULTS.review,
531
+ ...fileValues.review,
532
+ ...transformedCliArgs.review
533
+ };
534
+ const mergedTree = {
535
+ ...KODRDRIV_DEFAULTS.tree,
536
+ ...fileValues.tree,
537
+ ...transformedCliArgs.tree
538
+ };
539
+ const mergedBranches = {
540
+ ...KODRDRIV_DEFAULTS.branches || {},
541
+ ...fileValues.branches || {},
542
+ ...transformedCliArgs.branches || {}
543
+ };
544
+ const mergedVersions = {
545
+ ...KODRDRIV_DEFAULTS.versions,
546
+ ...fileValues.versions,
547
+ ...transformedCliArgs.versions
548
+ };
549
+ const mergedUpdates = {
550
+ ...KODRDRIV_DEFAULTS.updates,
551
+ ...fileValues.updates,
552
+ ...transformedCliArgs.updates
553
+ };
554
+ const partialConfig = {
555
+ ...KODRDRIV_DEFAULTS,
556
+ ...fileValues,
557
+ ...transformedCliArgs,
558
+ // Override with properly merged nested sections
559
+ link: mergedLink,
560
+ commit: mergedCommit,
561
+ release: mergedRelease,
562
+ publish: mergedPublish,
563
+ audioCommit: mergedAudioCommit,
564
+ audioReview: mergedAudioReview,
565
+ review: mergedReview,
566
+ tree: mergedTree,
567
+ branches: mergedBranches,
568
+ versions: mergedVersions,
569
+ updates: mergedUpdates
570
+ }; // Cast to Partial<Config> initially
571
+ // Specific validation and processing after merge
572
+ const config = await validateAndProcessOptions(partialConfig);
573
+ // Log effective configuration summary at verbose level
574
+ logger.verbose('Configuration complete. Effective settings:');
575
+ logger.verbose(` Command: ${commandConfig.commandName}`);
576
+ logger.verbose(` Model: ${config.model}`);
577
+ logger.verbose(` Dry run: ${config.dryRun}`);
578
+ logger.verbose(` Debug: ${config.debug}`);
579
+ logger.verbose(` Verbose: ${config.verbose}`);
580
+ logger.verbose(` Config directory: ${config.configDirectory}`);
581
+ logger.verbose(` Output directory: ${config.outputDirectory}`);
582
+ logger.verbose(` Context directories: ${((_config_contextDirectories = config.contextDirectories) === null || _config_contextDirectories === void 0 ? void 0 : _config_contextDirectories.join(', ')) || 'none'}`);
583
+ if (config.excludedPatterns && config.excludedPatterns.length > 0) {
584
+ logger.verbose(` Excluded patterns: ${config.excludedPatterns.join(', ')}`);
585
+ }
586
+ if (Object.keys(((_config_link = config.link) === null || _config_link === void 0 ? void 0 : _config_link.scopeRoots) || {}).length > 0) {
587
+ logger.verbose(` Link scope roots: ${Object.keys(config.link.scopeRoots).join(', ')}`);
588
+ }
589
+ logger.silly('Final configuration: %s', JSON.stringify(config, null, 2));
590
+ const secureConfig = await validateAndProcessSecureOptions();
591
+ return [
592
+ config,
593
+ secureConfig,
594
+ commandConfig
595
+ ];
596
+ };
597
+ // Function to handle CLI argument parsing and processing
598
+ async function getCliConfig(program, commands) {
599
+ const addSharedOptions = (command)=>{
600
+ command.option('--dry-run', 'perform a dry run without saving files') // Removed default, will be handled by merging
601
+ .option('--verbose', 'enable verbose logging').option('--debug', 'enable debug logging').option('--overrides', 'enable overrides').option('--model <model>', 'OpenAI model to use').option('--openai-reasoning <level>', 'OpenAI reasoning level (low, medium, high)').option('--openai-max-output-tokens <tokens>', 'OpenAI maximum output tokens', parseInt).option('-d, --context-directories [contextDirectories...]', 'directories to scan for context').option('--config-dir <configDir>', 'configuration directory') // Keep config-dir for specifying location
602
+ .option('--output-dir <outputDir>', 'output directory for generated files').option('--preferences-dir <preferencesDir>', 'preferences directory for personal settings').option('--excluded-paths [excludedPatterns...]', 'paths to exclude from the diff').option('--keep-temp', 'keep temporary recording files');
603
+ };
604
+ // Add global options to the main program
605
+ // (cardigantime already adds most global options like --verbose, --debug, --config-dir)
606
+ // Add subcommands
607
+ 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('--context-files [contextFiles...]', 'files containing additional 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('--interactive', 'Present commit message for interactive review and editing').option('--amend', 'Amend the last commit with the generated message').option('--push [remote]', 'push to remote after committing (default: origin)').option('--message-limit <messageLimit>', 'limit the number of messages to generate').option('--skip-file-check', 'skip check for file: dependencies before committing').option('--max-diff-bytes <maxDiffBytes>', 'maximum bytes per file in diff (default: 2048)').option('--self-reflection', 'generate self-reflection report with tool effectiveness analysis').option('--max-agentic-iterations <iterations>', 'maximum iterations for analysis (default: 10)', parseInt).option('--allow-commit-splitting', 'allow AI to suggest splitting commits').option('--tool-timeout <timeout>', 'timeout for tool execution in milliseconds', parseInt);
608
+ // Add shared options to commit command
609
+ addSharedOptions(commitCommand);
610
+ // Customize help output for commit command
611
+ commitCommand.configureHelp({
612
+ formatHelp: (cmd, helper)=>{
613
+ const nameAndVersion = `${helper.commandUsage(cmd)}\n\n${helper.commandDescription(cmd)}\n`;
614
+ const commitOptions = [
615
+ [
616
+ '--context <context>',
617
+ 'context for the commit message'
618
+ ],
619
+ [
620
+ '--context-files [contextFiles...]',
621
+ 'files containing additional context'
622
+ ]
623
+ ];
624
+ const behavioralOptions = [
625
+ [
626
+ '--cached',
627
+ 'use cached diff'
628
+ ],
629
+ [
630
+ '--add',
631
+ 'add all changes before committing'
632
+ ],
633
+ [
634
+ '--sendit',
635
+ 'Commit with the message generated. No review.'
636
+ ],
637
+ [
638
+ '--interactive',
639
+ 'Present commit message for interactive review and editing'
640
+ ],
641
+ [
642
+ '--amend',
643
+ 'Amend the last commit with the generated message'
644
+ ],
645
+ [
646
+ '--push [remote]',
647
+ 'push to remote after committing (default: origin)'
648
+ ],
649
+ [
650
+ '--message-limit <messageLimit>',
651
+ 'limit the number of messages to generate'
652
+ ],
653
+ [
654
+ '--skip-file-check',
655
+ 'skip check for file: dependencies before committing'
656
+ ],
657
+ [
658
+ '--max-diff-bytes <maxDiffBytes>',
659
+ 'maximum bytes per file in diff (default: 20480)'
660
+ ]
661
+ ];
662
+ const aiOptions = [
663
+ [
664
+ '--self-reflection',
665
+ 'generate self-reflection report with tool effectiveness analysis'
666
+ ],
667
+ [
668
+ '--max-agentic-iterations <iterations>',
669
+ 'maximum iterations for AI analysis (default: 10)'
670
+ ],
671
+ [
672
+ '--allow-commit-splitting',
673
+ 'allow AI to suggest splitting commits'
674
+ ],
675
+ [
676
+ '--tool-timeout <timeout>',
677
+ 'timeout for tool execution in milliseconds'
678
+ ]
679
+ ];
680
+ const globalOptions = [
681
+ [
682
+ '--dry-run',
683
+ 'perform a dry run without saving files'
684
+ ],
685
+ [
686
+ '--verbose',
687
+ 'enable verbose logging'
688
+ ],
689
+ [
690
+ '--debug',
691
+ 'enable debug logging'
692
+ ],
693
+ [
694
+ '--overrides',
695
+ 'enable overrides'
696
+ ],
697
+ [
698
+ '--model <model>',
699
+ 'OpenAI model to use'
700
+ ],
701
+ [
702
+ '--openai-reasoning <level>',
703
+ 'OpenAI reasoning level (low, medium, high)'
704
+ ],
705
+ [
706
+ '--openai-max-output-tokens <tokens>',
707
+ 'OpenAI maximum output tokens'
708
+ ],
709
+ [
710
+ '-d, --context-directories [contextDirectories...]',
711
+ 'directories to scan for context'
712
+ ],
713
+ [
714
+ '--config-dir <configDir>',
715
+ 'configuration directory'
716
+ ],
717
+ [
718
+ '--excluded-paths [excludedPatterns...]',
719
+ 'paths to exclude from the diff'
720
+ ],
721
+ [
722
+ '-h, --help',
723
+ 'display help for command'
724
+ ]
725
+ ];
726
+ const formatOptionsSection = (title, options)=>{
727
+ const maxWidth = Math.max(...options.map(([flag])=>flag.length));
728
+ return `${title}:\n` + options.map(([flag, desc])=>` ${flag.padEnd(maxWidth + 2)} ${desc}`).join('\n') + '\n';
729
+ };
730
+ return nameAndVersion + '\n' + formatOptionsSection('Commit Message Options', commitOptions) + '\n' + formatOptionsSection('Behavioral Options', behavioralOptions) + '\n' + formatOptionsSection('AI Options', aiOptions) + '\n' + formatOptionsSection('Global Options', globalOptions) + '\n' + 'Environment Variables:\n' + ' OPENAI_API_KEY OpenAI API key (required)\n';
731
+ }
732
+ });
733
+ 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('--file <file>', 'audio file path').description('Record audio to provide context, then generate and optionally commit with AI-generated message');
734
+ addSharedOptions(audioCommitCommand);
735
+ 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').option('--context-files [contextFiles...]', 'files containing additional context for release notes').option('--interactive', 'Present release notes for interactive review and editing').option('--max-diff-bytes <maxDiffBytes>', 'maximum bytes per file in diff (default: 2048)').option('--no-milestones', 'disable GitHub milestone integration').option('--from-main', 'force comparison against main branch instead of previous release tag').option('--self-reflection', 'generate self-reflection report with tool effectiveness analysis').option('--max-agentic-iterations <maxAgenticIterations>', 'maximum iterations for analysis (default: 30)', parseInt).description('Generate release notes');
736
+ addSharedOptions(releaseCommand);
737
+ const publishCommand = program.command('publish').option('--merge-method <method>', 'method to merge PR (merge, squash, rebase)', 'squash').option('--from <from>', 'branch/tag to generate release notes from (default: previous release tag)').option('--target-version <targetVersion>', 'target version for release (explicit version like "4.30.0" or semantic bump: "patch", "minor", "major")').option('--context-files [contextFiles...]', 'files containing additional context for release notes').option('--interactive', 'present release notes for interactive review and editing').option('--sendit', 'skip all confirmation prompts and proceed automatically').option('--sync-target', 'attempt to automatically sync target branch with remote before publishing').option('--skip-already-published', 'skip packages that are already published at target version on npm').option('--force-republish', 'delete existing tags and force republish even if tag exists').option('--no-milestones', 'disable GitHub milestone integration').option('--from-main', 'force comparison against main branch instead of previous release tag').option('--update-deps <scope>', 'update inter-project dependencies before publish (e.g., --update-deps @fjell)').option('--self-reflection', 'generate self-reflection report with tool effectiveness analysis').option('--max-agentic-iterations <maxAgenticIterations>', 'maximum iterations for analysis (default: 30)', parseInt).option('--agentic-publish', 'use AI agent to automatically diagnose and fix publish issues').option('--agentic-publish-max-iterations <agenticPublishMaxIterations>', 'maximum iterations for agentic publish (default: 10)', parseInt).description('Publish a release');
738
+ addSharedOptions(publishCommand);
739
+ const treeCommand = program.command('tree [command] [packageArgument]').option('--directory <directory>', 'target directory containing multiple packages (defaults to current directory)').option('--directories [directories...]', 'target directories containing multiple packages (defaults to current directory)').option('--start-from <startFrom>', 'resume execution from this package directory name (useful for restarting failed builds)').option('--stop-at <stopAt>', 'stop execution at this package directory name (the specified package will not be executed)').option('--cmd <cmd>', 'shell command to execute in each package directory (e.g., "npm install", "git status")')// Parallel Execution Options
740
+ .option('--parallel', 'execute packages in parallel when dependencies allow (packages with no interdependencies run simultaneously)').option('--max-concurrency <number>', 'maximum number of packages to execute concurrently (default: number of CPU cores)', parseInt).option('--max-retries <number>', 'maximum retry attempts for failed packages (default: 3)', parseInt).option('--retry-delay <ms>', 'initial retry delay in milliseconds (default: 5000)', parseInt)// Recovery & Status Options
741
+ .option('--continue', 'continue from previous tree publish execution using saved checkpoint state').option('--status', 'check status of running tree publish processes').option('--status-parallel', 'show detailed parallel execution status with package states, timing, and errors').option('--audit-branches', 'audit git branch state across all packages (checks branch consistency, merge conflicts with target, existing PRs, sync status, unpushed commits)').option('--promote <packageName>', 'mark a package as completed in the execution context (useful for recovery after timeouts)').option('--mark-completed <packages>', 'mark packages as completed using directory names (comma-separated, for recovery)').option('--skip <packages>', 'skip packages and their dependents (comma-separated)').option('--retry-failed', 'retry all previously failed packages from checkpoint').option('--skip-failed', 'skip failed packages and continue with remaining packages').option('--validate-state', 'validate checkpoint state integrity before continuing').option('--order', 'show package execution order (topological sort based on dependencies)')// Package Filtering
742
+ .option('--excluded-patterns [excludedPatterns...]', 'patterns to exclude packages from processing (e.g., "**/node_modules/**", "dist/*")')// Link/Unlink Options
743
+ .option('--clean-node-modules', 'for unlink command: remove node_modules and package-lock.json, then reinstall dependencies')// Command-specific options (forwarded to commit/release/publish)
744
+ .option('--context-files [contextFiles...]', 'files containing additional context (forwarded to commit/release/publish)').option('--self-reflection', 'generate self-reflection report (forwarded to commit/release/publish)').option('--max-agentic-iterations <iterations>', 'maximum iterations for AI analysis (forwarded to commit/release/publish)', parseInt).description(`Analyze package dependencies in workspace and execute commands in dependency order.
745
+
746
+ Built-in commands:
747
+ commit - Run 'kodrdriv commit' in each package
748
+ publish - Run 'kodrdriv publish' in each package (supports --parallel)
749
+ precommit - Run precommit checks (lint -> build -> test) in each package
750
+ link - Create file: dependencies for local development
751
+ unlink - Restore npm registry dependencies
752
+ development - Switch to development branch with version bump
753
+ branches - Show branch information for all packages
754
+ run - Execute custom shell command (use --cmd)
755
+ checkout - Checkout specified branch in all packages
756
+
757
+ Command-specific options:
758
+ You can pass any commit, release, or publish options and they will be forwarded.
759
+ Examples: --context-files, --sendit, --interactive, --self-reflection
760
+
761
+ For commit options: kodrdriv commit --help
762
+ For release options: kodrdriv release --help
763
+ For publish options: kodrdriv publish --help
764
+
765
+ Examples:
766
+ kodrdriv tree commit --context-files IMPL.md --sendit
767
+ kodrdriv tree publish --parallel --context-files RELEASE.md
768
+ kodrdriv tree publish --parallel --model "gpt-4o" --self-reflection
769
+ kodrdriv tree --cmd "npm test"
770
+ kodrdriv tree publish --continue --retry-failed
771
+ kodrdriv tree publish --audit-branches
772
+ kodrdriv tree publish --status-parallel
773
+ kodrdriv tree --order`);
774
+ addSharedOptions(treeCommand);
775
+ const linkCommand = program.command('link [packageArgument]').option('--scope-roots <scopeRoots>', 'JSON mapping of scopes to root directories (e.g., \'{"@company": "../"}\')').description('Create npm file: dependencies for local development');
776
+ addSharedOptions(linkCommand);
777
+ const unlinkCommand = program.command('unlink [packageArgument]').option('--scope-roots <scopeRoots>', 'JSON mapping of scopes to root directories (e.g., \'{"@company": "../"}\')').option('--clean-node-modules', 'remove node_modules and package-lock.json, then reinstall dependencies').description('Restore original dependencies and rebuild node_modules');
778
+ addSharedOptions(unlinkCommand);
779
+ 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('--file <file>', 'audio file path').option('--directory <directory>', 'directory containing audio files to process').option('--max-recording-time <time>', 'maximum recording time in seconds', parseInt).option('--sendit', 'Create GitHub issues automatically without confirmation').description('Record audio, transcribe with Whisper, and analyze for project issues using AI');
780
+ addSharedOptions(audioReviewCommand);
781
+ 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('--file <file>', 'read review note from a file').option('--directory <directory>', 'process all review files in a directory').option('--sendit', 'Create GitHub issues automatically without confirmation').option('--editor-timeout <timeout>', 'timeout for editor in milliseconds (default: no timeout)', parseInt).description('Analyze review note for project issues using AI');
782
+ addSharedOptions(reviewCommand);
783
+ // Customize help output for review command
784
+ reviewCommand.configureHelp({
785
+ formatHelp: (cmd, helper)=>{
786
+ const nameAndVersion = `kodrdriv review [note] [options]\n\nAnalyze review note for project issues using AI\n`;
787
+ const argumentsSection = [
788
+ [
789
+ 'note',
790
+ 'review note to analyze for project issues (can also be piped via STDIN)'
791
+ ]
792
+ ];
793
+ const reviewOptions = [
794
+ [
795
+ '--context <context>',
796
+ 'additional context for the review'
797
+ ],
798
+ [
799
+ '--file <file>',
800
+ 'read review note from a file'
801
+ ],
802
+ [
803
+ '--directory <directory>',
804
+ 'process all review files in a directory'
805
+ ]
806
+ ];
807
+ const gitContextOptions = [
808
+ [
809
+ '--include-commit-history',
810
+ 'include recent commit log messages in context (default: true)'
811
+ ],
812
+ [
813
+ '--no-include-commit-history',
814
+ 'exclude commit log messages from context'
815
+ ],
816
+ [
817
+ '--include-recent-diffs',
818
+ 'include recent commit diffs in context (default: true)'
819
+ ],
820
+ [
821
+ '--no-include-recent-diffs',
822
+ 'exclude recent diffs from context'
823
+ ],
824
+ [
825
+ '--include-release-notes',
826
+ 'include recent release notes in context (default: false)'
827
+ ],
828
+ [
829
+ '--no-include-release-notes',
830
+ 'exclude release notes from context'
831
+ ],
832
+ [
833
+ '--include-github-issues',
834
+ 'include open GitHub issues in context (default: true)'
835
+ ],
836
+ [
837
+ '--no-include-github-issues',
838
+ 'exclude GitHub issues from context'
839
+ ],
840
+ [
841
+ '--commit-history-limit <limit>',
842
+ 'number of recent commits to include'
843
+ ],
844
+ [
845
+ '--diff-history-limit <limit>',
846
+ 'number of recent commit diffs to include'
847
+ ],
848
+ [
849
+ '--release-notes-limit <limit>',
850
+ 'number of recent release notes to include'
851
+ ],
852
+ [
853
+ '--github-issues-limit <limit>',
854
+ 'number of open GitHub issues to include (max 20)'
855
+ ]
856
+ ];
857
+ const behavioralOptions = [
858
+ [
859
+ '--sendit',
860
+ 'Create GitHub issues automatically without confirmation'
861
+ ]
862
+ ];
863
+ const globalOptions = [
864
+ [
865
+ '--dry-run',
866
+ 'perform a dry run without saving files'
867
+ ],
868
+ [
869
+ '--verbose',
870
+ 'enable verbose logging'
871
+ ],
872
+ [
873
+ '--debug',
874
+ 'enable debug logging'
875
+ ],
876
+ [
877
+ '--overrides',
878
+ 'enable overrides'
879
+ ],
880
+ [
881
+ '--model <model>',
882
+ 'OpenAI model to use'
883
+ ],
884
+ [
885
+ '--openai-reasoning <level>',
886
+ 'OpenAI reasoning level (low, medium, high)'
887
+ ],
888
+ [
889
+ '--openai-max-output-tokens <tokens>',
890
+ 'OpenAI maximum output tokens'
891
+ ],
892
+ [
893
+ '-d, --context-directories [contextDirectories...]',
894
+ 'directories to scan for context'
895
+ ],
896
+ [
897
+ '--config-dir <configDir>',
898
+ 'configuration directory'
899
+ ],
900
+ [
901
+ '--output-dir <outputDir>',
902
+ 'output directory for generated files'
903
+ ],
904
+ [
905
+ '--excluded-paths [excludedPatterns...]',
906
+ 'paths to exclude from the diff'
907
+ ],
908
+ [
909
+ '-h, --help',
910
+ 'display help for command'
911
+ ]
912
+ ];
913
+ const formatOptionsSection = (title, options)=>{
914
+ const maxWidth = Math.max(...options.map(([flag])=>flag.length));
915
+ return `${title}:\n` + options.map(([flag, desc])=>` ${flag.padEnd(maxWidth + 2)} ${desc}`).join('\n') + '\n';
916
+ };
917
+ 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) + '\n' + 'Environment Variables:\n' + ' OPENAI_API_KEY OpenAI API key (required)\n';
918
+ }
919
+ });
920
+ const cleanCommand = program.command('clean').description('Remove the output directory and all generated files');
921
+ addSharedOptions(cleanCommand);
922
+ const pullCommand = program.command('pull').option('--remote <remote>', 'remote to pull from (default: origin)', 'origin').option('--branch <branch>', 'branch to pull (default: current branch)').option('--no-auto-stash', 'do not auto-stash local changes').option('--no-auto-resolve', 'do not auto-resolve common conflicts').description('Smart pull from remote with auto-conflict resolution for common files (package-lock.json, dist/, etc.)');
923
+ addSharedOptions(pullCommand);
924
+ const precommitCommand = program.command('precommit').option('--fix', 'Attempt to auto-fix linting issues before running precommit checks').description('Run precommit checks (lint -> build -> test) with optimization');
925
+ addSharedOptions(precommitCommand);
926
+ const developmentCommand = program.command('development').option('--target-version <targetVersion>', 'target version bump type (patch, minor, major) or explicit version (e.g., "2.1.0")', 'patch').option('--no-milestones', 'disable GitHub milestone integration').option('--tag-working-branch', 'tag working branch with release version before bumping to dev (default: true)').option('--no-tag-working-branch', 'skip tagging working branch').option('--create-retroactive-tags', 'create tags for past releases found in git history (one-time operation)').option('--working-tag-prefix <prefix>', 'tag prefix for working branch tags (default: "working/")').description('Switch to working branch and set up development version');
927
+ addSharedOptions(developmentCommand);
928
+ const versionsCommand = program.command('versions <subcommand>').option('--directories [directories...]', 'directories to scan for packages (defaults to current directory)').description('Update dependency versions across packages. Subcommands: minor');
929
+ addSharedOptions(versionsCommand);
930
+ const updatesCommand = program.command('updates [scope]').option('--directories [directories...]', 'directories to scan for packages (tree mode, defaults to current directory)').option('--inter-project', 'update inter-project dependencies based on tree state (requires --scope)').option('--report', 'generate a dependency analysis report instead of updating').option('--analyze', 'run AI-powered analysis on the dependency report to get upgrade recommendations').option('--strategy <strategy>', 'strategy for analyze mode: latest, conservative, or compatible', 'latest').description('Update dependencies matching a specific scope using npm-check-updates (e.g., kodrdriv updates @fjell) or update inter-project dependencies (kodrdriv updates --inter-project @fjell)');
931
+ addSharedOptions(updatesCommand);
932
+ const selectAudioCommand = program.command('select-audio').description('Interactively select and save audio device for recording');
933
+ addSharedOptions(selectAudioCommand);
934
+ program.parse();
935
+ const cliArgs = program.opts(); // Get all opts initially
936
+ // Determine which command is being run
937
+ let commandName = DEFAULT_COMMAND;
938
+ let commandOptions = {}; // Store specific command options
939
+ if (program.args.length > 0) {
940
+ commandName = program.args[0];
941
+ validateCommand(commandName);
942
+ }
943
+ // Only proceed with command-specific options if validation passed
944
+ if (ALLOWED_COMMANDS.includes(commandName)) {
945
+ var _chosen_commitCommand, _chosen_commit, _chosen_audioCommitCommand, _chosen_releaseCommand, _chosen_publishCommand, _chosen_treeCommand, _chosen_linkCommand, _chosen_unlinkCommand, _chosen_audioReviewCommand, _chosen_reviewCommand, _chosen_review, _chosen_cleanCommand, _chosen_precommitCommand, _chosen_developmentCommand, _chosen_versionsCommand, _chosen_updatesCommand, _chosen_selectAudioCommand;
946
+ const chosen = {
947
+ commitCommand,
948
+ audioCommitCommand,
949
+ releaseCommand,
950
+ publishCommand,
951
+ treeCommand,
952
+ linkCommand,
953
+ unlinkCommand,
954
+ audioReviewCommand,
955
+ reviewCommand,
956
+ cleanCommand,
957
+ precommitCommand,
958
+ developmentCommand,
959
+ versionsCommand,
960
+ updatesCommand,
961
+ selectAudioCommand
962
+ };
963
+ if (commandName === 'commit' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_commitCommand = chosen.commitCommand) === null || _chosen_commitCommand === void 0 ? void 0 : _chosen_commitCommand.opts)) {
964
+ const commitCmd = chosen.commitCommand;
965
+ commandOptions = commitCmd.opts();
966
+ // Handle positional argument for direction
967
+ // Try to get direction from program.args (after the command name)
968
+ if (program.args.length > 1) {
969
+ commandOptions.direction = program.args[1];
970
+ }
971
+ // Also try commitCommand.args as fallback
972
+ const args = commitCmd.args;
973
+ if (Array.isArray(args) && args.length > 0) {
974
+ const firstTruthyArg = args.find((arg)=>arg);
975
+ if (firstTruthyArg) {
976
+ commandOptions.direction = firstTruthyArg;
977
+ }
978
+ }
979
+ // Final fallback: use locally constructed commit command's args
980
+ if (!commandOptions.direction) {
981
+ const localArgs = commitCommand === null || commitCommand === void 0 ? void 0 : commitCommand.args;
982
+ if (Array.isArray(localArgs) && localArgs.length > 0) {
983
+ const firstLocalArg = localArgs.find((arg)=>arg);
984
+ if (firstLocalArg) {
985
+ commandOptions.direction = firstLocalArg;
986
+ }
987
+ }
988
+ }
989
+ // Check for STDIN input for direction (takes precedence over positional argument)
990
+ const stdinInput = await readStdin();
991
+ if (typeof stdinInput === 'string') {
992
+ commandOptions.direction = stdinInput;
993
+ }
994
+ } else if (commandName === 'commit' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_commit = chosen.commit) === null || _chosen_commit === void 0 ? void 0 : _chosen_commit.opts)) {
995
+ // Fallback when a test/mocked commands object provides 'commit' instead of 'commitCommand'
996
+ const commitCmd = chosen.commit;
997
+ commandOptions = commitCmd.opts();
998
+ if (program.args.length > 1) {
999
+ commandOptions.direction = program.args[1];
1000
+ }
1001
+ const args = commitCmd.args;
1002
+ if (Array.isArray(args) && args.length > 0) {
1003
+ const firstTruthyArg = args.find((arg)=>arg);
1004
+ if (firstTruthyArg) {
1005
+ commandOptions.direction = firstTruthyArg;
1006
+ }
1007
+ }
1008
+ if (!commandOptions.direction) {
1009
+ const localArgs = commitCommand === null || commitCommand === void 0 ? void 0 : commitCommand.args;
1010
+ if (Array.isArray(localArgs) && localArgs.length > 0) {
1011
+ const firstLocalArg = localArgs.find((arg)=>arg);
1012
+ if (firstLocalArg) {
1013
+ commandOptions.direction = firstLocalArg;
1014
+ }
1015
+ }
1016
+ }
1017
+ const stdinInput = await readStdin();
1018
+ if (typeof stdinInput === 'string') {
1019
+ commandOptions.direction = stdinInput;
1020
+ }
1021
+ } else if (commandName === 'audio-commit' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_audioCommitCommand = chosen.audioCommitCommand) === null || _chosen_audioCommitCommand === void 0 ? void 0 : _chosen_audioCommitCommand.opts)) {
1022
+ const audioCommitCmd = chosen.audioCommitCommand;
1023
+ commandOptions = audioCommitCmd.opts();
1024
+ } else if (commandName === 'release' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_releaseCommand = chosen.releaseCommand) === null || _chosen_releaseCommand === void 0 ? void 0 : _chosen_releaseCommand.opts)) {
1025
+ const releaseCmd = chosen.releaseCommand;
1026
+ commandOptions = releaseCmd.opts();
1027
+ } else if (commandName === 'publish' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_publishCommand = chosen.publishCommand) === null || _chosen_publishCommand === void 0 ? void 0 : _chosen_publishCommand.opts)) {
1028
+ const publishCmd = chosen.publishCommand;
1029
+ commandOptions = publishCmd.opts();
1030
+ } else if (commandName === 'tree' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_treeCommand = chosen.treeCommand) === null || _chosen_treeCommand === void 0 ? void 0 : _chosen_treeCommand.opts)) {
1031
+ const treeCmd = chosen.treeCommand;
1032
+ commandOptions = treeCmd.opts();
1033
+ // Handle positional arguments for built-in command and package argument
1034
+ const args = treeCmd.args;
1035
+ if (Array.isArray(args) && args.length > 0) {
1036
+ const firstTruthyArg = args.find((arg)=>arg);
1037
+ if (firstTruthyArg) {
1038
+ commandOptions.builtInCommand = firstTruthyArg;
1039
+ if ((firstTruthyArg === 'link' || firstTruthyArg === 'unlink' || firstTruthyArg === 'run' || firstTruthyArg === 'checkout' || firstTruthyArg === 'updates') && args.length > 1) {
1040
+ const secondTruthyArg = args.slice(1).find((arg)=>arg);
1041
+ if (secondTruthyArg) {
1042
+ commandOptions.packageArgument = secondTruthyArg;
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+ const stdinInput = await readStdin();
1048
+ if (typeof stdinInput === 'string') {
1049
+ commandOptions.builtInCommand = stdinInput.trim().split('\n')[0] || commandOptions.builtInCommand;
1050
+ const stdinLines = stdinInput.split('\n');
1051
+ if (stdinLines[1]) {
1052
+ commandOptions.packageArgument = stdinLines[1];
1053
+ }
1054
+ }
1055
+ } else if (commandName === 'link' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_linkCommand = chosen.linkCommand) === null || _chosen_linkCommand === void 0 ? void 0 : _chosen_linkCommand.opts)) {
1056
+ const linkCmd = chosen.linkCommand;
1057
+ commandOptions = linkCmd.opts();
1058
+ const args = linkCmd.args;
1059
+ if (Array.isArray(args) && args.length > 0) {
1060
+ const firstTruthyArg = args.find((arg)=>arg);
1061
+ if (firstTruthyArg) {
1062
+ commandOptions.packageArgument = firstTruthyArg === 'status' ? 'status' : firstTruthyArg;
1063
+ }
1064
+ }
1065
+ const stdinInput = await readStdin();
1066
+ if (typeof stdinInput === 'string') {
1067
+ commandOptions.packageArgument = stdinInput;
1068
+ }
1069
+ } else if (commandName === 'unlink' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_unlinkCommand = chosen.unlinkCommand) === null || _chosen_unlinkCommand === void 0 ? void 0 : _chosen_unlinkCommand.opts)) {
1070
+ const unlinkCmd = chosen.unlinkCommand;
1071
+ commandOptions = unlinkCmd.opts();
1072
+ const args = unlinkCmd.args;
1073
+ if (Array.isArray(args) && args.length > 0) {
1074
+ const firstTruthyArg = args.find((arg)=>arg);
1075
+ if (firstTruthyArg) {
1076
+ commandOptions.packageArgument = firstTruthyArg === 'status' ? 'status' : firstTruthyArg;
1077
+ }
1078
+ }
1079
+ const stdinInput = await readStdin();
1080
+ if (typeof stdinInput === 'string') {
1081
+ commandOptions.packageArgument = stdinInput;
1082
+ }
1083
+ } else if (commandName === 'audio-review' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_audioReviewCommand = chosen.audioReviewCommand) === null || _chosen_audioReviewCommand === void 0 ? void 0 : _chosen_audioReviewCommand.opts)) {
1084
+ const audioReviewCmd = chosen.audioReviewCommand;
1085
+ commandOptions = audioReviewCmd.opts();
1086
+ } else if (commandName === 'review' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_reviewCommand = chosen.reviewCommand) === null || _chosen_reviewCommand === void 0 ? void 0 : _chosen_reviewCommand.opts)) {
1087
+ const reviewCmd = chosen.reviewCommand;
1088
+ commandOptions = reviewCmd.opts();
1089
+ const args = reviewCmd.args;
1090
+ if (Array.isArray(args) && args.length > 0) {
1091
+ const firstTruthyArg = args.find((arg)=>arg);
1092
+ if (firstTruthyArg) {
1093
+ commandOptions.note = firstTruthyArg;
1094
+ }
1095
+ }
1096
+ // Final fallback: use locally constructed review command's args
1097
+ if (!commandOptions.note) {
1098
+ const localArgs = reviewCommand === null || reviewCommand === void 0 ? void 0 : reviewCommand.args;
1099
+ if (Array.isArray(localArgs) && localArgs.length > 0) {
1100
+ const firstLocalArg = localArgs.find((arg)=>arg);
1101
+ if (firstLocalArg) {
1102
+ commandOptions.note = firstLocalArg;
1103
+ }
1104
+ }
1105
+ }
1106
+ const stdinInput = await readStdin();
1107
+ if (typeof stdinInput === 'string') {
1108
+ commandOptions.note = stdinInput;
1109
+ }
1110
+ } else if (commandName === 'review' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_review = chosen.review) === null || _chosen_review === void 0 ? void 0 : _chosen_review.opts)) {
1111
+ const reviewCmd = chosen.review;
1112
+ commandOptions = reviewCmd.opts();
1113
+ const args = reviewCmd.args;
1114
+ if (Array.isArray(args) && args.length > 0) {
1115
+ const firstTruthyArg = args.find((arg)=>arg);
1116
+ if (firstTruthyArg) {
1117
+ commandOptions.note = firstTruthyArg;
1118
+ }
1119
+ }
1120
+ const stdinInput = await readStdin();
1121
+ if (typeof stdinInput === 'string') {
1122
+ commandOptions.note = stdinInput;
1123
+ }
1124
+ } else if (commandName === 'clean' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_cleanCommand = chosen.cleanCommand) === null || _chosen_cleanCommand === void 0 ? void 0 : _chosen_cleanCommand.opts)) {
1125
+ const cleanCmd = chosen.cleanCommand;
1126
+ commandOptions = cleanCmd.opts();
1127
+ } else if (commandName === 'precommit' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_precommitCommand = chosen.precommitCommand) === null || _chosen_precommitCommand === void 0 ? void 0 : _chosen_precommitCommand.opts)) {
1128
+ const precommitCmd = chosen.precommitCommand;
1129
+ commandOptions = precommitCmd.opts();
1130
+ } else if (commandName === 'development' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_developmentCommand = chosen.developmentCommand) === null || _chosen_developmentCommand === void 0 ? void 0 : _chosen_developmentCommand.opts)) {
1131
+ const developmentCmd = chosen.developmentCommand;
1132
+ commandOptions = developmentCmd.opts();
1133
+ } else if (commandName === 'versions' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_versionsCommand = chosen.versionsCommand) === null || _chosen_versionsCommand === void 0 ? void 0 : _chosen_versionsCommand.opts)) {
1134
+ const versionsCmd = chosen.versionsCommand;
1135
+ commandOptions = versionsCmd.opts();
1136
+ const args = versionsCmd.args;
1137
+ if (args && args.length > 0 && args[0]) {
1138
+ commandOptions.subcommand = args[0];
1139
+ }
1140
+ } else if (commandName === 'updates' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_updatesCommand = chosen.updatesCommand) === null || _chosen_updatesCommand === void 0 ? void 0 : _chosen_updatesCommand.opts)) {
1141
+ const updatesCmd = chosen.updatesCommand;
1142
+ commandOptions = updatesCmd.opts();
1143
+ const args = updatesCmd.args;
1144
+ if (args && args.length > 0 && args[0]) {
1145
+ commandOptions.scope = args[0];
1146
+ }
1147
+ } else if (commandName === 'select-audio' && (chosen === null || chosen === void 0 ? void 0 : (_chosen_selectAudioCommand = chosen.selectAudioCommand) === null || _chosen_selectAudioCommand === void 0 ? void 0 : _chosen_selectAudioCommand.opts)) {
1148
+ const selectAudioCmd = chosen.selectAudioCommand;
1149
+ commandOptions = selectAudioCmd.opts();
1150
+ } else {
1151
+ // Final fallback
1152
+ commandOptions = program.opts();
1153
+ }
1154
+ }
1155
+ // Include command name in CLI args for merging
1156
+ const finalCliArgs = {
1157
+ ...cliArgs,
1158
+ ...commandOptions
1159
+ };
1160
+ // Final safety fallback for positional arguments when STDIN is null and mocks provide args on constructed commands
1161
+ if (commandName === 'commit' && !finalCliArgs.direction) {
1162
+ const localArgs = commitCommand === null || commitCommand === void 0 ? void 0 : commitCommand.args;
1163
+ if (Array.isArray(localArgs) && localArgs.length > 0) {
1164
+ const firstLocalArg = localArgs.find((arg)=>arg);
1165
+ if (firstLocalArg) {
1166
+ finalCliArgs.direction = firstLocalArg;
1167
+ }
1168
+ }
1169
+ }
1170
+ if (commandName === 'review' && !finalCliArgs.note) {
1171
+ const localArgs = reviewCommand === null || reviewCommand === void 0 ? void 0 : reviewCommand.args;
1172
+ if (Array.isArray(localArgs) && localArgs.length > 0) {
1173
+ const firstLocalArg = localArgs.find((arg)=>arg);
1174
+ if (firstLocalArg) {
1175
+ finalCliArgs.note = firstLocalArg;
1176
+ }
1177
+ }
1178
+ }
1179
+ const commandConfig = {
1180
+ commandName
1181
+ };
1182
+ return [
1183
+ finalCliArgs,
1184
+ commandConfig
1185
+ ];
1186
+ }
1187
+ async function validateAndProcessSecureOptions() {
1188
+ // For check-config and init-config commands, we don't want to throw an error for missing API key
1189
+ const isCheckConfig = process.argv.includes('--check-config');
1190
+ const isInitConfig = process.argv.includes('--init-config');
1191
+ if (!process.env.OPENAI_API_KEY && !isCheckConfig && !isInitConfig) {
1192
+ throw new Error('OpenAI API key is required. Please set the OPENAI_API_KEY environment variable.');
1193
+ }
1194
+ // Prefer CLI key if provided, otherwise use env var (might be undefined for check-config/init-config)
1195
+ const openaiApiKey = process.env.OPENAI_API_KEY;
1196
+ const secureConfig = {
1197
+ openaiApiKey: openaiApiKey
1198
+ };
1199
+ return secureConfig;
1200
+ }
1201
+ // Renamed validation function to reflect its broader role
1202
+ async function validateAndProcessOptions(options) {
1203
+ var _options_dryRun, _options_verbose, _options_debug, _options_overrides, _options_model, _options_openaiReasoning, _options_openaiMaxOutputTokens, _options_outputDirectory, _options_preferencesDirectory, _options_discoveredConfigDirs, _options_resolvedConfigDirs, _options_excludedPatterns, _options_branches;
1204
+ const contextDirectories = await validateContextDirectories(options.contextDirectories || KODRDRIV_DEFAULTS.contextDirectories);
1205
+ const configDir = options.configDirectory || KODRDRIV_DEFAULTS.configDirectory;
1206
+ // Skip config directory validation since Cardigantime handles hierarchical lookup
1207
+ // Ensure all required fields are present and have correct types after merging
1208
+ const finalConfig = {
1209
+ dryRun: (_options_dryRun = options.dryRun) !== null && _options_dryRun !== void 0 ? _options_dryRun : KODRDRIV_DEFAULTS.dryRun,
1210
+ verbose: (_options_verbose = options.verbose) !== null && _options_verbose !== void 0 ? _options_verbose : KODRDRIV_DEFAULTS.verbose,
1211
+ debug: (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : KODRDRIV_DEFAULTS.debug,
1212
+ overrides: (_options_overrides = options.overrides) !== null && _options_overrides !== void 0 ? _options_overrides : KODRDRIV_DEFAULTS.overrides,
1213
+ model: (_options_model = options.model) !== null && _options_model !== void 0 ? _options_model : KODRDRIV_DEFAULTS.model,
1214
+ openaiReasoning: (_options_openaiReasoning = options.openaiReasoning) !== null && _options_openaiReasoning !== void 0 ? _options_openaiReasoning : KODRDRIV_DEFAULTS.openaiReasoning,
1215
+ openaiMaxOutputTokens: (_options_openaiMaxOutputTokens = options.openaiMaxOutputTokens) !== null && _options_openaiMaxOutputTokens !== void 0 ? _options_openaiMaxOutputTokens : KODRDRIV_DEFAULTS.openaiMaxOutputTokens,
1216
+ contextDirectories: contextDirectories,
1217
+ configDirectory: configDir,
1218
+ outputDirectory: (_options_outputDirectory = options.outputDirectory) !== null && _options_outputDirectory !== void 0 ? _options_outputDirectory : KODRDRIV_DEFAULTS.outputDirectory,
1219
+ preferencesDirectory: (_options_preferencesDirectory = options.preferencesDirectory) !== null && _options_preferencesDirectory !== void 0 ? _options_preferencesDirectory : KODRDRIV_DEFAULTS.preferencesDirectory,
1220
+ // Cardigantime-specific properties (from fileValues or defaults)
1221
+ discoveredConfigDirs: (_options_discoveredConfigDirs = options.discoveredConfigDirs) !== null && _options_discoveredConfigDirs !== void 0 ? _options_discoveredConfigDirs : [],
1222
+ resolvedConfigDirs: (_options_resolvedConfigDirs = options.resolvedConfigDirs) !== null && _options_resolvedConfigDirs !== void 0 ? _options_resolvedConfigDirs : [],
1223
+ // Command-specific options - ensure all defaults are present even for partial configs
1224
+ commit: {
1225
+ ...KODRDRIV_DEFAULTS.commit,
1226
+ ...Object.fromEntries(Object.entries(options.commit || {}).filter(([_, v])=>v !== undefined && v !== null))
1227
+ },
1228
+ audioCommit: {
1229
+ ...KODRDRIV_DEFAULTS.audioCommit,
1230
+ ...Object.fromEntries(Object.entries(options.audioCommit || {}).filter(([_, v])=>v !== undefined))
1231
+ },
1232
+ release: {
1233
+ ...KODRDRIV_DEFAULTS.release,
1234
+ ...Object.fromEntries(Object.entries(options.release || {}).filter(([_, v])=>v !== undefined))
1235
+ },
1236
+ audioReview: {
1237
+ ...KODRDRIV_DEFAULTS.audioReview,
1238
+ ...Object.fromEntries(Object.entries(options.audioReview || {}).filter(([_, v])=>v !== undefined))
1239
+ },
1240
+ review: {
1241
+ ...KODRDRIV_DEFAULTS.review,
1242
+ ...Object.fromEntries(Object.entries(options.review || {}).filter(([_, v])=>v !== undefined))
1243
+ },
1244
+ publish: {
1245
+ ...KODRDRIV_DEFAULTS.publish,
1246
+ ...Object.fromEntries(Object.entries(options.publish || {}).filter(([_, v])=>v !== undefined))
1247
+ },
1248
+ link: {
1249
+ ...KODRDRIV_DEFAULTS.link,
1250
+ ...Object.fromEntries(Object.entries(options.link || {}).filter(([_, v])=>v !== undefined))
1251
+ },
1252
+ unlink: {
1253
+ ...KODRDRIV_DEFAULTS.unlink,
1254
+ ...Object.fromEntries(Object.entries(options.unlink || {}).filter(([_, v])=>v !== undefined))
1255
+ },
1256
+ tree: {
1257
+ ...KODRDRIV_DEFAULTS.tree,
1258
+ ...Object.fromEntries(Object.entries(options.tree || {}).filter(([_, v])=>v !== undefined))
1259
+ },
1260
+ development: {
1261
+ ...KODRDRIV_DEFAULTS.development,
1262
+ ...Object.fromEntries(Object.entries(options.development || {}).filter(([_, v])=>v !== undefined))
1263
+ },
1264
+ versions: {
1265
+ ...KODRDRIV_DEFAULTS.versions,
1266
+ ...Object.fromEntries(Object.entries(options.versions || {}).filter(([_, v])=>v !== undefined))
1267
+ },
1268
+ updates: {
1269
+ ...KODRDRIV_DEFAULTS.updates,
1270
+ ...Object.fromEntries(Object.entries(options.updates || {}).filter(([_, v])=>v !== undefined))
1271
+ },
1272
+ excludedPatterns: (_options_excludedPatterns = options.excludedPatterns) !== null && _options_excludedPatterns !== void 0 ? _options_excludedPatterns : KODRDRIV_DEFAULTS.excludedPatterns,
1273
+ branches: (_options_branches = options.branches) !== null && _options_branches !== void 0 ? _options_branches : KODRDRIV_DEFAULTS.branches
1274
+ };
1275
+ // Final validation against the MainConfig shape (optional, cardigantime might handle it)
1276
+ // You could potentially use ConfigShape.parse(finalConfig) here if needed
1277
+ return finalConfig;
1278
+ }
1279
+ // Export for testing
1280
+ function validateCommand(commandName) {
1281
+ if (!ALLOWED_COMMANDS.includes(commandName)) {
1282
+ throw new Error(`Invalid command: ${commandName}, allowed commands: ${ALLOWED_COMMANDS.join(', ')}`);
1283
+ }
1284
+ return commandName;
1285
+ }
1286
+ // Export for testing
1287
+ async function validateContextDirectories(contextDirectories) {
1288
+ const logger = getLogger();
1289
+ const storage = createStorage();
1290
+ // Filter out directories that don't exist
1291
+ const validDirectories = [];
1292
+ for (const dir of contextDirectories){
1293
+ try {
1294
+ if (await storage.isDirectoryReadable(dir)) {
1295
+ validDirectories.push(dir);
1296
+ } else {
1297
+ logger.warn(`DIRECTORY_NOT_READABLE: Directory not readable | Directory: ${dir} | Impact: Cannot scan for packages`);
1298
+ }
1299
+ } catch (error) {
1300
+ logger.warn(`DIRECTORY_VALIDATION_ERROR: Error validating directory | Directory: ${dir} | Error: ${error.message}`);
1301
+ }
1302
+ }
1303
+ return validDirectories;
1304
+ }
1305
+
1306
+ export { configure, getCliConfig, transformCliArgs, validateAndProcessOptions, validateAndProcessSecureOptions, validateCommand, validateContextDirectories };
1307
+ //# sourceMappingURL=arguments.js.map