@eldrforge/kodrdriv 0.0.3 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.kodrdriv/config.yaml +13 -5
- package/.kodrdriv/context/content.md +1 -0
- package/README.md +361 -1
- package/dist/arguments.js +93 -16
- package/dist/arguments.js.map +1 -1
- package/dist/commands/commit.js +15 -8
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/link.js +166 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/publish.js +212 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/unlink.js +177 -0
- package/dist/commands/unlink.js.map +1 -0
- package/dist/constants.js +24 -3
- package/dist/constants.js.map +1 -1
- package/dist/content/diff.js.map +1 -1
- package/dist/content/log.js.map +1 -1
- package/dist/error/ExitError.js.map +1 -1
- package/dist/logging.js.map +1 -1
- package/dist/main.js +11 -2
- package/dist/main.js.map +1 -1
- package/dist/prompt/prompts.js.map +1 -1
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -1
- package/dist/util/child.js.map +1 -1
- package/dist/util/general.js +13 -1
- package/dist/util/general.js.map +1 -1
- package/dist/util/github.js +144 -0
- package/dist/util/github.js.map +1 -0
- package/dist/util/openai.js.map +1 -1
- package/dist/util/storage.js +4 -0
- package/dist/util/storage.js.map +1 -1
- package/package.json +19 -18
- package/vitest.config.ts +7 -4
- package/.kodrdriv/context/people/context.md +0 -5
- package/.kodrdriv/context/projects/context.md +0 -3
- package/.kodrdriv/instructions/INACTIVE-release-pre.md +0 -1
package/.kodrdriv/config.yaml
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
verbose: false
|
|
2
|
-
model: gpt-
|
|
2
|
+
model: gpt-4.1
|
|
3
3
|
contextDirectories:
|
|
4
|
-
- .kodrdriv/context
|
|
5
|
-
- .kodrdriv/context/projects
|
|
4
|
+
- .kodrdriv/context
|
|
6
5
|
commit:
|
|
6
|
+
add: true
|
|
7
7
|
cached: true
|
|
8
8
|
sendit: true
|
|
9
|
-
messageLimit: 10
|
|
10
9
|
release:
|
|
11
10
|
from: main
|
|
12
|
-
to: HEAD
|
|
11
|
+
to: HEAD
|
|
12
|
+
publish:
|
|
13
|
+
mergeMethod: squash
|
|
14
|
+
dependencyUpdatePatterns: ["@theunwalked/*", "@riotprompt/*"]
|
|
15
|
+
requiredEnvVars: ["NODE_AUTH_TOKEN"]
|
|
16
|
+
link:
|
|
17
|
+
scopeRoots:
|
|
18
|
+
"@theunwalked": "../../SemicolonAmbulance"
|
|
19
|
+
"@riotprompt": "../../StJustReckoning"
|
|
20
|
+
workspaceFile: "pnpm-workspace.yaml"
|
|
@@ -0,0 +1 @@
|
|
|
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.
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ This will make the `kodrdriv` command available globally on your system.
|
|
|
14
14
|
|
|
15
15
|
## Commands
|
|
16
16
|
|
|
17
|
-
KodrDriv provides
|
|
17
|
+
KodrDriv provides four main commands:
|
|
18
18
|
|
|
19
19
|
### Commit Command
|
|
20
20
|
|
|
@@ -53,6 +53,115 @@ kodrdriv release
|
|
|
53
53
|
>
|
|
54
54
|
> You can use the `--from` and `--to` options to generate release notes comparing two different releases. For example, to see what changed between v1.0.0 and v1.1.0, you could use `kodrdriv release --from v1.0.0 --to v1.1.0`. This is particularly useful for creating detailed changelogs when preparing release documentation.
|
|
55
55
|
|
|
56
|
+
### Publish Command
|
|
57
|
+
|
|
58
|
+
Automate the entire release process, from dependency updates to GitHub release creation:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
kodrdriv publish
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The `publish` command orchestrates a comprehensive release workflow, designed to ensure a safe and consistent release process. Here's what it does:
|
|
65
|
+
|
|
66
|
+
1. **Dependency Management**: If a `pnpm-workspace.yaml` file is present, it's temporarily renamed to switch from workspace dependencies to registry versions. It then runs `pnpm update --latest` to ensure dependencies are up to date. You can configure specific dependency patterns to update instead of updating all dependencies using the `dependencyUpdatePatterns` configuration option.
|
|
67
|
+
|
|
68
|
+
2. **Pre-flight Checks**: Before committing any changes, it runs the `prepublishOnly` script from your `package.json`. This script should contain your project's pre-flight checks (e.g., `clean`, `lint`, `build`, `test`) to ensure the project is in a good state. **Note**: A `prepublishOnly` script is required in your `package.json` - the publish command will fail if this script is not present.
|
|
69
|
+
|
|
70
|
+
3. **Release Commit**: If there are changes to `package.json` or `pnpm-lock.yaml`, it creates an intelligent commit message for the dependency updates.
|
|
71
|
+
|
|
72
|
+
4. **Version Bump**: It automatically bumps the patch version of your project.
|
|
73
|
+
|
|
74
|
+
5. **Release Notes**: It generates release notes based on the recent changes and saves them to `RELEASE_NOTES.md`.
|
|
75
|
+
|
|
76
|
+
6. **Pull Request Automation**:
|
|
77
|
+
* It pushes the changes and tags to the origin.
|
|
78
|
+
* It creates a new pull request for the release.
|
|
79
|
+
* It waits for all status checks on the pull request to pass.
|
|
80
|
+
* Once checks are complete, it automatically merges the pull request using the configured merge method (default: squash).
|
|
81
|
+
|
|
82
|
+
7. **GitHub Release**: After the PR is merged, it checks out the `main` branch, pulls the latest changes, and creates a new GitHub release with the tag and release notes.
|
|
83
|
+
|
|
84
|
+
8. **New Release Branch**: Finally, it creates and pushes a new release branch for the next version (e.g., `release/0.0.5`).
|
|
85
|
+
|
|
86
|
+
This command is designed for repositories that follow a pull-request-based release workflow with required status checks. It streamlines the process, reducing manual steps and potential for error.
|
|
87
|
+
|
|
88
|
+
> [!TIP]
|
|
89
|
+
> ### Choosing the Right Merge Method
|
|
90
|
+
>
|
|
91
|
+
> The merge method you choose affects your Git history and can impact your team's workflow:
|
|
92
|
+
>
|
|
93
|
+
> - **Squash** (default): Best for keeping a clean, linear history. All commits from the feature branch are combined into a single commit, making it easier to understand what was changed in each release.
|
|
94
|
+
>
|
|
95
|
+
> - **Merge**: Preserves the complete commit history from the feature branch. Use this when you want to maintain detailed development history and individual commit information.
|
|
96
|
+
>
|
|
97
|
+
> - **Rebase**: Creates a linear history without merge commits. The commits from the feature branch are replayed on top of the target branch. This keeps history clean while preserving individual commits.
|
|
98
|
+
>
|
|
99
|
+
> Consider your team's preferences and any branch protection rules when choosing a merge method.
|
|
100
|
+
|
|
101
|
+
### Link Command
|
|
102
|
+
|
|
103
|
+
Manage pnpm workspace links for local development with sibling projects:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
kodrdriv link
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The `link` command automates the creation and management of pnpm workspace configurations for local development. It scans your project's dependencies and automatically discovers matching sibling packages in configured scope directories, then updates your `pnpm-workspace.yaml` file to link them for local development.
|
|
110
|
+
|
|
111
|
+
This is particularly useful when working with monorepos or related packages where you want to use local versions of dependencies instead of published registry versions during development.
|
|
112
|
+
|
|
113
|
+
**How it works:**
|
|
114
|
+
|
|
115
|
+
1. **Dependency Analysis**: Reads your `package.json` and examines all dependencies (including devDependencies and peerDependencies)
|
|
116
|
+
|
|
117
|
+
2. **Scope-based Scanning**: For each configured scope (e.g., `@company`, `@myorg`), it scans the specified root directory to find all available packages by reading their `package.json` files
|
|
118
|
+
|
|
119
|
+
3. **Smart Matching**: Instead of relying on directory naming conventions, it matches dependencies by their actual package names from `package.json`, handling cases where directory names don't match package names
|
|
120
|
+
|
|
121
|
+
4. **Workspace Management**: Updates or creates a `pnpm-workspace.yaml` file with the discovered local packages, preserving any existing workspace configuration
|
|
122
|
+
|
|
123
|
+
**Example Scenario:**
|
|
124
|
+
|
|
125
|
+
Suppose you're working on `@company/api` and it depends on `@company/logging`. Your directory structure might look like:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
workspace/
|
|
129
|
+
├── company-api/ # Contains @company/api
|
|
130
|
+
├── company-logging-lib/ # Contains @company/logging (note: different directory name)
|
|
131
|
+
└── other-project/
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The link command would:
|
|
135
|
+
- Scan `../` for packages with scope `@company`
|
|
136
|
+
- Find `@company/logging` in `../company-logging-lib/`
|
|
137
|
+
- Update `pnpm-workspace.yaml` to include `../company-logging-lib`
|
|
138
|
+
|
|
139
|
+
**Configuration Requirements:**
|
|
140
|
+
|
|
141
|
+
The link command requires scope root mappings to be configured. You can provide these via:
|
|
142
|
+
|
|
143
|
+
1. **Command line**: `--scope-roots '{"@company": "../", "@myorg": "../../"}'`
|
|
144
|
+
2. **Configuration file**: Set `link.scopeRoots` in your `.kodrdriv/config.json`
|
|
145
|
+
|
|
146
|
+
**Dry Run Support:**
|
|
147
|
+
|
|
148
|
+
Use `--dry-run` to preview what packages would be linked without making changes:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
kodrdriv link --scope-roots '{"@company": "../"}' --dry-run
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> [!TIP]
|
|
155
|
+
> ### Best Practices for Link Command
|
|
156
|
+
>
|
|
157
|
+
> - **Use relative paths**: Configure scope roots with relative paths (like `../` or `../../`) to ensure the workspace file works across different environments
|
|
158
|
+
>
|
|
159
|
+
> - **Scope organization**: Group related packages under the same scope (e.g., `@company/api`, `@company/logging`) for easier management
|
|
160
|
+
>
|
|
161
|
+
> - **Version with caution**: Consider whether to commit the generated `pnpm-workspace.yaml` file. You might want to add it to `.gitignore` if it's only for local development
|
|
162
|
+
>
|
|
163
|
+
> - **Multiple scopes**: You can configure multiple scope roots to handle packages from different organizations or teams in the same workspace
|
|
164
|
+
|
|
56
165
|
## Command Line Options
|
|
57
166
|
|
|
58
167
|
KodrDriv provides several command line options to customize its behavior:
|
|
@@ -71,6 +180,180 @@ KodrDriv provides several command line options to customize its behavior:
|
|
|
71
180
|
- `--context <context>`: Provide additional context (as a string or file path) to guide the commit message generation. This context is included in the prompt sent to the AI and can be used to specify the purpose, theme, or any special considerations for the commit.
|
|
72
181
|
- `--message-limit <messageLimit>`: Limit the number of recent commit messages (from git log) to include in the prompt for context (default: 10). This can help focus the AI on the most relevant recent changes.
|
|
73
182
|
|
|
183
|
+
### Publish Command Options
|
|
184
|
+
|
|
185
|
+
- `--merge-method <method>`: Method to merge pull requests during the publish process (default: 'squash')
|
|
186
|
+
- Available methods: 'merge', 'squash', 'rebase'
|
|
187
|
+
- `merge`: Creates a merge commit that combines the feature branch into the target branch
|
|
188
|
+
- `squash`: Combines all commits from the feature branch into a single commit on the target branch
|
|
189
|
+
- `rebase`: Replays commits from the feature branch onto the target branch without creating a merge commit
|
|
190
|
+
|
|
191
|
+
#### Dependency Update Configuration
|
|
192
|
+
|
|
193
|
+
The publish command supports selective dependency updates through the `dependencyUpdatePatterns` configuration option. This allows you to specify which dependencies should be updated during the release process instead of updating all dependencies.
|
|
194
|
+
|
|
195
|
+
**Configuration:**
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"publish": {
|
|
199
|
+
"dependencyUpdatePatterns": ["@company/*", "@myorg/*", "specific-package"]
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Behavior:**
|
|
205
|
+
- When patterns are specified, only dependencies matching those patterns will be updated
|
|
206
|
+
- Patterns can include npm scopes (e.g., `@company/*`) or specific package names
|
|
207
|
+
- If no patterns are configured, all dependencies are updated (default behavior)
|
|
208
|
+
- This is particularly useful when developing a set of related packages where you want to ensure you're using the latest versions of your organization's packages while keeping other dependencies stable
|
|
209
|
+
|
|
210
|
+
#### Environment Variable Configuration
|
|
211
|
+
|
|
212
|
+
The publish command includes comprehensive environment variable validation to ensure all required credentials and tokens are available before starting the release process. This prevents failures partway through the publication workflow.
|
|
213
|
+
|
|
214
|
+
**Core Required Environment Variables:**
|
|
215
|
+
|
|
216
|
+
The following environment variables are required by default for all publish operations:
|
|
217
|
+
|
|
218
|
+
- `GITHUB_TOKEN`: Required for GitHub API operations (creating pull requests, releases, etc.)
|
|
219
|
+
- `OPENAI_API_KEY`: Required for AI-powered commit message and release note generation
|
|
220
|
+
|
|
221
|
+
**Configurable Additional Environment Variables:**
|
|
222
|
+
|
|
223
|
+
You can specify additional required environment variables specific to your project or organization:
|
|
224
|
+
|
|
225
|
+
**Configuration (config.yaml):**
|
|
226
|
+
```yaml
|
|
227
|
+
publish:
|
|
228
|
+
requiredEnvVars:
|
|
229
|
+
- NODE_AUTH_TOKEN # Often needed for publishing to npm
|
|
230
|
+
- DEPLOY_KEY # Custom deployment credentials
|
|
231
|
+
- CUSTOM_API_TOKEN # Organization-specific tokens
|
|
232
|
+
- CODECOV_TOKEN # Code coverage reporting
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Configuration (config.json):**
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"publish": {
|
|
239
|
+
"requiredEnvVars": [
|
|
240
|
+
"NODE_AUTH_TOKEN",
|
|
241
|
+
"DEPLOY_KEY",
|
|
242
|
+
"CUSTOM_API_TOKEN",
|
|
243
|
+
"CODECOV_TOKEN"
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Automatic .npmrc Scanning:**
|
|
250
|
+
|
|
251
|
+
The publish command automatically scans your `.npmrc` file for environment variable references and includes them in the validation. It detects common patterns like:
|
|
252
|
+
|
|
253
|
+
- `${NODE_AUTH_TOKEN}` - Curly brace syntax
|
|
254
|
+
- `$NODE_AUTH_TOKEN` - Direct variable reference
|
|
255
|
+
|
|
256
|
+
Example `.npmrc` file:
|
|
257
|
+
```
|
|
258
|
+
@myorg:registry=https://npm.pkg.github.com/
|
|
259
|
+
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
In this case, `NODE_AUTH_TOKEN` would be automatically detected and validated.
|
|
263
|
+
|
|
264
|
+
**Validation Behavior:**
|
|
265
|
+
- All environment variable checks happen during the initial prechecks phase
|
|
266
|
+
- If any required environment variables are missing, the publish command fails immediately with a clear error message
|
|
267
|
+
- The error message lists all missing variables at once, making it easy to set them all before retrying
|
|
268
|
+
- Variables from configuration, .npmrc scanning, and core requirements are combined and deduplicated
|
|
269
|
+
|
|
270
|
+
**Example Error:**
|
|
271
|
+
```
|
|
272
|
+
Missing required environment variables: NODE_AUTH_TOKEN, DEPLOY_KEY.
|
|
273
|
+
Please set these environment variables before running publish.
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Security Best Practices:**
|
|
277
|
+
- Store sensitive environment variables in your CI/CD system's secure variable storage
|
|
278
|
+
- Use tools like 1Password CLI, HashiCorp Vault, or similar for local development
|
|
279
|
+
- Never commit environment variables or tokens to your repository
|
|
280
|
+
- Consider using `.env` files (with proper .gitignore configuration) for local development
|
|
281
|
+
|
|
282
|
+
#### prepublishOnly Script Requirement
|
|
283
|
+
|
|
284
|
+
The publish command requires a `prepublishOnly` script to be defined in your `package.json`. This script should contain all the checks and builds necessary to verify your project is ready for release.
|
|
285
|
+
|
|
286
|
+
**Example package.json:**
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"scripts": {
|
|
290
|
+
"prepublishOnly": "pnpm run clean && pnpm run lint && pnpm run build && pnpm run test",
|
|
291
|
+
"clean": "rimraf dist",
|
|
292
|
+
"lint": "eslint src/",
|
|
293
|
+
"build": "tsc",
|
|
294
|
+
"test": "vitest run"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Why prepublishOnly?**
|
|
300
|
+
- The `prepublishOnly` script is an npm/pnpm standard that runs automatically before publishing packages
|
|
301
|
+
- It ensures consistent pre-flight checks regardless of how the package is published
|
|
302
|
+
- It allows projects to define their own specific validation pipeline
|
|
303
|
+
- The publish command validates this script exists during the initial prechecks phase
|
|
304
|
+
|
|
305
|
+
**Common prepublishOnly Patterns:**
|
|
306
|
+
- `"prepublishOnly": "npm run test"` - Run tests only
|
|
307
|
+
- `"prepublishOnly": "npm run build && npm run test"` - Build and test
|
|
308
|
+
- `"prepublishOnly": "npm run lint && npm run build && npm run test"` - Full validation pipeline
|
|
309
|
+
- `"prepublishOnly": "npm run ci"` - Delegate to a CI script that includes all checks
|
|
310
|
+
|
|
311
|
+
If this script is missing, the publish command will fail immediately with a helpful error message explaining the requirement.
|
|
312
|
+
|
|
313
|
+
### Link Command Options
|
|
314
|
+
|
|
315
|
+
- `--scope-roots <scopeRoots>`: JSON mapping of scopes to root directories for package discovery
|
|
316
|
+
- **Format**: `'{"@scope": "path", "@another": "path"}'`
|
|
317
|
+
- **Example**: `'{"@company": "../", "@myorg": "../../packages/"}'`
|
|
318
|
+
- **Required**: At least one scope mapping must be provided
|
|
319
|
+
- `--workspace-file <workspaceFile>`: Path to the workspace file to create/update (default: 'pnpm-workspace.yaml')
|
|
320
|
+
- Can specify custom workspace file names or paths
|
|
321
|
+
- Useful if your project uses non-standard workspace file naming
|
|
322
|
+
|
|
323
|
+
#### Scope Root Configuration
|
|
324
|
+
|
|
325
|
+
The `--scope-roots` option accepts a JSON object mapping package scopes to their corresponding root directories. Each entry tells the link command where to look for packages with that scope.
|
|
326
|
+
|
|
327
|
+
**Configuration Examples:**
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# Single scope
|
|
331
|
+
kodrdriv link --scope-roots '{"@company": "../"}'
|
|
332
|
+
|
|
333
|
+
# Multiple scopes with different paths
|
|
334
|
+
kodrdriv link --scope-roots '{"@company": "../", "@tools": "../../tools/", "@shared": "../shared-packages/"}'
|
|
335
|
+
|
|
336
|
+
# Absolute paths (not recommended for portability)
|
|
337
|
+
kodrdriv link --scope-roots '{"@company": "/Users/dev/projects/company-packages/"}'
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Path Resolution:**
|
|
341
|
+
- Relative paths are resolved from the current working directory
|
|
342
|
+
- Use `../` to scan the parent directory
|
|
343
|
+
- Use `../../` to scan two levels up
|
|
344
|
+
- Multiple levels and subdirectories are supported: `../../company/packages/`
|
|
345
|
+
|
|
346
|
+
**Package Discovery Process:**
|
|
347
|
+
1. For each scope root, the command lists all subdirectories
|
|
348
|
+
2. It reads each subdirectory's `package.json` to get the actual package name
|
|
349
|
+
3. It matches discovered package names against your project's dependencies
|
|
350
|
+
4. Matching packages are added to the workspace configuration
|
|
351
|
+
|
|
352
|
+
This approach handles complex scenarios where:
|
|
353
|
+
- Directory names don't match package names (e.g., `logging-lib` directory contains `@company/logging`)
|
|
354
|
+
- Packages are organized in different directory structures
|
|
355
|
+
- Multiple related packages exist in the same scope root
|
|
356
|
+
|
|
74
357
|
### OpenAI Configuration
|
|
75
358
|
|
|
76
359
|
- `--openai-api-key <key>`: OpenAI API key (can also be set via OPENAI_API_KEY environment variable)
|
|
@@ -131,6 +414,36 @@ kodrdriv commit --context "Refactoring for performance" --message-limit 5
|
|
|
131
414
|
kodrdriv release --context "Quarterly release, focus on stability" --message-limit 20
|
|
132
415
|
```
|
|
133
416
|
|
|
417
|
+
Publish with different merge methods:
|
|
418
|
+
```bash
|
|
419
|
+
# Use default squash merge
|
|
420
|
+
kodrdriv publish
|
|
421
|
+
|
|
422
|
+
# Use merge commit (preserves individual commits)
|
|
423
|
+
kodrdriv publish --merge-method merge
|
|
424
|
+
|
|
425
|
+
# Use rebase (clean linear history)
|
|
426
|
+
kodrdriv publish --merge-method rebase
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Link local packages for development:
|
|
430
|
+
```bash
|
|
431
|
+
# Basic linking with single scope
|
|
432
|
+
kodrdriv link --scope-roots '{"@company": "../"}'
|
|
433
|
+
|
|
434
|
+
# Multiple scopes with different root directories
|
|
435
|
+
kodrdriv link --scope-roots '{"@company": "../", "@tools": "../../tools/"}'
|
|
436
|
+
|
|
437
|
+
# Dry run to preview changes
|
|
438
|
+
kodrdriv link --scope-roots '{"@company": "../"}' --dry-run --verbose
|
|
439
|
+
|
|
440
|
+
# Custom workspace file
|
|
441
|
+
kodrdriv link --scope-roots '{"@company": "../"}' --workspace-file "workspace.yaml"
|
|
442
|
+
|
|
443
|
+
# Real-world example: linking @company packages from company directory
|
|
444
|
+
kodrdriv link --scope-roots '{"@company": "../../company/"}'
|
|
445
|
+
```
|
|
446
|
+
|
|
134
447
|
### Configuration Directory
|
|
135
448
|
|
|
136
449
|
KodrDriv uses a configuration directory to store custom settings, instructions, and other configuration files. You can specify a custom location using the `--config-dir` option:
|
|
@@ -152,9 +465,56 @@ The configuration directory structure is as follows:
|
|
|
152
465
|
│ ├── release.md # Override for release instructions
|
|
153
466
|
│ ├── release-pre.md # Content prepended to default release instructions
|
|
154
467
|
│ └── release-post.md # Content appended to default release instructions
|
|
468
|
+
├── config.json # Main configuration file
|
|
155
469
|
└── ... # Other configuration files
|
|
156
470
|
```
|
|
157
471
|
|
|
472
|
+
### Configuration File
|
|
473
|
+
|
|
474
|
+
You can create a `config.json` file in your `.kodrdriv` directory to set default options for all commands. This allows you to avoid repeating command-line options and ensures consistent behavior across your project.
|
|
475
|
+
|
|
476
|
+
Example configuration file (`.kodrdriv/config.json`):
|
|
477
|
+
|
|
478
|
+
```json
|
|
479
|
+
{
|
|
480
|
+
"model": "gpt-4o-mini",
|
|
481
|
+
"verbose": true,
|
|
482
|
+
"contextDirectories": ["src", "docs"],
|
|
483
|
+
"publish": {
|
|
484
|
+
"mergeMethod": "merge",
|
|
485
|
+
"dependencyUpdatePatterns": ["@company/*", "@myorg/*"],
|
|
486
|
+
"requiredEnvVars": ["NODE_AUTH_TOKEN", "CUSTOM_TOKEN"]
|
|
487
|
+
},
|
|
488
|
+
"commit": {
|
|
489
|
+
"add": true,
|
|
490
|
+
"messageLimit": 5
|
|
491
|
+
},
|
|
492
|
+
"release": {
|
|
493
|
+
"from": "main",
|
|
494
|
+
"to": "HEAD",
|
|
495
|
+
"messageLimit": 10
|
|
496
|
+
},
|
|
497
|
+
"link": {
|
|
498
|
+
"scopeRoots": {
|
|
499
|
+
"@company": "../",
|
|
500
|
+
"@myorg": "../../org-packages/",
|
|
501
|
+
"@tools": "../shared-tools/"
|
|
502
|
+
},
|
|
503
|
+
"workspaceFile": "pnpm-workspace.yaml"
|
|
504
|
+
},
|
|
505
|
+
"excludedPatterns": [
|
|
506
|
+
"node_modules",
|
|
507
|
+
"dist",
|
|
508
|
+
"*.log"
|
|
509
|
+
]
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Configuration options set in the file can be overridden by command-line arguments. The precedence order is:
|
|
514
|
+
1. Command-line arguments (highest priority)
|
|
515
|
+
2. Configuration file
|
|
516
|
+
3. Default values (lowest priority)
|
|
517
|
+
|
|
158
518
|
## Default Instructions
|
|
159
519
|
|
|
160
520
|
KodrDriv comes with default instructions that guide the AI in generating release notes or change logs. These instructions are defined in the source code:
|
package/dist/arguments.js
CHANGED
|
@@ -16,12 +16,20 @@ z.object({
|
|
|
16
16
|
instructions: z.string().optional(),
|
|
17
17
|
configDir: z.string().optional(),
|
|
18
18
|
cached: z.boolean().optional(),
|
|
19
|
+
add: z.boolean().optional(),
|
|
19
20
|
sendit: z.boolean().optional(),
|
|
20
21
|
from: z.string().optional(),
|
|
21
22
|
to: z.string().optional(),
|
|
22
23
|
excludedPatterns: z.array(z.string()).optional(),
|
|
23
24
|
context: z.string().optional(),
|
|
24
|
-
messageLimit: z.number().optional()
|
|
25
|
+
messageLimit: z.number().optional(),
|
|
26
|
+
mergeMethod: z.enum([
|
|
27
|
+
'merge',
|
|
28
|
+
'squash',
|
|
29
|
+
'rebase'
|
|
30
|
+
]).optional(),
|
|
31
|
+
scopeRoots: z.string().optional(),
|
|
32
|
+
workspaceFile: z.string().optional()
|
|
25
33
|
});
|
|
26
34
|
// Function to transform flat CLI args into nested Config structure
|
|
27
35
|
const transformCliArgs = (finalCliArgs)=>{
|
|
@@ -37,8 +45,9 @@ const transformCliArgs = (finalCliArgs)=>{
|
|
|
37
45
|
// Map configDir (CLI) to configDirectory (Cardigantime standard)
|
|
38
46
|
if (finalCliArgs.configDir !== undefined) transformedCliArgs.configDirectory = finalCliArgs.configDir;
|
|
39
47
|
// Nested mappings for 'commit' options
|
|
40
|
-
if (finalCliArgs.cached !== undefined || finalCliArgs.sendit !== undefined) {
|
|
48
|
+
if (finalCliArgs.cached !== undefined || finalCliArgs.sendit !== undefined || finalCliArgs.add !== undefined) {
|
|
41
49
|
transformedCliArgs.commit = {};
|
|
50
|
+
if (finalCliArgs.add !== undefined) transformedCliArgs.commit.add = finalCliArgs.add;
|
|
42
51
|
if (finalCliArgs.cached !== undefined) transformedCliArgs.commit.cached = finalCliArgs.cached;
|
|
43
52
|
if (finalCliArgs.sendit !== undefined) transformedCliArgs.commit.sendit = finalCliArgs.sendit;
|
|
44
53
|
if (finalCliArgs.messageLimit !== undefined) transformedCliArgs.commit.messageLimit = finalCliArgs.messageLimit;
|
|
@@ -52,6 +61,24 @@ const transformCliArgs = (finalCliArgs)=>{
|
|
|
52
61
|
if (finalCliArgs.context !== undefined) transformedCliArgs.release.context = finalCliArgs.context;
|
|
53
62
|
if (finalCliArgs.messageLimit !== undefined) transformedCliArgs.release.messageLimit = finalCliArgs.messageLimit;
|
|
54
63
|
}
|
|
64
|
+
// Nested mappings for 'publish' options
|
|
65
|
+
if (finalCliArgs.mergeMethod !== undefined) {
|
|
66
|
+
transformedCliArgs.publish = {};
|
|
67
|
+
if (finalCliArgs.mergeMethod !== undefined) transformedCliArgs.publish.mergeMethod = finalCliArgs.mergeMethod;
|
|
68
|
+
}
|
|
69
|
+
// Nested mappings for 'link' and 'unlink' options (both use the same configuration)
|
|
70
|
+
if (finalCliArgs.scopeRoots !== undefined || finalCliArgs.workspaceFile !== undefined) {
|
|
71
|
+
transformedCliArgs.link = {};
|
|
72
|
+
if (finalCliArgs.scopeRoots !== undefined) {
|
|
73
|
+
try {
|
|
74
|
+
transformedCliArgs.link.scopeRoots = JSON.parse(finalCliArgs.scopeRoots);
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new Error(`Invalid JSON for scope-roots: ${finalCliArgs.scopeRoots}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (finalCliArgs.workspaceFile !== undefined) transformedCliArgs.link.workspaceFile = finalCliArgs.workspaceFile;
|
|
81
|
+
}
|
|
55
82
|
if (finalCliArgs.excludedPatterns !== undefined) transformedCliArgs.excludedPatterns = finalCliArgs.excludedPatterns;
|
|
56
83
|
// Note: finalCliArgs.openaiApiKey is intentionally omitted here as it belongs to SecureConfig
|
|
57
84
|
return transformedCliArgs;
|
|
@@ -71,14 +98,38 @@ const configure = async (cardigantime)=>{
|
|
|
71
98
|
const transformedCliArgs = transformCliArgs(finalCliArgs);
|
|
72
99
|
logger.debug('Transformed CLI Args for merging: %s', JSON.stringify(transformedCliArgs, null, 2));
|
|
73
100
|
// Get values from config file
|
|
74
|
-
|
|
75
|
-
|
|
101
|
+
// Temporary workaround: Read config file manually due to cardigantime parsing issue
|
|
102
|
+
let fileValues = {};
|
|
103
|
+
// Force manual config reading for now
|
|
104
|
+
const configPath = path.join(process.cwd(), '.kodrdriv', 'config.yaml');
|
|
105
|
+
const storage = create({
|
|
106
|
+
log: logger.info
|
|
107
|
+
});
|
|
108
|
+
const exists = await storage.exists(configPath);
|
|
109
|
+
if (exists) {
|
|
110
|
+
const yaml = await import('js-yaml');
|
|
111
|
+
const configContent = await storage.readFile(configPath, 'utf-8');
|
|
112
|
+
fileValues = yaml.load(configContent);
|
|
113
|
+
// Add the configDirectory since it's not in the config file but is required
|
|
114
|
+
if (!fileValues.configDirectory) {
|
|
115
|
+
fileValues.configDirectory = '.kodrdriv';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Temporarily skip cardigantime validation due to parsing issues
|
|
119
|
+
// await cardigantime.validate(fileValues);
|
|
76
120
|
// Merge configurations: Defaults -> File -> CLI
|
|
121
|
+
// Properly merge the link section to preserve scope roots from config file
|
|
122
|
+
const mergedLink = {
|
|
123
|
+
...KODRDRIV_DEFAULTS.link,
|
|
124
|
+
...fileValues.link,
|
|
125
|
+
...transformedCliArgs.link
|
|
126
|
+
};
|
|
77
127
|
const partialConfig = {
|
|
78
128
|
...KODRDRIV_DEFAULTS,
|
|
79
129
|
...fileValues,
|
|
80
|
-
...transformedCliArgs
|
|
81
|
-
|
|
130
|
+
...transformedCliArgs,
|
|
131
|
+
link: mergedLink
|
|
132
|
+
}; // Cast to Partial<Config> initially
|
|
82
133
|
// Specific validation and processing after merge
|
|
83
134
|
const config = await validateAndProcessOptions(partialConfig);
|
|
84
135
|
logger.verbose('Final configuration: %s', JSON.stringify(config, null, 2));
|
|
@@ -97,24 +148,39 @@ function getCliConfig(program) {
|
|
|
97
148
|
.option('--excluded-paths [excludedPatterns...]', 'paths to exclude from the diff');
|
|
98
149
|
};
|
|
99
150
|
// Add subcommands
|
|
100
|
-
const commitCommand = program.command('commit').option('--cached', 'use cached diff').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');
|
|
151
|
+
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');
|
|
101
152
|
addSharedOptions(commitCommand);
|
|
102
153
|
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');
|
|
103
154
|
addSharedOptions(releaseCommand);
|
|
155
|
+
const publishCommand = program.command('publish').option('--merge-method <method>', 'method to merge PR (merge, squash, rebase)', 'squash').description('Publish a release');
|
|
156
|
+
addSharedOptions(publishCommand);
|
|
157
|
+
const linkCommand = program.command('link').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('Manage pnpm workspace links for local development');
|
|
158
|
+
addSharedOptions(linkCommand);
|
|
159
|
+
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');
|
|
160
|
+
addSharedOptions(unlinkCommand);
|
|
104
161
|
program.parse();
|
|
105
162
|
const cliArgs = program.opts(); // Get all opts initially
|
|
106
163
|
// Determine which command is being run
|
|
107
164
|
let commandName = DEFAULT_COMMAND;
|
|
108
165
|
let commandOptions = {}; // Store specific command options
|
|
109
|
-
if (program.args.length > 0
|
|
166
|
+
if (program.args.length > 0) {
|
|
110
167
|
commandName = program.args[0];
|
|
168
|
+
}
|
|
169
|
+
validateCommand(commandName);
|
|
170
|
+
// Only proceed with command-specific options if validation passed
|
|
171
|
+
if (ALLOWED_COMMANDS.includes(commandName)) {
|
|
111
172
|
if (commandName === 'commit' && commitCommand.opts) {
|
|
112
173
|
commandOptions = commitCommand.opts();
|
|
113
174
|
} else if (commandName === 'release' && releaseCommand.opts) {
|
|
114
175
|
commandOptions = releaseCommand.opts();
|
|
176
|
+
} else if (commandName === 'publish' && publishCommand.opts) {
|
|
177
|
+
commandOptions = publishCommand.opts();
|
|
178
|
+
} else if (commandName === 'link' && linkCommand.opts) {
|
|
179
|
+
commandOptions = linkCommand.opts();
|
|
180
|
+
} else if (commandName === 'unlink' && unlinkCommand.opts) {
|
|
181
|
+
commandOptions = unlinkCommand.opts();
|
|
115
182
|
}
|
|
116
183
|
}
|
|
117
|
-
validateCommand(commandName);
|
|
118
184
|
// Include command name in CLI args for merging
|
|
119
185
|
const finalCliArgs = {
|
|
120
186
|
...cliArgs,
|
|
@@ -141,13 +207,13 @@ async function validateAndProcessSecureOptions() {
|
|
|
141
207
|
}
|
|
142
208
|
// Renamed validation function to reflect its broader role
|
|
143
209
|
async function validateAndProcessOptions(options) {
|
|
144
|
-
var _options_commit, _options_commit1, _options_commit2, _options_commit3, _options_release, _options_release1, _options_release2, _options_release3;
|
|
210
|
+
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;
|
|
145
211
|
const contextDirectories = await validateContextDirectories(options.contextDirectories || KODRDRIV_DEFAULTS.contextDirectories);
|
|
146
212
|
const instructionsPathOrContent = options.instructions || KODRDRIV_DEFAULTS.instructions;
|
|
147
213
|
const instructions = await validateAndReadInstructions(instructionsPathOrContent);
|
|
148
214
|
const configDir = options.configDirectory || KODRDRIV_DEFAULTS.configDirectory;
|
|
149
215
|
await validateConfigDir(configDir); // Keep validation, but maybe remove return if not used elsewhere
|
|
150
|
-
var _options_dryRun, _options_verbose, _options_debug, _options_overrides, _options_model, _options_commit_cached, _options_commit_sendit, _options_commit_messageLimit, _options_release_from, _options_release_to, _options_release_messageLimit, _options_excludedPatterns;
|
|
216
|
+
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;
|
|
151
217
|
// Ensure all required fields are present and have correct types after merging
|
|
152
218
|
const finalConfig = {
|
|
153
219
|
dryRun: (_options_dryRun = options.dryRun) !== null && _options_dryRun !== void 0 ? _options_dryRun : KODRDRIV_DEFAULTS.dryRun,
|
|
@@ -160,10 +226,11 @@ async function validateAndProcessOptions(options) {
|
|
|
160
226
|
configDirectory: configDir,
|
|
161
227
|
// Command-specific options with defaults
|
|
162
228
|
commit: {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
229
|
+
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,
|
|
230
|
+
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,
|
|
231
|
+
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,
|
|
232
|
+
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,
|
|
233
|
+
context: (_options_commit4 = options.commit) === null || _options_commit4 === void 0 ? void 0 : _options_commit4.context
|
|
167
234
|
},
|
|
168
235
|
release: {
|
|
169
236
|
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,
|
|
@@ -171,6 +238,16 @@ async function validateAndProcessOptions(options) {
|
|
|
171
238
|
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,
|
|
172
239
|
context: (_options_release3 = options.release) === null || _options_release3 === void 0 ? void 0 : _options_release3.context
|
|
173
240
|
},
|
|
241
|
+
publish: {
|
|
242
|
+
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,
|
|
243
|
+
dependencyUpdatePatterns: (_options_publish1 = options.publish) === null || _options_publish1 === void 0 ? void 0 : _options_publish1.dependencyUpdatePatterns,
|
|
244
|
+
requiredEnvVars: (_options_publish_requiredEnvVars = (_options_publish2 = options.publish) === null || _options_publish2 === void 0 ? void 0 : _options_publish2.requiredEnvVars) !== null && _options_publish_requiredEnvVars !== void 0 ? _options_publish_requiredEnvVars : KODRDRIV_DEFAULTS.publish.requiredEnvVars
|
|
245
|
+
},
|
|
246
|
+
link: {
|
|
247
|
+
scopeRoots: (_options_link_scopeRoots = (_options_link = options.link) === null || _options_link === void 0 ? void 0 : _options_link.scopeRoots) !== null && _options_link_scopeRoots !== void 0 ? _options_link_scopeRoots : KODRDRIV_DEFAULTS.link.scopeRoots,
|
|
248
|
+
workspaceFile: (_options_link_workspaceFile = (_options_link1 = options.link) === null || _options_link1 === void 0 ? void 0 : _options_link1.workspaceFile) !== null && _options_link_workspaceFile !== void 0 ? _options_link_workspaceFile : KODRDRIV_DEFAULTS.link.workspaceFile,
|
|
249
|
+
dryRun: (_options_link_dryRun = (_options_link2 = options.link) === null || _options_link2 === void 0 ? void 0 : _options_link2.dryRun) !== null && _options_link_dryRun !== void 0 ? _options_link_dryRun : KODRDRIV_DEFAULTS.link.dryRun
|
|
250
|
+
},
|
|
174
251
|
excludedPatterns: (_options_excludedPatterns = options.excludedPatterns) !== null && _options_excludedPatterns !== void 0 ? _options_excludedPatterns : KODRDRIV_DEFAULTS.excludedPatterns
|
|
175
252
|
};
|
|
176
253
|
// Final validation against the MainConfig shape (optional, cardigantime might handle it)
|
|
@@ -258,5 +335,5 @@ async function validateAndReadInstructions(instructionsPath) {
|
|
|
258
335
|
}
|
|
259
336
|
}
|
|
260
337
|
|
|
261
|
-
export { configure, transformCliArgs, validateAndReadInstructions, validateCommand, validateContextDirectories };
|
|
338
|
+
export { configure, getCliConfig, transformCliArgs, validateAndProcessOptions, validateAndProcessSecureOptions, validateAndReadInstructions, validateCommand, validateConfigDir, validateContextDirectories };
|
|
262
339
|
//# sourceMappingURL=arguments.js.map
|