@dezkareid/osddt 1.11.0 → 1.11.1

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 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
- └── prompt.ts # Inquirer prompts: askAgents() (checkbox) and askRepoType() (select)
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 | Context | Description |
150
- | -------------------------------------------------------------------- | ------------- | ------------------------------------------------------------- |
151
- | `osddt setup` | Local dev | Generate agent command files for Claude and Gemini |
152
- | `osddt setup --agents <list> --repo-type <type>` | Local dev | Non-interactive setup (for CI/scripted environments) |
153
- | `npx @dezkareid/osddt setup` | External | Generate agent command files for Claude and Gemini |
154
- | `npx @dezkareid/osddt setup --agents <list> --repo-type <type>` | External | Non-interactive setup (for CI/scripted environments) |
155
- | `osddt meta-info` | Local dev | Output current branch and date as JSON |
156
- | `npx @dezkareid/osddt meta-info` | External | Output current branch and date as JSON |
157
- | `osddt done <feature-name> --dir <project-path>` | Local dev | Move `working-on/<feature>` to `done/<feature>` |
158
- | `npx @dezkareid/osddt done <feature-name> --dir <project-path>` | External | Move `working-on/<feature>` to `done/<feature>` |
159
- | `osddt done <feature-name> --dir <project-path> --worktree` | Local dev | Archive feature, remove git worktree, and clean state file |
160
- | `npx @dezkareid/osddt done <feature-name> --dir <project-path> --worktree` | External | Archive feature, remove git worktree, and clean state file |
161
- | `osddt update` | Local dev | Regenerate agent command files from the existing `.osddtrc` |
162
- | `npx @dezkareid/osddt update` | External | Regenerate agent command files from the existing `.osddtrc` |
163
- | `osddt start-worktree <feature-name>` | Local dev | Create a git worktree for a feature and scaffold working-on/ |
164
- | `npx @dezkareid/osddt start-worktree <feature-name>` | External | Create a git worktree for a feature and scaffold working-on/ |
165
- | `osddt start-worktree <feature-name> --dir <package-path>` | Local dev | Same, specifying the package path in a monorepo |
166
- | `npx @dezkareid/osddt start-worktree <feature-name> --dir <package-path>` | External | Same, specifying the package path in a monorepo |
167
- | `osddt worktree-info <feature-name>` | Local dev | Look up worktree paths for a feature (JSON output) |
168
- | `npx @dezkareid/osddt worktree-info <feature-name>` | External | Look up worktree paths for a feature (JSON output) |
169
- | `osddt setup-worktree` | Local dev | Validate environment for git worktree usage |
170
- | `npx @dezkareid/osddt setup-worktree` | External | Validate environment for git worktree usage |
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
- Both flags are optional. Providing neither runs the fully interactive mode. Providing both skips all prompts.
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 | Description |
187
- | ------------------ | ------------------------------------------------------------------ |
188
- | `osddt.continue` | Detect the current workflow phase and prompt the next command |
189
- | `osddt.research` | Research a topic and write a research file to inform the spec |
190
- | `osddt.start` | Start a new feature by creating a branch and working-on folder |
191
- | `osddt.start-worktree` | Start a new feature using a git worktree for parallel development |
192
- | `osddt.spec` | Analyze requirements and write a feature specification |
193
- | `osddt.clarify` | Resolve open questions in the spec and record decisions (optional) |
194
- | `osddt.plan` | Create a technical implementation plan from a specification |
195
- | `osddt.tasks` | Generate actionable tasks from an implementation plan |
196
- | `osddt.implement` | Execute tasks from the task list one by one |
197
- | `osddt.fast` | Bootstrap all planning artifacts (spec, plan, tasks) in one shot |
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
- Use `osddt.start-worktree` to work on multiple features simultaneously. Each feature gets its own isolated directory (a git worktree), so you can keep multiple editor windows open without switching branches.
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
- Then start a feature in its own worktree:
271
+ From that point on, `/osddt.start` automatically uses the worktree workflow:
273
272
 
274
273
  ```
275
- /osddt.start-worktree add-payment-gateway
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
- - **Actions performed by the agent**:
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. Reads `.osddtrc` to resolve the project path (single vs monorepo).
321
- 3. Checks for an existing `working-on/<feature-name>/` folder — offers **Resume** or **Abort** if found, otherwise creates it.
322
- 4. Reports the branch and working directory, then shows a context-aware next step:
323
- - If input was a **human-readable description**: informs the user their description will be used as the starting point for the spec and suggests running `/osddt.spec` (with an optional-context note).
324
- - If input was a **branch name** (or no arguments): prompts the user to run `/osddt.spec` with an optional-context note.
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
- Both flags are optional. Providing neither runs the fully interactive mode. Providing both skips all prompts.
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` alongside `repoType` so that `osddt update` can regenerate the correct files without prompting.
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
- Use `osddt.start-worktree` when you want to work on multiple features simultaneously. Each feature gets its own isolated directory so you can keep multiple editor windows open without switching branches.
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
- Then start a feature in its own worktree:
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-worktree add-payment-gateway
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 | Description |
161
- | ----------------------- | ------------------------------------------------------------------ |
162
- | `osddt.continue` | Detect the current workflow phase and prompt the next command |
163
- | `osddt.research` | Research a topic and write a research file to inform the spec |
164
- | `osddt.start` | Start a new feature by creating a branch and working-on folder |
165
- | `osddt.start-worktree` | Start a new feature using a git worktree for parallel development |
166
- | `osddt.spec` | Analyze requirements and write a feature specification |
167
- | `osddt.clarify` | Resolve open questions in the spec and record decisions (optional) |
168
- | `osddt.plan` | Create a technical implementation plan from a specification |
169
- | `osddt.tasks` | Generate actionable tasks from an implementation plan |
170
- | `osddt.implement` | Execute tasks from the task list one by one |
171
- | `osddt.fast` | Bootstrap all planning artifacts (spec, plan, tasks) in one shot |
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
@@ -5,6 +5,7 @@ import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import select from '@inquirer/select';
7
7
  import checkbox from '@inquirer/checkbox';
8
+ import input from '@inquirer/input';
8
9
  import { execSync } from 'child_process';
9
10
  import readline from 'readline';
10
11
 
@@ -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
- // .osddtrc example
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. ${WORKING_DIR_STEP}
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
-
216
- 3. Check whether the branch already exists locally or remotely:
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}
215
+ Once the branch name is determined, choose the workflow based on \`.osddtrc\`:
226
216
 
227
- Where \`<feature-name>\` is the last segment of the branch name (after the last \`/\`, or the full branch name if no \`/\` is present).
217
+ ---
228
218
 
229
- 5. Report the branch name and working directory that were created or resumed.
219
+ ### If \`worktree-repository\` is **present** Worktree workflow
230
220
 
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
- ${args}
223
+ \`\`\`
224
+ ${npxCommand} start-worktree <feature-name>
225
+ \`\`\`
234
226
 
235
- ${getNextStepToSpec(args)}
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
- The argument provided is: ${args}
229
+ \`\`\`
230
+ ${npxCommand} start-worktree <feature-name> --dir <package-path>
231
+ \`\`\`
244
232
 
245
- Determine the branch name using the following logic:
233
+ 4. Parse the command output to extract \`worktreePath\` and \`workingDir\`.
246
234
 
247
- 1. If ${args} looks like a branch name (e.g. \`feat/my-feature\`, \`fix/some-bug\`, \`my-feature-branch\` — no spaces, kebab-case or slash-separated), use it as-is.
248
- 2. Otherwise treat ${args} as a human-readable feature description, convert it to a feature name, and use the format \`feat/<derived-name>\` as the branch name.
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
- Apply the constraints below to the feature name (the segment after the last \`/\`) before using it:
241
+ 6. Report the branch name, worktree path, project root, and working directory.
251
242
 
252
- ${FEATURE_NAME_RULES}
243
+ ---
253
244
 
254
- Once the branch name is determined:
245
+ ### If \`worktree-repository\` is **absent** — Standard workflow
255
246
 
256
- 3. Run the following command to create the git worktree, scaffold the working directory, and register the feature in the state file:
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
- For monorepos, pass the package path:
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
- 4. Report the branch name, worktree path, and working directory shown in the command output.
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 runSetup(cwd, rawAgents, rawRepoType) {
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,38 @@ async function runSetup(cwd, rawAgents, rawRepoType) {
748
856
  }
749
857
  console.log('');
750
858
  }
751
- await writeConfig(cwd, { repoType, agents });
859
+ }
860
+ async function setupWorktreeEnvironment(cwd, _worktreeRepository) {
861
+ console.log('Checking environment for git worktree support...\n');
862
+ const allPassed = await runWorktreeChecks(cwd);
863
+ console.log('');
864
+ if (!allPassed) {
865
+ console.log('Some checks failed. Resolve the issues above before using the worktree workflow.');
866
+ process.exit(1);
867
+ }
868
+ await initStateFile(cwd);
869
+ console.log('');
870
+ }
871
+ async function runSetup(cwd, rawAgents, rawRepoType, rawWorktreeRepository) {
872
+ const agents = rawAgents !== undefined ? parseAgents(rawAgents) : await askAgents();
873
+ if (rawAgents === undefined)
874
+ console.log('');
875
+ const repoType = rawRepoType !== undefined ? parseRepoType(rawRepoType) : await askRepoType();
876
+ if (rawRepoType === undefined)
877
+ console.log('');
878
+ const worktreeRepository = rawWorktreeRepository !== undefined ? rawWorktreeRepository : (await askWorktreeUrl()) || undefined;
879
+ if (rawWorktreeRepository === undefined)
880
+ console.log('');
881
+ if (worktreeRepository) {
882
+ await setupWorktreeEnvironment(cwd);
883
+ }
884
+ const npxCommand = await resolveNpxCommand(cwd);
885
+ console.log('Setting up OSDDT command files...\n');
886
+ await writeAgentFiles(cwd, agents, npxCommand);
887
+ const config = { repoType, agents };
888
+ if (worktreeRepository)
889
+ config['worktree-repository'] = worktreeRepository;
890
+ await writeConfig(cwd, config);
752
891
  console.log('\nSetup complete!');
753
892
  console.log('Commands created: osddt.spec, osddt.plan, osddt.tasks, osddt.implement');
754
893
  }
@@ -759,9 +898,10 @@ function setupCommand() {
759
898
  .option('-d, --dir <directory>', 'target directory', process.cwd())
760
899
  .option('--agents <list>', 'comma-separated agents to set up (claude, gemini)')
761
900
  .option('--repo-type <type>', 'repository type (single, monorepo)')
901
+ .option('--worktree-repository <url>', 'remote repository URL to enable worktree workflow')
762
902
  .action(async (options) => {
763
903
  const targetDir = path.resolve(options.dir);
764
- await runSetup(targetDir, options.agents, options.repoType);
904
+ await runSetup(targetDir, options.agents, options.repoType, options.worktreeRepository);
765
905
  });
766
906
  return cmd;
767
907
  }
@@ -1148,106 +1288,6 @@ function worktreeInfoCommand() {
1148
1288
  return cmd;
1149
1289
  }
1150
1290
 
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
1291
  const __filename$1 = fileURLToPath(import.meta.url);
1252
1292
  const __dirname$1 = path.dirname(__filename$1);
1253
1293
  const pkgPath = path.join(__dirname$1, '..', 'package.json');
@@ -1264,5 +1304,4 @@ program.addCommand(updateCommand());
1264
1304
  program.addCommand(contextCommand());
1265
1305
  program.addCommand(startWorktreeCommand());
1266
1306
  program.addCommand(worktreeInfoCommand());
1267
- program.addCommand(setupWorktreeCommand());
1268
1307
  program.parse(process.argv);
@@ -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.0",
3
+ "version": "1.11.1",
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",
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function setupWorktreeCommand(): Command;