@dezkareid/osddt 1.11.0 → 1.11.2
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/AGENTS.md +53 -62
- package/README.md +31 -22
- package/dist/index.js +222 -165
- package/dist/utils/prompt.d.ts +1 -0
- package/dist/utils/worktree.d.ts +11 -0
- package/package.json +2 -1
- package/dist/commands/setup-worktree.d.ts +0 -2
package/AGENTS.md
CHANGED
|
@@ -111,7 +111,8 @@ osddt/
|
|
|
111
111
|
│ │ ├── claude.ts # Formats COMMAND_DEFINITIONS as Markdown (.claude/commands/osddt.<name>.md)
|
|
112
112
|
│ │ └── gemini.ts # Formats COMMAND_DEFINITIONS as TOML (.gemini/commands/osddt.<name>.toml)
|
|
113
113
|
│ └── utils/
|
|
114
|
-
│
|
|
114
|
+
│ ├── prompt.ts # Inquirer prompts: askAgents() (checkbox), askRepoType() (select), askWorktreeUrl() (input)
|
|
115
|
+
│ └── worktree.ts # Shared worktree helpers: git version check, not-a-worktree check, writable check, state file init
|
|
115
116
|
├── dist/ # Compiled output (single ESM bundle, gitignored)
|
|
116
117
|
├── rollup.config.js # Bundles src/index.ts → dist/index.js (ESM, shebang injected)
|
|
117
118
|
├── tsconfig.json # TypeScript config
|
|
@@ -125,7 +126,7 @@ osddt/
|
|
|
125
126
|
#### Key relationships
|
|
126
127
|
|
|
127
128
|
- **`shared.ts` is the single source of truth** for all command template content. Both `claude.ts` and `gemini.ts` import `COMMAND_DEFINITIONS` from it and only differ in file format (Markdown vs TOML) and argument placeholder (`$ARGUMENTS` vs `{{args}}`).
|
|
128
|
-
- **`setup.ts`** orchestrates setup: reads `--agents`/`--repo-type` flags when provided (non-interactive), otherwise calls `askAgents()` → `askRepoType()` → writes selected agent files → writes `.osddtrc`.
|
|
129
|
+
- **`setup.ts`** orchestrates setup: reads `--agents`/`--repo-type`/`--worktree-repository` flags when provided (non-interactive), otherwise calls `askAgents()` → `askRepoType()` → `askWorktreeUrl()` → if URL provided, runs worktree environment checks via `worktree.ts` → writes selected agent files → writes `.osddtrc`.
|
|
129
130
|
- **`meta-info.ts`** is referenced inside the generated templates so agents can fetch live branch/date at invocation time (not baked in at build time).
|
|
130
131
|
- **Test files** (`.spec.ts`) live next to the source file they cover. Template tests are pure (no mocks); command tests mock `fs-extra` and `child_process`.
|
|
131
132
|
|
|
@@ -146,28 +147,28 @@ The selected agents are saved in `.osddtrc` alongside `repoType`. When `osddt up
|
|
|
146
147
|
|
|
147
148
|
#### Available commands
|
|
148
149
|
|
|
149
|
-
| Command
|
|
150
|
-
|
|
|
151
|
-
| `osddt setup`
|
|
152
|
-
| `osddt setup --agents <list> --repo-type <type>`
|
|
153
|
-
| `
|
|
154
|
-
| `npx @dezkareid/osddt setup
|
|
155
|
-
| `osddt
|
|
156
|
-
| `npx @dezkareid/osddt
|
|
157
|
-
| `osddt
|
|
158
|
-
| `npx @dezkareid/osddt
|
|
159
|
-
| `osddt done <feature-name> --dir <project-path
|
|
160
|
-
| `npx @dezkareid/osddt done <feature-name> --dir <project-path
|
|
161
|
-
| `osddt
|
|
162
|
-
| `npx @dezkareid/osddt
|
|
163
|
-
| `osddt
|
|
164
|
-
| `npx @dezkareid/osddt
|
|
165
|
-
| `osddt start-worktree <feature-name
|
|
166
|
-
| `npx @dezkareid/osddt start-worktree <feature-name
|
|
167
|
-
| `osddt worktree
|
|
168
|
-
| `npx @dezkareid/osddt worktree
|
|
169
|
-
| `osddt
|
|
170
|
-
| `npx @dezkareid/osddt
|
|
150
|
+
| Command | Context | Description |
|
|
151
|
+
| ---------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------- |
|
|
152
|
+
| `osddt setup` | Local dev | Generate agent command files for Claude and Gemini |
|
|
153
|
+
| `osddt setup --agents <list> --repo-type <type>` | Local dev | Non-interactive setup (for CI/scripted environments) |
|
|
154
|
+
| `osddt setup --worktree-repository <url>` | Local dev | Setup with worktree workflow enabled |
|
|
155
|
+
| `npx @dezkareid/osddt setup` | External | Generate agent command files for Claude and Gemini |
|
|
156
|
+
| `npx @dezkareid/osddt setup --agents <list> --repo-type <type>` | External | Non-interactive setup (for CI/scripted environments) |
|
|
157
|
+
| `npx @dezkareid/osddt setup --worktree-repository <url>` | External | Setup with worktree workflow enabled |
|
|
158
|
+
| `osddt meta-info` | Local dev | Output current branch and date as JSON |
|
|
159
|
+
| `npx @dezkareid/osddt meta-info` | External | Output current branch and date as JSON |
|
|
160
|
+
| `osddt done <feature-name> --dir <project-path>` | Local dev | Move `working-on/<feature>` to `done/<feature>` |
|
|
161
|
+
| `npx @dezkareid/osddt done <feature-name> --dir <project-path>` | External | Move `working-on/<feature>` to `done/<feature>` |
|
|
162
|
+
| `osddt done <feature-name> --dir <project-path> --worktree` | Local dev | Archive feature, remove git worktree, and clean state file |
|
|
163
|
+
| `npx @dezkareid/osddt done <feature-name> --dir <project-path> --worktree` | External | Archive feature, remove git worktree, and clean state file |
|
|
164
|
+
| `osddt update` | Local dev | Regenerate agent command files from the existing `.osddtrc` |
|
|
165
|
+
| `npx @dezkareid/osddt update` | External | Regenerate agent command files from the existing `.osddtrc` |
|
|
166
|
+
| `osddt start-worktree <feature-name>` | Local dev | Create a git worktree for a feature and scaffold working-on/ |
|
|
167
|
+
| `npx @dezkareid/osddt start-worktree <feature-name>` | External | Create a git worktree for a feature and scaffold working-on/ |
|
|
168
|
+
| `osddt start-worktree <feature-name> --dir <package-path>` | Local dev | Same, specifying the package path in a monorepo |
|
|
169
|
+
| `npx @dezkareid/osddt start-worktree <feature-name> --dir <package-path>` | External | Same, specifying the package path in a monorepo |
|
|
170
|
+
| `osddt worktree-info <feature-name>` | Local dev | Look up worktree paths for a feature (JSON output) |
|
|
171
|
+
| `npx @dezkareid/osddt worktree-info <feature-name>` | External | Look up worktree paths for a feature (JSON output) |
|
|
171
172
|
|
|
172
173
|
#### `osddt setup` options
|
|
173
174
|
|
|
@@ -175,27 +176,27 @@ The selected agents are saved in `.osddtrc` alongside `repoType`. When `osddt up
|
|
|
175
176
|
| ---- | ------ | ----------- |
|
|
176
177
|
| `--agents <list>` | `claude`, `gemini` (comma-separated) | Skip the agents prompt and use the provided value(s) |
|
|
177
178
|
| `--repo-type <type>` | `single`, `monorepo` | Skip the repo type prompt and use the provided value |
|
|
179
|
+
| `--worktree-repository <url>` | any git URL | Enable worktree workflow; saves URL as `"worktree-repository"` in `.osddtrc` |
|
|
178
180
|
| `-d, --dir <directory>` | any path | Target directory (defaults to current working directory) |
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
All flags are optional. Providing neither runs the fully interactive mode. When `--worktree-repository` is provided, environment checks run and `.osddt-worktrees` is initialised.
|
|
181
183
|
|
|
182
184
|
### Command Templates
|
|
183
185
|
|
|
184
186
|
Templates are generated by `npx @dezkareid/osddt setup` and placed in each agent's commands directory. Each template corresponds to a step in the spec-driven workflow.
|
|
185
187
|
|
|
186
|
-
| Template
|
|
187
|
-
|
|
|
188
|
-
| `osddt.continue`
|
|
189
|
-
| `osddt.research`
|
|
190
|
-
| `osddt.start`
|
|
191
|
-
| `osddt.
|
|
192
|
-
| `osddt.
|
|
193
|
-
| `osddt.
|
|
194
|
-
| `osddt.
|
|
195
|
-
| `osddt.
|
|
196
|
-
| `osddt.
|
|
197
|
-
| `osddt.
|
|
198
|
-
| `osddt.done` | Resolve project path, verify tasks, and move the feature to done |
|
|
188
|
+
| Template | Description |
|
|
189
|
+
| ---------------- | ---------------------------------------------------------------------------------------- |
|
|
190
|
+
| `osddt.continue` | Detect the current workflow phase and prompt the next command |
|
|
191
|
+
| `osddt.research` | Research a topic and write a research file to inform the spec |
|
|
192
|
+
| `osddt.start` | Start a new feature — uses standard or worktree workflow based on `.osddtrc` |
|
|
193
|
+
| `osddt.spec` | Analyze requirements and write a feature specification |
|
|
194
|
+
| `osddt.clarify` | Resolve open questions in the spec and record decisions (optional) |
|
|
195
|
+
| `osddt.plan` | Create a technical implementation plan from a specification |
|
|
196
|
+
| `osddt.tasks` | Generate actionable tasks from an implementation plan |
|
|
197
|
+
| `osddt.implement`| Execute tasks from the task list one by one |
|
|
198
|
+
| `osddt.fast` | Bootstrap all planning artifacts (spec, plan, tasks) in one shot |
|
|
199
|
+
| `osddt.done` | Resolve project path, verify tasks, and move the feature to done |
|
|
199
200
|
|
|
200
201
|
#### Template Workflow
|
|
201
202
|
|
|
@@ -261,18 +262,16 @@ Templates are generated by `npx @dezkareid/osddt setup` and placed in each agent
|
|
|
261
262
|
|
|
262
263
|
##### Example D — Parallel feature workflow (git worktree)
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
Before using worktrees for the first time, validate your environment:
|
|
265
|
+
Enable worktree mode once during setup by providing the repository URL:
|
|
267
266
|
|
|
268
267
|
```bash
|
|
269
|
-
npx @dezkareid/osddt setup-worktree
|
|
268
|
+
npx @dezkareid/osddt setup --agents claude --repo-type single --worktree-repository https://github.com/org/repo.git
|
|
270
269
|
```
|
|
271
270
|
|
|
272
|
-
|
|
271
|
+
From that point on, `/osddt.start` automatically uses the worktree workflow:
|
|
273
272
|
|
|
274
273
|
```
|
|
275
|
-
/osddt.start
|
|
274
|
+
/osddt.start add-payment-gateway
|
|
276
275
|
/osddt.spec
|
|
277
276
|
/osddt.plan use Stripe SDK, REST endpoints
|
|
278
277
|
/osddt.tasks
|
|
@@ -285,7 +284,7 @@ The worktree is created as a sibling of the repo root (e.g. `../my-repo-add-paym
|
|
|
285
284
|
You can customise the worktree base directory via `worktreeBase` in `.osddtrc`:
|
|
286
285
|
|
|
287
286
|
```json
|
|
288
|
-
{ "repoType": "single", "worktreeBase": "/Users/me/worktrees" }
|
|
287
|
+
{ "repoType": "single", "worktree-repository": "https://github.com/org/repo.git", "worktreeBase": "/Users/me/worktrees" }
|
|
289
288
|
```
|
|
290
289
|
|
|
291
290
|
---
|
|
@@ -315,13 +314,16 @@ You can customise the worktree base directory via `worktreeBase` in `.osddtrc`:
|
|
|
315
314
|
|
|
316
315
|
- **Input**: Either a human-readable feature description (e.g. `"Add user authentication"`) or an existing branch name (e.g. `feat/add-user-auth`).
|
|
317
316
|
- **Branch name resolution**: input is used as-is if it looks like a branch name; otherwise a name is derived (lowercased, hyphens, prefixed with `feat/`), subject to the 30-character feature name limit.
|
|
318
|
-
- **
|
|
317
|
+
- **Workflow mode**: determined by reading `.osddtrc`. If `"worktree-repository"` is present, the worktree workflow is used; otherwise the standard branch workflow is used. The user is never prompted to choose.
|
|
318
|
+
- **Standard workflow** (no `"worktree-repository"` in `.osddtrc`):
|
|
319
319
|
1. Checks for an existing branch — offers **Resume** (`git checkout`) or **Abort** if found, otherwise runs `git checkout -b <branch-name>`.
|
|
320
|
-
2.
|
|
321
|
-
3.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
2. Checks for an existing `working-on/<feature-name>/` folder — offers **Resume** or **Abort** if found, otherwise creates it.
|
|
321
|
+
3. Reports the branch and working directory.
|
|
322
|
+
- **Worktree workflow** (`"worktree-repository"` present in `.osddtrc`):
|
|
323
|
+
1. Derives the branch and feature name.
|
|
324
|
+
2. Runs `npx @dezkareid/osddt start-worktree <feature-name> [--dir <package-path>]`.
|
|
325
|
+
3. Navigates into the created worktree directory to locate the project root.
|
|
326
|
+
4. Reports the branch, worktree path, project root, and working directory.
|
|
325
327
|
|
|
326
328
|
#### osddt.research behaviour
|
|
327
329
|
|
|
@@ -343,17 +345,6 @@ You can customise the worktree base directory via `worktreeBase` in `.osddtrc`:
|
|
|
343
345
|
4. Records all new answers in a `## Decisions` section of `osddt.spec.md` and removes each answered question from the **Open Questions** section (removing the section heading too if it becomes empty).
|
|
344
346
|
5. Always prompts the user to run (or re-run) `osddt.plan` to reflect the updated decisions.
|
|
345
347
|
|
|
346
|
-
#### osddt.start-worktree behaviour
|
|
347
|
-
|
|
348
|
-
- **Input**: Either a human-readable feature description or an existing branch name.
|
|
349
|
-
- **Branch name resolution**: same rules as `osddt.start`.
|
|
350
|
-
- **Actions performed by the agent**:
|
|
351
|
-
1. Derives the branch and feature name.
|
|
352
|
-
2. Runs `npx @dezkareid/osddt start-worktree <feature-name> [--dir <package-path>]`.
|
|
353
|
-
3. The CLI creates the git worktree as a sibling of the repo root (`../<repo-name>-<feature-name>`, overridable via `worktreeBase` in `.osddtrc`), scaffolds `working-on/<feature-name>/` inside the worktree, and writes an entry to `.osddt-worktrees` (sibling to repo root).
|
|
354
|
-
4. Reports the branch, worktree path, and working directory.
|
|
355
|
-
5. Next step: `/osddt.spec`.
|
|
356
|
-
|
|
357
348
|
#### osddt.done behaviour
|
|
358
349
|
|
|
359
350
|
- **Input**: None — the feature is identified automatically.
|
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Other spec driven development tool but for monorepo
|
|
|
7
7
|
| -------------------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
8
8
|
| `@dezkareid/osddt setup` | Generate agent command files for Claude and Gemini |
|
|
9
9
|
| `@dezkareid/osddt setup --agents <list> --repo-type <type>` | Non-interactive setup (for CI/scripted environments) |
|
|
10
|
+
| `@dezkareid/osddt setup --worktree-repository <url>` | Setup with worktree workflow enabled |
|
|
10
11
|
| `@dezkareid/osddt meta-info` | Output current branch and date as JSON |
|
|
11
12
|
| `@dezkareid/osddt done <feature-name> --dir <project-path>` | Move `working-on/<feature>` to `done/<feature>` |
|
|
12
13
|
| `@dezkareid/osddt done <feature-name> --dir <project-path> --worktree` | Archive feature, remove git worktree, and clean state file |
|
|
@@ -14,7 +15,6 @@ Other spec driven development tool but for monorepo
|
|
|
14
15
|
| `@dezkareid/osddt start-worktree <feature-name>` | Create a git worktree for a feature and scaffold working-on/ |
|
|
15
16
|
| `@dezkareid/osddt start-worktree <feature-name> --dir <package-path>` | Same, specifying the package path in a monorepo |
|
|
16
17
|
| `@dezkareid/osddt worktree-info <feature-name>` | Look up worktree paths for a feature (JSON output) |
|
|
17
|
-
| `@dezkareid/osddt setup-worktree` | Validate environment for git worktree usage |
|
|
18
18
|
|
|
19
19
|
### `osddt setup` options
|
|
20
20
|
|
|
@@ -22,11 +22,20 @@ Other spec driven development tool but for monorepo
|
|
|
22
22
|
| ---- | ------ | ----------- |
|
|
23
23
|
| `--agents <list>` | `claude`, `gemini` (comma-separated) | Skip the agents prompt and use the provided value(s) |
|
|
24
24
|
| `--repo-type <type>` | `single`, `monorepo` | Skip the repo type prompt and use the provided value |
|
|
25
|
+
| `--worktree-repository <url>` | any git URL | Enable worktree workflow and save the repository URL |
|
|
25
26
|
| `-d, --dir <directory>` | any path | Target directory (defaults to current working directory) |
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
All flags are optional. Providing neither runs the fully interactive mode. Providing `--agents` and `--repo-type` together skips all standard prompts. Adding `--worktree-repository` also runs environment checks and initialises the worktree state file.
|
|
28
29
|
|
|
29
|
-
The selected agents are saved in `.osddtrc`
|
|
30
|
+
The selected agents and config are saved in `.osddtrc` so that `osddt update` can regenerate the correct files without prompting.
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
// Standard mode
|
|
34
|
+
{ "repoType": "single", "agents": ["claude"] }
|
|
35
|
+
|
|
36
|
+
// Worktree mode — the "worktree-repository" field enables the worktree workflow
|
|
37
|
+
{ "repoType": "single", "agents": ["claude"], "worktree-repository": "https://github.com/org/repo.git" }
|
|
38
|
+
```
|
|
30
39
|
|
|
31
40
|
```bash
|
|
32
41
|
# Interactive (default)
|
|
@@ -113,18 +122,16 @@ flowchart LR
|
|
|
113
122
|
|
|
114
123
|
#### Parallel feature workflow (git worktree)
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
Before using worktrees for the first time, validate your environment:
|
|
125
|
+
Enable worktree mode by providing the repository URL during setup:
|
|
119
126
|
|
|
120
127
|
```bash
|
|
121
|
-
npx @dezkareid/osddt setup-worktree
|
|
128
|
+
npx @dezkareid/osddt setup --agents claude --repo-type single --worktree-repository https://github.com/org/repo.git
|
|
122
129
|
```
|
|
123
130
|
|
|
124
|
-
|
|
131
|
+
This saves `"worktree-repository"` in `.osddtrc`, runs environment checks, and initialises the `.osddt-worktrees` state file. From that point on, `/osddt.start` automatically uses the worktree workflow:
|
|
125
132
|
|
|
126
133
|
```
|
|
127
|
-
/osddt.start
|
|
134
|
+
/osddt.start add-payment-gateway
|
|
128
135
|
/osddt.spec
|
|
129
136
|
/osddt.plan use Stripe SDK, REST endpoints
|
|
130
137
|
/osddt.tasks
|
|
@@ -139,12 +146,15 @@ You can customise the worktree base directory by adding `worktreeBase` to `.osdd
|
|
|
139
146
|
```json
|
|
140
147
|
{
|
|
141
148
|
"repoType": "single",
|
|
149
|
+
"worktree-repository": "https://github.com/org/repo.git",
|
|
142
150
|
"worktreeBase": "/Users/me/worktrees"
|
|
143
151
|
}
|
|
144
152
|
```
|
|
145
153
|
|
|
146
154
|
Active worktrees are tracked in `.osddt-worktrees` (sibling to the repo root), a JSON array with entries containing `featureName`, `branch`, `worktreePath`, `workingDir`, and `repoRoot`. This file is the single source of truth used by `osddt.continue` and `osddt.done` to resolve the correct paths.
|
|
147
155
|
|
|
156
|
+
> **Migration note**: If you previously used `osddt setup-worktree` or `/osddt.start-worktree`, those commands have been removed. Re-run `osddt setup --worktree-repository <url>` to configure the new unified workflow. Manually delete any `osddt.start-worktree.*` files from your agent command directories — `osddt update` will not regenerate them.
|
|
157
|
+
|
|
148
158
|
#### Resuming after closing a session
|
|
149
159
|
|
|
150
160
|
```
|
|
@@ -157,19 +167,18 @@ Active worktrees are tracked in `.osddt-worktrees` (sibling to the repo root), a
|
|
|
157
167
|
/osddt.done
|
|
158
168
|
```
|
|
159
169
|
|
|
160
|
-
| Template
|
|
161
|
-
|
|
|
162
|
-
| `osddt.continue`
|
|
163
|
-
| `osddt.research`
|
|
164
|
-
| `osddt.start`
|
|
165
|
-
| `osddt.
|
|
166
|
-
| `osddt.
|
|
167
|
-
| `osddt.
|
|
168
|
-
| `osddt.
|
|
169
|
-
| `osddt.
|
|
170
|
-
| `osddt.
|
|
171
|
-
| `osddt.
|
|
172
|
-
| `osddt.done` | Resolve project path, verify tasks, and move the feature to done |
|
|
170
|
+
| Template | Description |
|
|
171
|
+
| ---------------- | ------------------------------------------------------------------ |
|
|
172
|
+
| `osddt.continue` | Detect the current workflow phase and prompt the next command |
|
|
173
|
+
| `osddt.research` | Research a topic and write a research file to inform the spec |
|
|
174
|
+
| `osddt.start` | Start a new feature — uses standard or worktree workflow based on `.osddtrc` |
|
|
175
|
+
| `osddt.spec` | Analyze requirements and write a feature specification |
|
|
176
|
+
| `osddt.clarify` | Resolve open questions in the spec and record decisions (optional) |
|
|
177
|
+
| `osddt.plan` | Create a technical implementation plan from a specification |
|
|
178
|
+
| `osddt.tasks` | Generate actionable tasks from an implementation plan |
|
|
179
|
+
| `osddt.implement`| Execute tasks from the task list one by one |
|
|
180
|
+
| `osddt.fast` | Bootstrap all planning artifacts (spec, plan, tasks) in one shot |
|
|
181
|
+
| `osddt.done` | Resolve project path, verify tasks, and move the feature to done |
|
|
173
182
|
|
|
174
183
|
Generated files are placed in:
|
|
175
184
|
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,10 @@ import { Command } from 'commander';
|
|
|
3
3
|
import fs from 'fs-extra';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { execSync } from 'child_process';
|
|
6
7
|
import select from '@inquirer/select';
|
|
7
8
|
import checkbox from '@inquirer/checkbox';
|
|
8
|
-
import
|
|
9
|
+
import input from '@inquirer/input';
|
|
9
10
|
import readline from 'readline';
|
|
10
11
|
|
|
11
12
|
function getRepoPreamble(npxCommand) {
|
|
@@ -19,15 +20,22 @@ ${npxCommand} meta-info
|
|
|
19
20
|
|
|
20
21
|
## Repository Configuration
|
|
21
22
|
|
|
22
|
-
Before proceeding, read the \`.osddtrc\` file in the root of the repository to determine the project path.
|
|
23
|
+
Before proceeding, read the \`.osddtrc\` file in the root of the repository to determine the project path and workflow mode.
|
|
23
24
|
|
|
24
25
|
\`\`\`json
|
|
25
|
-
//
|
|
26
|
-
{ "repoType": "monorepo" | "single" }
|
|
26
|
+
// standard mode
|
|
27
|
+
{ "repoType": "monorepo" | "single", "agents": ["claude"] }
|
|
28
|
+
|
|
29
|
+
// worktree mode — "worktree-repository" presence determines the workflow
|
|
30
|
+
{ "repoType": "monorepo" | "single", "agents": ["claude"], "worktree-repository": "https://github.com/org/repo.git" }
|
|
27
31
|
\`\`\`
|
|
28
32
|
|
|
29
33
|
- If \`repoType\` is \`"single"\`: the project path is the repository root.
|
|
30
34
|
- If \`repoType\` is \`"monorepo"\`: ask the user which package to work on (e.g. \`packages/my-package\`), then use \`<repo-root>/<package>\` as the project path.
|
|
35
|
+
- If \`"worktree-repository"\` is **present**: once the feature name is known, run \`${npxCommand} worktree-info <feature-name>\` to resolve the working directory:
|
|
36
|
+
- exit code **0**: parse the JSON and use the returned \`workingDir\` as the working directory.
|
|
37
|
+
- exit code **1**: the feature is not yet in a worktree — proceed as standard.
|
|
38
|
+
- If \`"worktree-repository"\` is **absent**: use the standard project path from \`.osddtrc\`.
|
|
31
39
|
|
|
32
40
|
## Working Directory
|
|
33
41
|
|
|
@@ -122,15 +130,6 @@ const COMMAND_DEFINITIONS = [
|
|
|
122
130
|
|
|
123
131
|
## Instructions
|
|
124
132
|
|
|
125
|
-
Before checking the working directory, run the following command to check whether this feature uses a git worktree:
|
|
126
|
-
|
|
127
|
-
\`\`\`
|
|
128
|
-
${npxCommand} worktree-info <feature-name>
|
|
129
|
-
\`\`\`
|
|
130
|
-
|
|
131
|
-
- If it exits with code **0**: parse the JSON output and use the returned \`workingDir\` as \`<project-path>/working-on/<feature-name>\`. Skip the main-tree scan below.
|
|
132
|
-
- If it exits with code **1**: the feature is not a worktree feature. Use the standard project path from \`.osddtrc\` and scan the main tree as usual.
|
|
133
|
-
|
|
134
133
|
Check the working directory \`<project-path>/working-on/<feature-name>\` for the files listed below **in order** to determine the current phase. Use the first matching condition:
|
|
135
134
|
|
|
136
135
|
| Condition | Current phase | Run next |
|
|
@@ -169,7 +168,9 @@ ${FEATURE_NAME_RULES}
|
|
|
169
168
|
|
|
170
169
|
Once the feature name is determined:
|
|
171
170
|
|
|
172
|
-
3.
|
|
171
|
+
3. Resolve the working directory:
|
|
172
|
+
- If \`"worktree-repository"\` is present in \`.osddtrc\`: run \`${npxCommand} worktree-info <feature-name>\` and use the returned \`workingDir\` if it exits with code 0; otherwise fall through to the standard path.
|
|
173
|
+
- Otherwise: ${WORKING_DIR_STEP}
|
|
173
174
|
|
|
174
175
|
4. Research the topic thoroughly:
|
|
175
176
|
- Explore the existing codebase for relevant patterns, conventions, and prior art
|
|
@@ -211,61 +212,54 @@ Apply the constraints below to the feature name (the segment after the last \`/\
|
|
|
211
212
|
|
|
212
213
|
${FEATURE_NAME_RULES}
|
|
213
214
|
|
|
214
|
-
Once the branch name is determined
|
|
215
|
+
Once the branch name is determined, choose the workflow based on \`.osddtrc\`:
|
|
215
216
|
|
|
216
|
-
|
|
217
|
-
- If it **does not exist**, create and switch to it:
|
|
218
|
-
\`\`\`
|
|
219
|
-
git checkout -b <branch-name>
|
|
220
|
-
\`\`\`
|
|
221
|
-
- If it **already exists**, warn the user and ask whether to:
|
|
222
|
-
- **Resume** — switch to the existing branch (\`git checkout <branch-name>\`) and continue
|
|
223
|
-
- **Abort** — stop and do nothing
|
|
224
|
-
|
|
225
|
-
4. ${WORKING_DIR_STEP}
|
|
217
|
+
---
|
|
226
218
|
|
|
227
|
-
|
|
219
|
+
### If \`worktree-repository\` is **present** — Worktree workflow
|
|
228
220
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
${getCustomContextStep(npxCommand, 'start')}## Arguments
|
|
221
|
+
3. Run the following command to create the git worktree, scaffold the working directory, and register the feature in the state file:
|
|
232
222
|
|
|
233
|
-
|
|
223
|
+
\`\`\`
|
|
224
|
+
${npxCommand} start-worktree <feature-name>
|
|
225
|
+
\`\`\`
|
|
234
226
|
|
|
235
|
-
|
|
236
|
-
`,
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
name: 'osddt.start-worktree',
|
|
240
|
-
description: 'Start a new feature using a git worktree for parallel development',
|
|
241
|
-
body: ({ args, npxCommand }) => `${getRepoPreamble(npxCommand)}## Instructions
|
|
227
|
+
For monorepos, pass the package path:
|
|
242
228
|
|
|
243
|
-
|
|
229
|
+
\`\`\`
|
|
230
|
+
${npxCommand} start-worktree <feature-name> --dir <package-path>
|
|
231
|
+
\`\`\`
|
|
244
232
|
|
|
245
|
-
|
|
233
|
+
4. Parse the command output to extract \`worktreePath\` and \`workingDir\`.
|
|
246
234
|
|
|
247
|
-
|
|
248
|
-
|
|
235
|
+
5. Navigate into the worktree directory to locate the project:
|
|
236
|
+
- Enter \`<worktreePath>\` — this is the isolated git worktree for this feature.
|
|
237
|
+
- If \`repoType\` is \`"single"\`: the project root is \`<worktreePath>\`.
|
|
238
|
+
- If \`repoType\` is \`"monorepo"\`: the project root is \`<worktreePath>/<package-path>\`.
|
|
239
|
+
- The planning files will live under \`<workingDir>\` (i.e. \`<project-root>/working-on/<feature-name>/\`).
|
|
249
240
|
|
|
250
|
-
|
|
241
|
+
6. Report the branch name, worktree path, project root, and working directory.
|
|
251
242
|
|
|
252
|
-
|
|
243
|
+
---
|
|
253
244
|
|
|
254
|
-
|
|
245
|
+
### If \`worktree-repository\` is **absent** — Standard workflow
|
|
255
246
|
|
|
256
|
-
3.
|
|
247
|
+
3. Check whether the branch already exists locally or remotely:
|
|
248
|
+
- If it **does not exist**, create and switch to it:
|
|
249
|
+
\`\`\`
|
|
250
|
+
git checkout -b <branch-name>
|
|
251
|
+
\`\`\`
|
|
252
|
+
- If it **already exists**, warn the user and ask whether to:
|
|
253
|
+
- **Resume** — switch to the existing branch (\`git checkout <branch-name>\`) and continue
|
|
254
|
+
- **Abort** — stop and do nothing
|
|
257
255
|
|
|
258
|
-
|
|
259
|
-
${npxCommand} start-worktree <feature-name>
|
|
260
|
-
\`\`\`
|
|
256
|
+
4. ${WORKING_DIR_STEP}
|
|
261
257
|
|
|
262
|
-
|
|
258
|
+
Where \`<feature-name>\` is the last segment of the branch name (after the last \`/\`, or the full branch name if no \`/\` is present).
|
|
263
259
|
|
|
264
|
-
|
|
265
|
-
${npxCommand} start-worktree <feature-name> --dir <package-path>
|
|
266
|
-
\`\`\`
|
|
260
|
+
5. Report the branch name and working directory that were created or resumed.
|
|
267
261
|
|
|
268
|
-
|
|
262
|
+
---
|
|
269
263
|
|
|
270
264
|
${getCustomContextStep(npxCommand, 'start')}## Arguments
|
|
271
265
|
|
|
@@ -485,6 +479,26 @@ ${FEATURE_NAME_RULES}
|
|
|
485
479
|
|
|
486
480
|
### Step 2 — Create branch and working directory
|
|
487
481
|
|
|
482
|
+
Choose the workflow based on \`.osddtrc\`:
|
|
483
|
+
|
|
484
|
+
#### If \`worktree-repository\` is **present** — Worktree workflow
|
|
485
|
+
|
|
486
|
+
3. Run the following command to create the git worktree, scaffold the working directory, and register the feature in the state file:
|
|
487
|
+
|
|
488
|
+
\`\`\`
|
|
489
|
+
${npxCommand} start-worktree <feature-name>
|
|
490
|
+
\`\`\`
|
|
491
|
+
|
|
492
|
+
For monorepos, pass the package path:
|
|
493
|
+
|
|
494
|
+
\`\`\`
|
|
495
|
+
${npxCommand} start-worktree <feature-name> --dir <package-path>
|
|
496
|
+
\`\`\`
|
|
497
|
+
|
|
498
|
+
4. Parse the command output to extract \`worktreePath\` and \`workingDir\`. Navigate into \`<worktreePath>\` to locate the project root.
|
|
499
|
+
|
|
500
|
+
#### If \`worktree-repository\` is **absent** — Standard workflow
|
|
501
|
+
|
|
488
502
|
3. Check whether the branch already exists locally or remotely:
|
|
489
503
|
- If it **does not exist**, create and switch to it:
|
|
490
504
|
\`\`\`
|
|
@@ -652,6 +666,12 @@ async function askRepoType() {
|
|
|
652
666
|
],
|
|
653
667
|
});
|
|
654
668
|
}
|
|
669
|
+
async function askWorktreeUrl() {
|
|
670
|
+
return input({
|
|
671
|
+
message: 'Remote repository URL for worktree workflow (leave blank to skip):',
|
|
672
|
+
default: '',
|
|
673
|
+
});
|
|
674
|
+
}
|
|
655
675
|
async function askAgents() {
|
|
656
676
|
return checkbox({
|
|
657
677
|
message: 'Which AI assistant tools do you want to set up?',
|
|
@@ -676,6 +696,102 @@ async function askAgents() {
|
|
|
676
696
|
});
|
|
677
697
|
}
|
|
678
698
|
|
|
699
|
+
function checkGitVersion() {
|
|
700
|
+
try {
|
|
701
|
+
const output = execSync('git --version', { encoding: 'utf-8' }).trim();
|
|
702
|
+
const match = output.match(/git version (\d+)\.(\d+)/);
|
|
703
|
+
if (!match) {
|
|
704
|
+
return { label: 'Git version >= 2.5', passed: false, detail: `Could not parse git version: ${output}` };
|
|
705
|
+
}
|
|
706
|
+
const major = parseInt(match[1], 10);
|
|
707
|
+
const minor = parseInt(match[2], 10);
|
|
708
|
+
const ok = major > 2 || (major === 2 && minor >= 5);
|
|
709
|
+
return {
|
|
710
|
+
label: 'Git version >= 2.5',
|
|
711
|
+
passed: ok,
|
|
712
|
+
detail: ok ? output : `Found ${output} — git worktree requires >= 2.5`,
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
catch {
|
|
716
|
+
return { label: 'Git version >= 2.5', passed: false, detail: 'git not found or not executable' };
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function checkNotAWorktree(cwd) {
|
|
720
|
+
try {
|
|
721
|
+
const gitCommonDir = execSync('git rev-parse --git-common-dir', { cwd, encoding: 'utf-8' }).trim();
|
|
722
|
+
const gitDir = execSync('git rev-parse --git-dir', { cwd, encoding: 'utf-8' }).trim();
|
|
723
|
+
const isWorktree = gitDir !== gitCommonDir && gitDir !== '.git';
|
|
724
|
+
return {
|
|
725
|
+
label: 'Current directory is not a worktree',
|
|
726
|
+
passed: !isWorktree,
|
|
727
|
+
detail: isWorktree
|
|
728
|
+
? `This directory is itself a worktree (git-dir: ${gitDir}). Run setup from the main repository.`
|
|
729
|
+
: 'OK',
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
catch {
|
|
733
|
+
return { label: 'Current directory is not a worktree', passed: false, detail: 'Not inside a git repository' };
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function checkTargetWritable(cwd) {
|
|
737
|
+
let targetBase;
|
|
738
|
+
try {
|
|
739
|
+
const repoRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
|
|
740
|
+
const rcPath = path.join(repoRoot, '.osddtrc');
|
|
741
|
+
if (await fs.pathExists(rcPath)) {
|
|
742
|
+
const rc = await fs.readJson(rcPath);
|
|
743
|
+
targetBase = rc.worktreeBase ?? path.dirname(repoRoot);
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
targetBase = path.dirname(repoRoot);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
catch {
|
|
750
|
+
return { label: 'Worktree target directory is writable', passed: false, detail: 'Could not resolve repo root' };
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
await fs.access(targetBase, fs.constants.W_OK);
|
|
754
|
+
return { label: 'Worktree target directory is writable', passed: true, detail: `${targetBase} is writable` };
|
|
755
|
+
}
|
|
756
|
+
catch {
|
|
757
|
+
return { label: 'Worktree target directory is writable', passed: false, detail: `${targetBase} is not writable` };
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
async function initStateFile(cwd) {
|
|
761
|
+
try {
|
|
762
|
+
const repoRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
|
|
763
|
+
const stateFile = path.join(path.dirname(repoRoot), '.osddt-worktrees');
|
|
764
|
+
if (!(await fs.pathExists(stateFile))) {
|
|
765
|
+
await fs.writeJson(stateFile, [], { spaces: 2 });
|
|
766
|
+
console.log(` ✓ Initialized worktree state file: ${stateFile}`);
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
console.log(` ✓ Worktree state file already exists: ${stateFile}`);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
catch {
|
|
773
|
+
console.log(' ✗ Could not initialize worktree state file');
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
function printCheckResult(result) {
|
|
777
|
+
const icon = result.passed ? '✓' : '✗';
|
|
778
|
+
console.log(` ${icon} ${result.label}`);
|
|
779
|
+
if (!result.passed) {
|
|
780
|
+
console.log(` → ${result.detail}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
async function runWorktreeChecks(cwd) {
|
|
784
|
+
const results = [
|
|
785
|
+
checkGitVersion(),
|
|
786
|
+
checkNotAWorktree(cwd),
|
|
787
|
+
await checkTargetWritable(cwd),
|
|
788
|
+
];
|
|
789
|
+
for (const result of results) {
|
|
790
|
+
printCheckResult(result);
|
|
791
|
+
}
|
|
792
|
+
return results.every(r => r.passed);
|
|
793
|
+
}
|
|
794
|
+
|
|
679
795
|
const CANONICAL_PACKAGE_NAME = '@dezkareid/osddt';
|
|
680
796
|
const NPX_COMMAND = 'npx osddt';
|
|
681
797
|
const NPX_COMMAND_FALLBACK = `npx ${CANONICAL_PACKAGE_NAME}`;
|
|
@@ -723,15 +839,7 @@ async function writeConfig(cwd, config) {
|
|
|
723
839
|
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
724
840
|
console.log(`\nSaved config: ${configPath}`);
|
|
725
841
|
}
|
|
726
|
-
async function
|
|
727
|
-
const agents = rawAgents !== undefined ? parseAgents(rawAgents) : await askAgents();
|
|
728
|
-
if (rawAgents === undefined)
|
|
729
|
-
console.log('');
|
|
730
|
-
const repoType = rawRepoType !== undefined ? parseRepoType(rawRepoType) : await askRepoType();
|
|
731
|
-
if (rawRepoType === undefined)
|
|
732
|
-
console.log('');
|
|
733
|
-
const npxCommand = await resolveNpxCommand(cwd);
|
|
734
|
-
console.log('Setting up OSDDT command files...\n');
|
|
842
|
+
async function writeAgentFiles(cwd, agents, npxCommand) {
|
|
735
843
|
if (agents.includes('claude')) {
|
|
736
844
|
const claudeFiles = getClaudeTemplates(cwd, npxCommand);
|
|
737
845
|
console.log('Claude Code commands (.claude/commands/):');
|
|
@@ -748,7 +856,56 @@ async function runSetup(cwd, rawAgents, rawRepoType) {
|
|
|
748
856
|
}
|
|
749
857
|
console.log('');
|
|
750
858
|
}
|
|
751
|
-
|
|
859
|
+
}
|
|
860
|
+
function isGitRepository(cwd) {
|
|
861
|
+
try {
|
|
862
|
+
execSync('git rev-parse --git-dir', { cwd, stdio: 'ignore' });
|
|
863
|
+
return true;
|
|
864
|
+
}
|
|
865
|
+
catch {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
function cloneBareRepository(cwd, repositoryUrl) {
|
|
870
|
+
console.log(`Cloning repository as bare into ${cwd}/.git ...\n`);
|
|
871
|
+
execSync(`git clone --bare "${repositoryUrl}" .git`, { cwd, stdio: 'inherit' });
|
|
872
|
+
execSync('git config --local core.bare false', { cwd, stdio: 'inherit' });
|
|
873
|
+
console.log('');
|
|
874
|
+
}
|
|
875
|
+
async function setupWorktreeEnvironment(cwd, worktreeRepository) {
|
|
876
|
+
if (!isGitRepository(cwd)) {
|
|
877
|
+
cloneBareRepository(cwd, worktreeRepository);
|
|
878
|
+
}
|
|
879
|
+
console.log('Checking environment for git worktree support...\n');
|
|
880
|
+
const allPassed = await runWorktreeChecks(cwd);
|
|
881
|
+
console.log('');
|
|
882
|
+
if (!allPassed) {
|
|
883
|
+
console.log('Some checks failed. Resolve the issues above before using the worktree workflow.');
|
|
884
|
+
process.exit(1);
|
|
885
|
+
}
|
|
886
|
+
await initStateFile(cwd);
|
|
887
|
+
console.log('');
|
|
888
|
+
}
|
|
889
|
+
async function runSetup(cwd, rawAgents, rawRepoType, rawWorktreeRepository) {
|
|
890
|
+
const agents = rawAgents !== undefined ? parseAgents(rawAgents) : await askAgents();
|
|
891
|
+
if (rawAgents === undefined)
|
|
892
|
+
console.log('');
|
|
893
|
+
const repoType = rawRepoType !== undefined ? parseRepoType(rawRepoType) : await askRepoType();
|
|
894
|
+
if (rawRepoType === undefined)
|
|
895
|
+
console.log('');
|
|
896
|
+
const worktreeRepository = rawWorktreeRepository !== undefined ? rawWorktreeRepository : (await askWorktreeUrl()) || undefined;
|
|
897
|
+
if (rawWorktreeRepository === undefined)
|
|
898
|
+
console.log('');
|
|
899
|
+
if (worktreeRepository) {
|
|
900
|
+
await setupWorktreeEnvironment(cwd, worktreeRepository);
|
|
901
|
+
}
|
|
902
|
+
const npxCommand = await resolveNpxCommand(cwd);
|
|
903
|
+
console.log('Setting up OSDDT command files...\n');
|
|
904
|
+
await writeAgentFiles(cwd, agents, npxCommand);
|
|
905
|
+
const config = { repoType, agents };
|
|
906
|
+
if (worktreeRepository)
|
|
907
|
+
config['worktree-repository'] = worktreeRepository;
|
|
908
|
+
await writeConfig(cwd, config);
|
|
752
909
|
console.log('\nSetup complete!');
|
|
753
910
|
console.log('Commands created: osddt.spec, osddt.plan, osddt.tasks, osddt.implement');
|
|
754
911
|
}
|
|
@@ -759,9 +916,10 @@ function setupCommand() {
|
|
|
759
916
|
.option('-d, --dir <directory>', 'target directory', process.cwd())
|
|
760
917
|
.option('--agents <list>', 'comma-separated agents to set up (claude, gemini)')
|
|
761
918
|
.option('--repo-type <type>', 'repository type (single, monorepo)')
|
|
919
|
+
.option('--worktree-repository <url>', 'remote repository URL to enable worktree workflow')
|
|
762
920
|
.action(async (options) => {
|
|
763
921
|
const targetDir = path.resolve(options.dir);
|
|
764
|
-
await runSetup(targetDir, options.agents, options.repoType);
|
|
922
|
+
await runSetup(targetDir, options.agents, options.repoType, options.worktreeRepository);
|
|
765
923
|
});
|
|
766
924
|
return cmd;
|
|
767
925
|
}
|
|
@@ -1148,106 +1306,6 @@ function worktreeInfoCommand() {
|
|
|
1148
1306
|
return cmd;
|
|
1149
1307
|
}
|
|
1150
1308
|
|
|
1151
|
-
function checkGitVersion() {
|
|
1152
|
-
try {
|
|
1153
|
-
const output = execSync('git --version', { encoding: 'utf-8' }).trim();
|
|
1154
|
-
// e.g. "git version 2.39.3"
|
|
1155
|
-
const match = output.match(/git version (\d+)\.(\d+)/);
|
|
1156
|
-
if (!match) {
|
|
1157
|
-
return { label: 'Git version >= 2.5', passed: false, detail: `Could not parse git version: ${output}` };
|
|
1158
|
-
}
|
|
1159
|
-
const major = parseInt(match[1], 10);
|
|
1160
|
-
const minor = parseInt(match[2], 10);
|
|
1161
|
-
const ok = major > 2 || (major === 2 && minor >= 5);
|
|
1162
|
-
return {
|
|
1163
|
-
label: 'Git version >= 2.5',
|
|
1164
|
-
passed: ok,
|
|
1165
|
-
detail: ok ? output : `Found ${output} — git worktree requires >= 2.5`,
|
|
1166
|
-
};
|
|
1167
|
-
}
|
|
1168
|
-
catch {
|
|
1169
|
-
return { label: 'Git version >= 2.5', passed: false, detail: 'git not found or not executable' };
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
function checkNotAWorktree(cwd) {
|
|
1173
|
-
try {
|
|
1174
|
-
const gitCommonDir = execSync('git rev-parse --git-common-dir', { cwd, encoding: 'utf-8' }).trim();
|
|
1175
|
-
const gitDir = execSync('git rev-parse --git-dir', { cwd, encoding: 'utf-8' }).trim();
|
|
1176
|
-
const isWorktree = gitDir !== gitCommonDir && gitDir !== '.git';
|
|
1177
|
-
return {
|
|
1178
|
-
label: 'Current directory is not a worktree',
|
|
1179
|
-
passed: !isWorktree,
|
|
1180
|
-
detail: isWorktree
|
|
1181
|
-
? `This directory is itself a worktree (git-dir: ${gitDir}). Run setup-worktree from the main repository.`
|
|
1182
|
-
: 'OK',
|
|
1183
|
-
};
|
|
1184
|
-
}
|
|
1185
|
-
catch {
|
|
1186
|
-
return { label: 'Current directory is not a worktree', passed: false, detail: 'Not inside a git repository' };
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
async function checkTargetWritable(cwd) {
|
|
1190
|
-
let targetBase;
|
|
1191
|
-
try {
|
|
1192
|
-
const repoRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf-8' }).trim();
|
|
1193
|
-
const rcPath = path.join(repoRoot, '.osddtrc');
|
|
1194
|
-
if (await fs.pathExists(rcPath)) {
|
|
1195
|
-
const rc = await fs.readJson(rcPath);
|
|
1196
|
-
targetBase = rc.worktreeBase ?? path.dirname(repoRoot);
|
|
1197
|
-
}
|
|
1198
|
-
else {
|
|
1199
|
-
targetBase = path.dirname(repoRoot);
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
catch {
|
|
1203
|
-
return { label: 'Worktree target directory is writable', passed: false, detail: 'Could not resolve repo root' };
|
|
1204
|
-
}
|
|
1205
|
-
try {
|
|
1206
|
-
await fs.access(targetBase, fs.constants.W_OK);
|
|
1207
|
-
return { label: 'Worktree target directory is writable', passed: true, detail: `${targetBase} is writable` };
|
|
1208
|
-
}
|
|
1209
|
-
catch {
|
|
1210
|
-
return { label: 'Worktree target directory is writable', passed: false, detail: `${targetBase} is not writable` };
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
function printResult(result) {
|
|
1214
|
-
const icon = result.passed ? '✓' : '✗';
|
|
1215
|
-
console.log(` ${icon} ${result.label}`);
|
|
1216
|
-
if (!result.passed) {
|
|
1217
|
-
console.log(` → ${result.detail}`);
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
async function runSetupWorktree(cwd) {
|
|
1221
|
-
console.log('Checking environment for git worktree support...\n');
|
|
1222
|
-
const results = [
|
|
1223
|
-
checkGitVersion(),
|
|
1224
|
-
checkNotAWorktree(cwd),
|
|
1225
|
-
await checkTargetWritable(cwd),
|
|
1226
|
-
];
|
|
1227
|
-
for (const result of results) {
|
|
1228
|
-
printResult(result);
|
|
1229
|
-
}
|
|
1230
|
-
const allPassed = results.every(r => r.passed);
|
|
1231
|
-
console.log('');
|
|
1232
|
-
if (allPassed) {
|
|
1233
|
-
console.log('All checks passed. You can use the worktree workflow.');
|
|
1234
|
-
}
|
|
1235
|
-
else {
|
|
1236
|
-
console.log('Some checks failed. Resolve the issues above before using the worktree workflow.');
|
|
1237
|
-
process.exit(1);
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
function setupWorktreeCommand() {
|
|
1241
|
-
const cmd = new Command('setup-worktree');
|
|
1242
|
-
cmd
|
|
1243
|
-
.description('Validate the environment for git worktree usage')
|
|
1244
|
-
.option('-d, --dir <directory>', 'directory to check', process.cwd())
|
|
1245
|
-
.action(async (options) => {
|
|
1246
|
-
await runSetupWorktree(path.resolve(options.dir));
|
|
1247
|
-
});
|
|
1248
|
-
return cmd;
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
1309
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
1252
1310
|
const __dirname$1 = path.dirname(__filename$1);
|
|
1253
1311
|
const pkgPath = path.join(__dirname$1, '..', 'package.json');
|
|
@@ -1264,5 +1322,4 @@ program.addCommand(updateCommand());
|
|
|
1264
1322
|
program.addCommand(contextCommand());
|
|
1265
1323
|
program.addCommand(startWorktreeCommand());
|
|
1266
1324
|
program.addCommand(worktreeInfoCommand());
|
|
1267
|
-
program.addCommand(setupWorktreeCommand());
|
|
1268
1325
|
program.parse(process.argv);
|
package/dist/utils/prompt.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type RepoType = 'monorepo' | 'single';
|
|
2
2
|
export type AgentType = 'claude' | 'gemini';
|
|
3
3
|
export declare function askRepoType(): Promise<RepoType>;
|
|
4
|
+
export declare function askWorktreeUrl(): Promise<string>;
|
|
4
5
|
export declare function askAgents(): Promise<AgentType[]>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CheckResult {
|
|
2
|
+
label: string;
|
|
3
|
+
passed: boolean;
|
|
4
|
+
detail: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function checkGitVersion(): CheckResult;
|
|
7
|
+
export declare function checkNotAWorktree(cwd: string): CheckResult;
|
|
8
|
+
export declare function checkTargetWritable(cwd: string): Promise<CheckResult>;
|
|
9
|
+
export declare function initStateFile(cwd: string): Promise<void>;
|
|
10
|
+
export declare function printCheckResult(result: CheckResult): void;
|
|
11
|
+
export declare function runWorktreeChecks(cwd: string): Promise<boolean>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dezkareid/osddt",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "Package for Spec-Driven Development workflow",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spec-driven",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"main": "./dist/index.js",
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@inquirer/checkbox": "5.0.7",
|
|
37
|
+
"@inquirer/input": "5.0.7",
|
|
37
38
|
"@inquirer/select": "5.0.7",
|
|
38
39
|
"commander": "12.0.0",
|
|
39
40
|
"fs-extra": "11.2.0",
|