@dezkareid/osddt 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +68 -10
- package/README.md +69 -6
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.spec.d.ts +1 -0
- package/dist/index.js +109 -22
- package/dist/templates/shared.d.ts +1 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -105,7 +105,8 @@ osddt/
|
|
|
105
105
|
│ ├── commands/
|
|
106
106
|
│ │ ├── setup.ts # `osddt setup` — prompts for agents & repo type (or reads --agents/--repo-type flags), writes command files and .osddtrc
|
|
107
107
|
│ │ ├── meta-info.ts # `osddt meta-info` — outputs { branch, date } as JSON (consumed by generated templates)
|
|
108
|
-
│ │
|
|
108
|
+
│ │ ├── done.ts # `osddt done <feature>` — moves working-on/<feature> → done/YYYY-MM-DD-<feature>
|
|
109
|
+
│ │ └── update.ts # `osddt update` — reads .osddtrc and regenerates agent command files for detected agents
|
|
109
110
|
│ ├── templates/
|
|
110
111
|
│ │ ├── shared.ts # REPO_PREAMBLE, FEATURE_NAME_RULES, WORKING_DIR_STEP, and COMMAND_DEFINITIONS array
|
|
111
112
|
│ │ ├── claude.ts # Formats COMMAND_DEFINITIONS as Markdown (.claude/commands/osddt.<name>.md)
|
|
@@ -117,7 +118,7 @@ osddt/
|
|
|
117
118
|
├── tsconfig.json # TypeScript config
|
|
118
119
|
├── vitest.config.ts # Vitest config
|
|
119
120
|
├── package.json # Package name: @dezkareid/osddt, bin: osddt → dist/index.js
|
|
120
|
-
├── .osddtrc # Runtime config written by setup (repoType: "single" | "monorepo")
|
|
121
|
+
├── .osddtrc # Runtime config written by setup (repoType: "single" | "monorepo", agents: ["claude", "gemini"])
|
|
121
122
|
├── AGENTS.md / CLAUDE.md / GEMINI.md # Agent-specific instructions (kept in sync)
|
|
122
123
|
└── README.md # Public-facing documentation
|
|
123
124
|
```
|
|
@@ -142,6 +143,8 @@ There are two contexts in which osddt commands are invoked:
|
|
|
142
143
|
|
|
143
144
|
When `osddt setup` is run, it reads the `name` field of `package.json` in the target directory. If the name is `@dezkareid/osddt`, templates are written with `npx osddt`. Otherwise they fall back to `npx @dezkareid/osddt`. The resolution lives in `resolveNpxCommand()` in `src/commands/setup.ts`.
|
|
144
145
|
|
|
146
|
+
The selected agents are saved in `.osddtrc` alongside `repoType`. When `osddt update` is run, if `.osddtrc` has no `agents` key, it scans each agent's command directory for any command files to infer the active agents and writes the result back into `.osddtrc`.
|
|
147
|
+
|
|
145
148
|
#### Available commands
|
|
146
149
|
|
|
147
150
|
| Command | Context | Description |
|
|
@@ -154,6 +157,8 @@ When `osddt setup` is run, it reads the `name` field of `package.json` in the ta
|
|
|
154
157
|
| `npx @dezkareid/osddt meta-info` | External | Output current branch and date as JSON |
|
|
155
158
|
| `osddt done <feature-name> --dir <project-path>` | Local dev | Move `working-on/<feature>` to `done/<feature>` |
|
|
156
159
|
| `npx @dezkareid/osddt done <feature-name> --dir <project-path>` | External | Move `working-on/<feature>` to `done/<feature>` |
|
|
160
|
+
| `osddt update` | Local dev | Regenerate agent command files from the existing `.osddtrc` |
|
|
161
|
+
| `npx @dezkareid/osddt update` | External | Regenerate agent command files from the existing `.osddtrc` |
|
|
157
162
|
|
|
158
163
|
#### `osddt setup` options
|
|
159
164
|
|
|
@@ -183,17 +188,65 @@ Templates are generated by `npx @dezkareid/osddt setup` and placed in each agent
|
|
|
183
188
|
|
|
184
189
|
#### Template Workflow
|
|
185
190
|
|
|
186
|
-
`osddt.research` and `osddt.start` are **peer entry points** — use whichever fits your situation. Both lead to `osddt.spec`. If you close the coding session,
|
|
191
|
+
`osddt.research` and `osddt.start` are **peer entry points** — use whichever fits your situation. Both lead to `osddt.spec`. If you close the coding session, execute `osddt.continue` to resume the workflow.
|
|
192
|
+
|
|
193
|
+
**Standard steps:**
|
|
194
|
+
|
|
195
|
+
1. Pick an entry point:
|
|
196
|
+
- **`osddt.research <topic>`** — explore the codebase or gather external findings first, then proceed to spec.
|
|
197
|
+
- **`osddt.start <feature>`** — jump straight to creating the branch and working directory, then write the spec.
|
|
198
|
+
2. **`osddt.spec <feature>`** — analyse requirements and write the feature specification.
|
|
199
|
+
3. *(optional)* **`osddt.clarify <feature>`** — resolve any Open Questions in the spec and record decisions.
|
|
200
|
+
4. **`osddt.plan <tech decisions>`** — create a technical implementation plan from the spec.
|
|
201
|
+
5. **`osddt.tasks`** — generate a checklist of actionable tasks from the plan.
|
|
202
|
+
6. **`osddt.implement`** — execute tasks one by one until all are checked off.
|
|
203
|
+
7. **`osddt.done`** — verify all tasks are complete and move the feature folder to `done/`.
|
|
204
|
+
|
|
205
|
+
> **Note:** You can re-run any step to go back and revise it — except once `osddt.done` has been executed, the feature is considered finished and cannot be revisited.
|
|
206
|
+
|
|
207
|
+
**If you close a session:**
|
|
208
|
+
|
|
209
|
+
- Run **`osddt.continue <feature>`** — it inspects the `working-on/<feature-name>/` folder, identifies the current phase, and tells you the exact next command to run.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
##### Example A — Starting with research
|
|
187
214
|
|
|
188
215
|
```
|
|
189
|
-
osddt.
|
|
190
|
-
|
|
191
|
-
osddt.
|
|
192
|
-
|
|
193
|
-
osddt.
|
|
216
|
+
/osddt.research add payment gateway
|
|
217
|
+
/osddt.spec add-payment-gateway
|
|
218
|
+
/osddt.clarify add-payment-gateway # optional — resolve open questions
|
|
219
|
+
/osddt.plan use Stripe SDK, REST endpoints, no webhooks
|
|
220
|
+
/osddt.tasks
|
|
221
|
+
/osddt.implement
|
|
222
|
+
/osddt.done
|
|
194
223
|
```
|
|
195
224
|
|
|
196
|
-
|
|
225
|
+
##### Example B — Starting directly
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
/osddt.start add user profile page
|
|
229
|
+
/osddt.spec add-user-profile-page
|
|
230
|
+
/osddt.plan React with React Query, REST API
|
|
231
|
+
/osddt.tasks
|
|
232
|
+
/osddt.implement
|
|
233
|
+
/osddt.done
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
##### Example C — Resuming after closing a session
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
# You closed Claude and want to pick up where you left off:
|
|
240
|
+
/osddt.continue add-payment-gateway
|
|
241
|
+
# → osddt.continue detects osddt.plan.md exists and reports:
|
|
242
|
+
# "Planning phase complete. Run: /osddt.tasks"
|
|
243
|
+
/osddt.tasks
|
|
244
|
+
/osddt.implement
|
|
245
|
+
/osddt.done
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
197
250
|
- Use **`osddt.research`** when you want to explore the codebase and gather findings before writing the spec. It creates the `working-on/<feature-name>/` folder and writes `osddt.research.md`.
|
|
198
251
|
- Use **`osddt.start`** when you are ready to begin implementation directly. It creates the git branch and the `working-on/<feature-name>/` folder.
|
|
199
252
|
- Both `osddt.research` and `osddt.start` check whether the working directory already exists and ask to **Resume** or **Abort** if it does.
|
|
@@ -223,6 +276,9 @@ osddt.start ──┘
|
|
|
223
276
|
1. Checks for an existing branch — offers **Resume** (`git checkout`) or **Abort** if found, otherwise runs `git checkout -b <branch-name>`.
|
|
224
277
|
2. Reads `.osddtrc` to resolve the project path (single vs monorepo).
|
|
225
278
|
3. Checks for an existing `working-on/<feature-name>/` folder — offers **Resume** or **Abort** if found, otherwise creates it.
|
|
279
|
+
4. Reports the branch and working directory, then shows a context-aware next step:
|
|
280
|
+
- 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).
|
|
281
|
+
- If input was a **branch name** (or no arguments): prompts the user to run `/osddt.spec` with an optional-context note.
|
|
226
282
|
|
|
227
283
|
#### osddt.research behaviour
|
|
228
284
|
|
|
@@ -231,10 +287,12 @@ osddt.start ──┘
|
|
|
231
287
|
1. Derives the feature name (subject to the 30-character limit).
|
|
232
288
|
2. Checks for an existing `working-on/<feature-name>/` folder — offers **Resume** or **Abort** if found, otherwise creates it.
|
|
233
289
|
3. Researches the topic (codebase exploration, external references) and writes `osddt.research.md`.
|
|
290
|
+
4. Shows a context-aware next step:
|
|
291
|
+
- 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).
|
|
292
|
+
- If input was a **branch name** (or no arguments): prompts the user to run `/osddt.spec` with an optional-context note.
|
|
234
293
|
|
|
235
294
|
#### osddt.clarify behaviour
|
|
236
295
|
|
|
237
|
-
- **Input**: A feature name or branch name identifying the feature whose spec to clarify.
|
|
238
296
|
- **Actions performed by the agent**:
|
|
239
297
|
1. Locates `osddt.spec.md` in `working-on/<feature-name>/`; if absent, suggests running `osddt.spec` first.
|
|
240
298
|
2. Reads the **Open Questions** section and the **Decisions** section (if present) to determine which questions are already answered.
|
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Other spec driven development tool but for monorepo
|
|
|
9
9
|
| `@dezkareid/osddt setup --agents <list> --repo-type <type>` | Non-interactive setup (for CI/scripted environments) |
|
|
10
10
|
| `@dezkareid/osddt meta-info` | Output current branch and date as JSON |
|
|
11
11
|
| `@dezkareid/osddt done <feature-name> --dir <project-path>` | Move `working-on/<feature>` to `done/<feature>` |
|
|
12
|
+
| `@dezkareid/osddt update` | Regenerate agent command files from the existing `.osddtrc` |
|
|
12
13
|
|
|
13
14
|
### `osddt setup` options
|
|
14
15
|
|
|
@@ -20,6 +21,8 @@ Other spec driven development tool but for monorepo
|
|
|
20
21
|
|
|
21
22
|
Both flags are optional. Providing neither runs the fully interactive mode. Providing both skips all prompts.
|
|
22
23
|
|
|
24
|
+
The selected agents are saved in `.osddtrc` alongside `repoType` so that `osddt update` can regenerate the correct files without prompting.
|
|
25
|
+
|
|
23
26
|
```bash
|
|
24
27
|
# Interactive (default)
|
|
25
28
|
npx @dezkareid/osddt setup
|
|
@@ -32,14 +35,74 @@ npx @dezkareid/osddt setup --agents claude,gemini --repo-type single
|
|
|
32
35
|
|
|
33
36
|
Run `npx @dezkareid/osddt setup` once to generate the agent command files.
|
|
34
37
|
|
|
35
|
-
`osddt.research` and `osddt.start` are **peer entry points** — use whichever fits your situation. Both lead to `osddt.spec`. If you close the coding session,
|
|
38
|
+
`osddt.research` and `osddt.start` are **peer entry points** — use whichever fits your situation. Both lead to `osddt.spec`. If you close the coding session, execute `osddt.continue` to resume the workflow.
|
|
39
|
+
|
|
40
|
+
```mermaid
|
|
41
|
+
flowchart LR
|
|
42
|
+
continue([osddt.continue])
|
|
43
|
+
|
|
44
|
+
subgraph entry[Entry points]
|
|
45
|
+
research([osddt.research])
|
|
46
|
+
start([osddt.start])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
spec([osddt.spec])
|
|
50
|
+
clarify([osddt.clarify\noptional])
|
|
51
|
+
plan([osddt.plan])
|
|
52
|
+
tasks([osddt.tasks])
|
|
53
|
+
implement([osddt.implement])
|
|
54
|
+
done([osddt.done])
|
|
55
|
+
|
|
56
|
+
research --> spec
|
|
57
|
+
start --> spec
|
|
58
|
+
spec --> clarify
|
|
59
|
+
clarify --> plan
|
|
60
|
+
spec --> plan
|
|
61
|
+
plan --> tasks
|
|
62
|
+
tasks --> implement
|
|
63
|
+
implement --> done
|
|
64
|
+
done --> continue
|
|
65
|
+
continue -.resume.-> spec & plan & tasks & implement & done
|
|
66
|
+
|
|
67
|
+
note["⚠️ You can go back to any step,\nbut once osddt.done runs\nthe feature is finished."]
|
|
68
|
+
done --- note
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Example workflows
|
|
72
|
+
|
|
73
|
+
#### Starting with research
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
/osddt.research add payment gateway
|
|
77
|
+
/osddt.spec add-payment-gateway
|
|
78
|
+
/osddt.clarify add-payment-gateway # optional — resolve open questions
|
|
79
|
+
/osddt.plan use Stripe SDK, REST endpoints, no webhooks
|
|
80
|
+
/osddt.tasks
|
|
81
|
+
/osddt.implement
|
|
82
|
+
/osddt.done
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### Starting directly
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
/osddt.start add user profile page
|
|
89
|
+
/osddt.spec add-user-profile-page
|
|
90
|
+
/osddt.plan React with React Query, REST API
|
|
91
|
+
/osddt.tasks
|
|
92
|
+
/osddt.implement
|
|
93
|
+
/osddt.done
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Resuming after closing a session
|
|
36
97
|
|
|
37
98
|
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
osddt.
|
|
41
|
-
|
|
42
|
-
osddt.
|
|
99
|
+
# You closed your agent session and want to pick up where you left off:
|
|
100
|
+
/osddt.continue add-payment-gateway
|
|
101
|
+
# → detects osddt.plan.md exists and reports:
|
|
102
|
+
# "Planning phase complete. Run: /osddt.tasks"
|
|
103
|
+
/osddt.tasks
|
|
104
|
+
/osddt.implement
|
|
105
|
+
/osddt.done
|
|
43
106
|
```
|
|
44
107
|
|
|
45
108
|
| Template | Description |
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -76,6 +76,29 @@ Use the following logic to determine \`<feature-name>\`:
|
|
|
76
76
|
- If there is **only one folder**, use it automatically and inform the user.
|
|
77
77
|
- If there are **multiple folders**, present the list to the user and ask them to pick one.
|
|
78
78
|
- If there are **no folders**, inform the user that no in-progress features were found and stop.`;
|
|
79
|
+
function getNextStepToSpec(args) {
|
|
80
|
+
return `## Next Step
|
|
81
|
+
|
|
82
|
+
- If ${args} was a **human-readable description** (not a branch name):
|
|
83
|
+
|
|
84
|
+
Your description will be used as the starting point for the spec. Run:
|
|
85
|
+
|
|
86
|
+
\`\`\`
|
|
87
|
+
/osddt.spec
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
> You can append more details if you want the spec to capture additional context.
|
|
91
|
+
|
|
92
|
+
- If ${args} was a **branch name** (or no arguments were provided):
|
|
93
|
+
|
|
94
|
+
Run the following command to write the feature specification:
|
|
95
|
+
|
|
96
|
+
\`\`\`
|
|
97
|
+
/osddt.spec <brief feature description, e.g. "add user authentication with JWT">
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
> Add a short description of what you're building so the spec has the right starting point.`;
|
|
101
|
+
}
|
|
79
102
|
const COMMAND_DEFINITIONS = [
|
|
80
103
|
{
|
|
81
104
|
name: 'osddt.continue',
|
|
@@ -145,13 +168,7 @@ The research file should include:
|
|
|
145
168
|
|
|
146
169
|
${args}
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
Run the following command to write the feature specification:
|
|
151
|
-
|
|
152
|
-
\`\`\`
|
|
153
|
-
/osddt.spec <brief description of the feature or topic researched>
|
|
154
|
-
\`\`\`
|
|
171
|
+
${getNextStepToSpec(args)}
|
|
155
172
|
`,
|
|
156
173
|
},
|
|
157
174
|
{
|
|
@@ -191,13 +208,7 @@ Where \`<feature-name>\` is the last segment of the branch name (after the last
|
|
|
191
208
|
|
|
192
209
|
${args}
|
|
193
210
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Run the following command to write the feature specification:
|
|
197
|
-
|
|
198
|
-
\`\`\`
|
|
199
|
-
/osddt.spec <brief description of the feature being built>
|
|
200
|
-
\`\`\`
|
|
211
|
+
${getNextStepToSpec(args)}
|
|
201
212
|
`,
|
|
202
213
|
},
|
|
203
214
|
{
|
|
@@ -205,10 +216,11 @@ Run the following command to write the feature specification:
|
|
|
205
216
|
description: 'Analyze requirements and write a feature specification',
|
|
206
217
|
body: ({ args }) => `## Instructions
|
|
207
218
|
|
|
208
|
-
1.
|
|
209
|
-
-
|
|
210
|
-
-
|
|
211
|
-
|
|
219
|
+
1. Gather requirements from all available sources — combine them when multiple sources are present:
|
|
220
|
+
- **Arguments** (${args}): use as the primary description of the feature, if provided.
|
|
221
|
+
- **Conversation context**: consider any additional details, clarifications, or constraints discussed in the current session that are not captured in ${args}.
|
|
222
|
+
- **Research file**: if \`osddt.research.md\` exists in the working directory, read it and incorporate its findings (key insights, constraints, open questions, codebase findings).
|
|
223
|
+
2. Analyze the combined requirements
|
|
212
224
|
3. Identify the core problem being solved
|
|
213
225
|
4. Define the scope, user-facing constraints, and acceptance criteria
|
|
214
226
|
5. Write the specification to \`osddt.spec.md\` in the working directory
|
|
@@ -225,6 +237,7 @@ The spec should include:
|
|
|
225
237
|
- **Open Questions**: Ambiguities about desired behaviour or product decisions to resolve
|
|
226
238
|
|
|
227
239
|
> If \`osddt.research.md\` was found, add a **Research Summary** section that briefly references the key insights and user-facing constraints it identified.
|
|
240
|
+
> If additional context was gathered from the conversation session, add a **Session Context** section summarising any extra details, decisions, or constraints discussed beyond what was passed as arguments.
|
|
228
241
|
|
|
229
242
|
## Arguments
|
|
230
243
|
|
|
@@ -513,7 +526,7 @@ function parseRepoType(raw) {
|
|
|
513
526
|
}
|
|
514
527
|
return raw;
|
|
515
528
|
}
|
|
516
|
-
async function writeCommandFile(file) {
|
|
529
|
+
async function writeCommandFile$1(file) {
|
|
517
530
|
await fs.ensureDir(path.dirname(file.filePath));
|
|
518
531
|
await fs.writeFile(file.filePath, file.content, 'utf-8');
|
|
519
532
|
console.log(` Created: ${file.filePath}`);
|
|
@@ -536,7 +549,7 @@ async function runSetup(cwd, rawAgents, rawRepoType) {
|
|
|
536
549
|
const claudeFiles = getClaudeTemplates(cwd, npxCommand);
|
|
537
550
|
console.log('Claude Code commands (.claude/commands/):');
|
|
538
551
|
for (const file of claudeFiles) {
|
|
539
|
-
await writeCommandFile(file);
|
|
552
|
+
await writeCommandFile$1(file);
|
|
540
553
|
}
|
|
541
554
|
console.log('');
|
|
542
555
|
}
|
|
@@ -544,11 +557,11 @@ async function runSetup(cwd, rawAgents, rawRepoType) {
|
|
|
544
557
|
const geminiFiles = getGeminiTemplates(cwd, npxCommand);
|
|
545
558
|
console.log('Gemini CLI commands (.gemini/commands/):');
|
|
546
559
|
for (const file of geminiFiles) {
|
|
547
|
-
await writeCommandFile(file);
|
|
560
|
+
await writeCommandFile$1(file);
|
|
548
561
|
}
|
|
549
562
|
console.log('');
|
|
550
563
|
}
|
|
551
|
-
await writeConfig(cwd, { repoType });
|
|
564
|
+
await writeConfig(cwd, { repoType, agents });
|
|
552
565
|
console.log('\nSetup complete!');
|
|
553
566
|
console.log('Commands created: osddt.spec, osddt.plan, osddt.tasks, osddt.implement');
|
|
554
567
|
}
|
|
@@ -623,6 +636,79 @@ function doneCommand() {
|
|
|
623
636
|
return cmd;
|
|
624
637
|
}
|
|
625
638
|
|
|
639
|
+
const AGENT_CONFIGS = {
|
|
640
|
+
claude: { dir: ['.claude', 'commands'], filePattern: /^osddt\..+\.md$/ },
|
|
641
|
+
gemini: { dir: ['.gemini', 'commands'], filePattern: /^osddt\..+\.toml$/ },
|
|
642
|
+
};
|
|
643
|
+
async function hasOsddtCommandFile(dir, pattern) {
|
|
644
|
+
if (!(await fs.pathExists(dir)))
|
|
645
|
+
return false;
|
|
646
|
+
const entries = await fs.readdir(dir);
|
|
647
|
+
return entries.some((f) => pattern.test(f));
|
|
648
|
+
}
|
|
649
|
+
async function inferAgents(cwd) {
|
|
650
|
+
const detected = [];
|
|
651
|
+
for (const [agent, config] of Object.entries(AGENT_CONFIGS)) {
|
|
652
|
+
const dir = path.join(cwd, ...config.dir);
|
|
653
|
+
if (await hasOsddtCommandFile(dir, config.filePattern)) {
|
|
654
|
+
detected.push(agent);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return detected;
|
|
658
|
+
}
|
|
659
|
+
async function writeCommandFile(file) {
|
|
660
|
+
await fs.writeFile(file.filePath, file.content, 'utf-8');
|
|
661
|
+
console.log(` Updated: ${file.filePath}`);
|
|
662
|
+
}
|
|
663
|
+
async function runUpdate(cwd) {
|
|
664
|
+
const configPath = path.join(cwd, '.osddtrc');
|
|
665
|
+
if (!(await fs.pathExists(configPath))) {
|
|
666
|
+
console.error('Error: .osddtrc not found. Run `osddt setup` first.');
|
|
667
|
+
process.exit(1);
|
|
668
|
+
}
|
|
669
|
+
const config = await fs.readJson(configPath);
|
|
670
|
+
const npxCommand = await resolveNpxCommand(cwd);
|
|
671
|
+
let agents = config.agents;
|
|
672
|
+
if (!agents || agents.length === 0) {
|
|
673
|
+
agents = await inferAgents(cwd);
|
|
674
|
+
if (agents.length === 0) {
|
|
675
|
+
console.error('Error: No agent command directories found. Run `osddt setup` first.');
|
|
676
|
+
process.exit(1);
|
|
677
|
+
}
|
|
678
|
+
await fs.writeJson(configPath, { ...config, agents }, { spaces: 2 });
|
|
679
|
+
console.log(`Inferred agents from command directories and saved to .osddtrc: ${agents.join(', ')}\n`);
|
|
680
|
+
}
|
|
681
|
+
console.log('Updating OSDDT command files...\n');
|
|
682
|
+
if (agents.includes('claude')) {
|
|
683
|
+
const claudeFiles = getClaudeTemplates(cwd, npxCommand);
|
|
684
|
+
console.log('Claude Code commands (.claude/commands/):');
|
|
685
|
+
for (const file of claudeFiles) {
|
|
686
|
+
await writeCommandFile(file);
|
|
687
|
+
}
|
|
688
|
+
console.log('');
|
|
689
|
+
}
|
|
690
|
+
if (agents.includes('gemini')) {
|
|
691
|
+
const geminiFiles = getGeminiTemplates(cwd, npxCommand);
|
|
692
|
+
console.log('Gemini CLI commands (.gemini/commands/):');
|
|
693
|
+
for (const file of geminiFiles) {
|
|
694
|
+
await writeCommandFile(file);
|
|
695
|
+
}
|
|
696
|
+
console.log('');
|
|
697
|
+
}
|
|
698
|
+
console.log('Update complete!');
|
|
699
|
+
}
|
|
700
|
+
function updateCommand() {
|
|
701
|
+
const cmd = new Command('update');
|
|
702
|
+
cmd
|
|
703
|
+
.description('Regenerate agent command files from the existing .osddtrc configuration')
|
|
704
|
+
.option('-d, --dir <directory>', 'target directory', process.cwd())
|
|
705
|
+
.action(async (options) => {
|
|
706
|
+
const targetDir = path.resolve(options.dir);
|
|
707
|
+
await runUpdate(targetDir);
|
|
708
|
+
});
|
|
709
|
+
return cmd;
|
|
710
|
+
}
|
|
711
|
+
|
|
626
712
|
const program = new Command();
|
|
627
713
|
program
|
|
628
714
|
.name('osddt')
|
|
@@ -631,4 +717,5 @@ program
|
|
|
631
717
|
program.addCommand(setupCommand());
|
|
632
718
|
program.addCommand(metaInfoCommand());
|
|
633
719
|
program.addCommand(doneCommand());
|
|
720
|
+
program.addCommand(updateCommand());
|
|
634
721
|
program.parse(process.argv);
|
|
@@ -2,6 +2,7 @@ export declare function getRepoPreamble(npxCommand: string): string;
|
|
|
2
2
|
export declare const FEATURE_NAME_RULES = "### Feature Name Constraints\n\nWhen deriving a feature name from a description:\n\n- Use only lowercase letters, digits, and hyphens (`a-z`, `0-9`, `-`)\n- Replace spaces and special characters with hyphens\n- Remove consecutive hyphens (e.g. `--` \u2192 `-`)\n- Remove leading and trailing hyphens\n- **Maximum length: 30 characters** \u2014 if the derived name exceeds 30 characters, truncate at the last hyphen boundary before or at the 30th character\n- If the input is already a valid branch name (no spaces, kebab-case or slash-separated), apply the 30-character limit to the last segment only (after the last `/`)\n- Reject (and ask the user to provide a shorter name) if no valid name can be derived after truncation\n\n**Examples:**\n\n| Input | Derived feature name |\n| ----------------------------------------------------- | ---------------------------- |\n| `Add user authentication` | `add-user-authentication` |\n| `Implement real-time notifications for dashboard` | `implement-real-time` |\n| `feat/add-user-authentication` | `add-user-authentication` |\n| `feat/implement-real-time-notifications-for-dashboard` | `implement-real-time` |\n";
|
|
3
3
|
export declare const WORKING_DIR_STEP = "Check whether the working directory `<project-path>/working-on/<feature-name>` already exists:\n - If it **does not exist**, create it:\n ```\n mkdir -p <project-path>/working-on/<feature-name>\n ```\n - If it **already exists**, warn the user and ask whether to:\n - **Resume** \u2014 continue into the existing folder (proceed to the next step without recreating it)\n - **Abort** \u2014 stop and do nothing";
|
|
4
4
|
export declare const RESOLVE_FEATURE_NAME = "### Resolving the Feature Name\n\nUse the following logic to determine `<feature-name>`:\n\n1. If arguments were provided, derive the feature name from them:\n - If the argument looks like a branch name (no spaces, kebab-case or slash-separated), use the last segment (after the last `/`, or the full value if no `/` is present).\n - Otherwise treat it as a human-readable description and convert it to a feature name following the constraints in the Feature Name Constraints section.\n2. If **no arguments were provided**:\n - List all folders under `<project-path>/working-on/`.\n - If there is **only one folder**, use it automatically and inform the user.\n - If there are **multiple folders**, present the list to the user and ask them to pick one.\n - If there are **no folders**, inform the user that no in-progress features were found and stop.";
|
|
5
|
+
export declare function getNextStepToSpec(args: ArgPlaceholder): string;
|
|
5
6
|
export type ArgPlaceholder = '$ARGUMENTS' | '{{args}}';
|
|
6
7
|
export interface CommandDefinitionContext {
|
|
7
8
|
args: ArgPlaceholder;
|