@dezkareid/osddt 1.2.0 → 1.3.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 +30 -8
- package/README.md +47 -6
- package/dist/commands/setup.spec.d.ts +1 -0
- package/dist/index.js +47 -27
- package/package.json +2 -2
package/AGENTS.md
CHANGED
|
@@ -103,7 +103,7 @@ osddt/
|
|
|
103
103
|
├── src/
|
|
104
104
|
│ ├── index.ts # CLI entry point — wires Commander program and registers all commands
|
|
105
105
|
│ ├── commands/
|
|
106
|
-
│ │ ├── setup.ts # `osddt setup` — prompts for agents & repo type, writes command files and .osddtrc
|
|
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
109
|
│ ├── templates/
|
|
@@ -125,7 +125,7 @@ osddt/
|
|
|
125
125
|
#### Key relationships
|
|
126
126
|
|
|
127
127
|
- **`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
|
|
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
129
|
- **`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
130
|
- **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
131
|
|
|
@@ -133,11 +133,22 @@ osddt/
|
|
|
133
133
|
|
|
134
134
|
All commands available via `npx @dezkareid/osddt <command>`:
|
|
135
135
|
|
|
136
|
-
| Command
|
|
137
|
-
|
|
|
138
|
-
| `@dezkareid/osddt setup`
|
|
139
|
-
| `@dezkareid/osddt
|
|
140
|
-
| `@dezkareid/osddt
|
|
136
|
+
| Command | Description |
|
|
137
|
+
| -------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
138
|
+
| `@dezkareid/osddt setup` | Generate agent command files for Claude and Gemini |
|
|
139
|
+
| `@dezkareid/osddt setup --agents <list> --repo-type <type>` | Non-interactive setup (for CI/scripted environments) |
|
|
140
|
+
| `@dezkareid/osddt meta-info` | Output current branch and date as JSON |
|
|
141
|
+
| `@dezkareid/osddt done <feature-name> --dir <project-path>` | Move `working-on/<feature>` to `done/<feature>` |
|
|
142
|
+
|
|
143
|
+
#### `osddt setup` options
|
|
144
|
+
|
|
145
|
+
| Flag | Values | Description |
|
|
146
|
+
| ---- | ------ | ----------- |
|
|
147
|
+
| `--agents <list>` | `claude`, `gemini` (comma-separated) | Skip the agents prompt and use the provided value(s) |
|
|
148
|
+
| `--repo-type <type>` | `single`, `monorepo` | Skip the repo type prompt and use the provided value |
|
|
149
|
+
| `-d, --dir <directory>` | any path | Target directory (defaults to current working directory) |
|
|
150
|
+
|
|
151
|
+
Both flags are optional. Providing neither runs the fully interactive mode. Providing both skips all prompts.
|
|
141
152
|
|
|
142
153
|
### Command Templates
|
|
143
154
|
|
|
@@ -152,7 +163,7 @@ Templates are generated by `npx @dezkareid/osddt setup` and placed in each agent
|
|
|
152
163
|
| `osddt.plan` | Create a technical implementation plan from a specification |
|
|
153
164
|
| `osddt.tasks` | Generate actionable tasks from an implementation plan |
|
|
154
165
|
| `osddt.implement` | Execute tasks from the task list one by one |
|
|
155
|
-
| `osddt.done` |
|
|
166
|
+
| `osddt.done` | Resolve project path, verify tasks, and move the feature to done |
|
|
156
167
|
|
|
157
168
|
#### Template Workflow
|
|
158
169
|
|
|
@@ -203,6 +214,17 @@ osddt.start ──┘
|
|
|
203
214
|
2. Checks for an existing `working-on/<feature-name>/` folder — offers **Resume** or **Abort** if found, otherwise creates it.
|
|
204
215
|
3. Researches the topic (codebase exploration, external references) and writes `osddt.research.md`.
|
|
205
216
|
|
|
217
|
+
#### osddt.done behaviour
|
|
218
|
+
|
|
219
|
+
- **Input**: A feature name or branch name identifying the feature to close.
|
|
220
|
+
- **Actions performed by the agent**:
|
|
221
|
+
1. Reads `.osddtrc` to resolve the project path (single vs monorepo). For monorepos, asks the user which package.
|
|
222
|
+
2. Derives the feature name from the input (same rules as other commands — last segment of a branch name or kebab-cased slug, subject to the 30-character limit). Must match the folder under `working-on/`.
|
|
223
|
+
3. Confirms all tasks in `osddt.tasks.md` are checked off (`- [x]`).
|
|
224
|
+
4. Runs `npx @dezkareid/osddt done <feature-name> --dir <project-path>` to move the folder.
|
|
225
|
+
|
|
226
|
+
Note: the `osddt done` CLI command does **not** read `.osddtrc` — project path resolution is the agent's responsibility, handled in step 1 above.
|
|
227
|
+
|
|
206
228
|
### Template Data Convention
|
|
207
229
|
|
|
208
230
|
When a template needs dynamic information (e.g. current branch, date, repo config), **do not pass it as a build-time argument**. Instead:
|
package/README.md
CHANGED
|
@@ -3,11 +3,30 @@ Other spec driven development tool but for monorepo
|
|
|
3
3
|
|
|
4
4
|
## CLI Commands
|
|
5
5
|
|
|
6
|
-
| Command
|
|
7
|
-
|
|
|
8
|
-
| `@dezkareid/osddt setup`
|
|
9
|
-
| `@dezkareid/osddt
|
|
10
|
-
| `@dezkareid/osddt
|
|
6
|
+
| Command | Description |
|
|
7
|
+
| -------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
8
|
+
| `@dezkareid/osddt setup` | Generate agent command files for Claude and Gemini |
|
|
9
|
+
| `@dezkareid/osddt setup --agents <list> --repo-type <type>` | Non-interactive setup (for CI/scripted environments) |
|
|
10
|
+
| `@dezkareid/osddt meta-info` | Output current branch and date as JSON |
|
|
11
|
+
| `@dezkareid/osddt done <feature-name> --dir <project-path>` | Move `working-on/<feature>` to `done/<feature>` |
|
|
12
|
+
|
|
13
|
+
### `osddt setup` options
|
|
14
|
+
|
|
15
|
+
| Flag | Values | Description |
|
|
16
|
+
| ---- | ------ | ----------- |
|
|
17
|
+
| `--agents <list>` | `claude`, `gemini` (comma-separated) | Skip the agents prompt and use the provided value(s) |
|
|
18
|
+
| `--repo-type <type>` | `single`, `monorepo` | Skip the repo type prompt and use the provided value |
|
|
19
|
+
| `-d, --dir <directory>` | any path | Target directory (defaults to current working directory) |
|
|
20
|
+
|
|
21
|
+
Both flags are optional. Providing neither runs the fully interactive mode. Providing both skips all prompts.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Interactive (default)
|
|
25
|
+
npx @dezkareid/osddt setup
|
|
26
|
+
|
|
27
|
+
# Non-interactive (CI-friendly)
|
|
28
|
+
npx @dezkareid/osddt setup --agents claude,gemini --repo-type single
|
|
29
|
+
```
|
|
11
30
|
|
|
12
31
|
## Command Templates
|
|
13
32
|
|
|
@@ -32,9 +51,31 @@ osddt.start ──┘
|
|
|
32
51
|
| `osddt.plan` | Create a technical implementation plan from a specification |
|
|
33
52
|
| `osddt.tasks` | Generate actionable tasks from an implementation plan |
|
|
34
53
|
| `osddt.implement` | Execute tasks from the task list one by one |
|
|
35
|
-
| `osddt.done` |
|
|
54
|
+
| `osddt.done` | Resolve project path, verify tasks, and move the feature to done |
|
|
36
55
|
|
|
37
56
|
Generated files are placed in:
|
|
38
57
|
|
|
39
58
|
- `.claude/commands/osddt.<name>.md` (Claude Code)
|
|
40
59
|
- `.gemini/commands/osddt.<name>.toml` (Gemini CLI)
|
|
60
|
+
|
|
61
|
+
## Development
|
|
62
|
+
|
|
63
|
+
### Running Tests
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Run the full test suite once
|
|
67
|
+
pnpm test
|
|
68
|
+
|
|
69
|
+
# Run in watch mode during development
|
|
70
|
+
pnpm run test:watch
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Local Setup
|
|
74
|
+
|
|
75
|
+
After making changes to the source, rebuild and regenerate the agent command files in the repository:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pnpm run setup-local
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This runs `pnpm run build` followed by `npx osddt setup`, prompting you to select which agents to configure and the repo type.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -224,13 +224,13 @@ Run the following command to create the implementation plan:
|
|
|
224
224
|
description: 'Create a technical implementation plan from a specification',
|
|
225
225
|
body: (args) => `## Instructions
|
|
226
226
|
|
|
227
|
-
1.
|
|
228
|
-
2. Check whether \`osddt.plan.md\` already exists in the working directory:
|
|
227
|
+
1. Check whether \`osddt.plan.md\` already exists in the working directory:
|
|
229
228
|
- If it **does not exist**, proceed to generate it.
|
|
230
229
|
- If it **already exists**, ask the user whether to:
|
|
231
230
|
- **Regenerate** — discard the existing file and create a fresh plan from scratch
|
|
232
231
|
- **Update** — read the existing file and apply targeted changes based on ${args}
|
|
233
232
|
- **Do nothing** — stop here and leave the file as-is
|
|
233
|
+
2. Read \`osddt.spec.md\` from the working directory
|
|
234
234
|
3. Break down the implementation into logical phases and steps
|
|
235
235
|
4. Identify technical decisions, dependencies, and risks
|
|
236
236
|
5. Write the plan to \`osddt.plan.md\` in the working directory
|
|
@@ -262,13 +262,13 @@ Run the following command to generate the task list:
|
|
|
262
262
|
description: 'Generate actionable tasks from an implementation plan',
|
|
263
263
|
body: (args) => `## Instructions
|
|
264
264
|
|
|
265
|
-
1.
|
|
266
|
-
2. Check whether \`osddt.tasks.md\` already exists in the working directory:
|
|
265
|
+
1. Check whether \`osddt.tasks.md\` already exists in the working directory:
|
|
267
266
|
- If it **does not exist**, proceed to generate it.
|
|
268
267
|
- If it **already exists**, ask the user whether to:
|
|
269
268
|
- **Regenerate** — discard the existing file and create a fresh task list from scratch
|
|
270
269
|
- **Update** — read the existing file and apply targeted changes based on ${args}
|
|
271
270
|
- **Do nothing** — stop here and leave the file as-is
|
|
271
|
+
2. Read \`osddt.plan.md\` from the working directory
|
|
272
272
|
3. Break each phase into discrete, executable tasks
|
|
273
273
|
4. Estimate complexity (S/M/L) for each task
|
|
274
274
|
5. Write the task list to \`osddt.tasks.md\` in the working directory
|
|
@@ -301,10 +301,6 @@ Run the following command to start implementing tasks:
|
|
|
301
301
|
|
|
302
302
|
1. Check whether \`osddt.tasks.md\` exists in the working directory:
|
|
303
303
|
- If it **does not exist**, stop and ask the user to run \`/osddt.tasks ${args}\` first.
|
|
304
|
-
- If it **already exists**, ask the user whether to:
|
|
305
|
-
- **Continue** — find the next unchecked task and implement it (default)
|
|
306
|
-
- **Update tasks** — edit \`osddt.tasks.md\` before implementing (e.g. to add, remove, or reorder tasks)
|
|
307
|
-
- **Do nothing** — stop here without making any changes
|
|
308
304
|
2. Read \`osddt.tasks.md\` from the working directory
|
|
309
305
|
3. Find the next unchecked task (\`- [ ]\`)
|
|
310
306
|
4. Implement that task following the spec (\`osddt.spec.md\`) and plan (\`osddt.plan.md\`) in the working directory
|
|
@@ -336,17 +332,22 @@ Once all tasks are checked off, run the following command to mark the feature as
|
|
|
336
332
|
description: 'Mark a feature as done and move it from working-on to done',
|
|
337
333
|
body: (args) => `## Instructions
|
|
338
334
|
|
|
339
|
-
1.
|
|
340
|
-
|
|
335
|
+
1. Resolve the project path:
|
|
336
|
+
- Read \`.osddtrc\` from the repository root.
|
|
337
|
+
- If \`repoType\` is \`"single"\`: the project path is the repository root.
|
|
338
|
+
- 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.
|
|
339
|
+
2. Derive the feature name from ${args} using the same rules as the other commands (last segment of a branch name, or a kebab-cased slug — subject to the 30-character limit). This must match the folder name under \`working-on/\`.
|
|
340
|
+
3. Confirm all tasks in \`osddt.tasks.md\` are checked off (\`- [x]\`)
|
|
341
|
+
4. Run the following command to move the feature folder from \`working-on\` to \`done\`:
|
|
341
342
|
|
|
342
343
|
\`\`\`
|
|
343
|
-
npx @dezkareid/osddt done
|
|
344
|
+
npx @dezkareid/osddt done <feature-name> --dir <project-path>
|
|
344
345
|
\`\`\`
|
|
345
346
|
|
|
346
347
|
The command will automatically prefix the destination folder name with today's date in \`YYYY-MM-DD\` format.
|
|
347
348
|
For example, \`working-on/feature-a\` will be moved to \`done/YYYY-MM-DD-feature-a\`.
|
|
348
349
|
|
|
349
|
-
|
|
350
|
+
5. Report the result of the command, including the full destination path
|
|
350
351
|
|
|
351
352
|
## Arguments
|
|
352
353
|
|
|
@@ -428,6 +429,28 @@ async function askAgents() {
|
|
|
428
429
|
});
|
|
429
430
|
}
|
|
430
431
|
|
|
432
|
+
const VALID_AGENTS = ['claude', 'gemini'];
|
|
433
|
+
const VALID_REPO_TYPES = ['single', 'monorepo'];
|
|
434
|
+
function parseAgents(raw) {
|
|
435
|
+
const values = raw.split(',').map((s) => s.trim());
|
|
436
|
+
if (values.length === 0) {
|
|
437
|
+
console.error('Error: --agents requires at least one value.');
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
const invalid = values.filter((v) => !VALID_AGENTS.includes(v));
|
|
441
|
+
if (invalid.length > 0) {
|
|
442
|
+
console.error(`Error: Invalid agent(s): ${invalid.join(', ')}. Valid values: ${VALID_AGENTS.join(', ')}.`);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
return values;
|
|
446
|
+
}
|
|
447
|
+
function parseRepoType(raw) {
|
|
448
|
+
if (!VALID_REPO_TYPES.includes(raw)) {
|
|
449
|
+
console.error(`Error: Invalid repo type: "${raw}". Valid values: ${VALID_REPO_TYPES.join(', ')}.`);
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
return raw;
|
|
453
|
+
}
|
|
431
454
|
async function writeCommandFile(file) {
|
|
432
455
|
await fs.ensureDir(path.dirname(file.filePath));
|
|
433
456
|
await fs.writeFile(file.filePath, file.content, 'utf-8');
|
|
@@ -438,11 +461,13 @@ async function writeConfig(cwd, config) {
|
|
|
438
461
|
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
439
462
|
console.log(`\nSaved config: ${configPath}`);
|
|
440
463
|
}
|
|
441
|
-
async function runSetup(cwd) {
|
|
442
|
-
const agents = await askAgents();
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
464
|
+
async function runSetup(cwd, rawAgents, rawRepoType) {
|
|
465
|
+
const agents = rawAgents !== undefined ? parseAgents(rawAgents) : await askAgents();
|
|
466
|
+
if (rawAgents === undefined)
|
|
467
|
+
console.log('');
|
|
468
|
+
const repoType = rawRepoType !== undefined ? parseRepoType(rawRepoType) : await askRepoType();
|
|
469
|
+
if (rawRepoType === undefined)
|
|
470
|
+
console.log('');
|
|
446
471
|
console.log('Setting up OSDDT command files...\n');
|
|
447
472
|
if (agents.includes('claude')) {
|
|
448
473
|
const claudeFiles = getClaudeTemplates(cwd);
|
|
@@ -469,9 +494,11 @@ function setupCommand() {
|
|
|
469
494
|
cmd
|
|
470
495
|
.description('Create OSDDT command files for Claude and Gemini CLI agents')
|
|
471
496
|
.option('-d, --dir <directory>', 'target directory', process.cwd())
|
|
497
|
+
.option('--agents <list>', 'comma-separated agents to set up (claude, gemini)')
|
|
498
|
+
.option('--repo-type <type>', 'repository type (single, monorepo)')
|
|
472
499
|
.action(async (options) => {
|
|
473
500
|
const targetDir = path.resolve(options.dir);
|
|
474
|
-
await runSetup(targetDir);
|
|
501
|
+
await runSetup(targetDir, options.agents, options.repoType);
|
|
475
502
|
});
|
|
476
503
|
return cmd;
|
|
477
504
|
}
|
|
@@ -509,16 +536,9 @@ function todayPrefix() {
|
|
|
509
536
|
return `${yyyy}-${mm}-${dd}`;
|
|
510
537
|
}
|
|
511
538
|
async function runDone(featureName, cwd) {
|
|
512
|
-
const
|
|
513
|
-
if (!(await fs.pathExists(configPath))) {
|
|
514
|
-
console.error('Error: .osddtrc not found. Run `osddt setup` first.');
|
|
515
|
-
process.exit(1);
|
|
516
|
-
}
|
|
517
|
-
await fs.readJson(configPath);
|
|
518
|
-
const projectPath = cwd;
|
|
519
|
-
const src = path.join(projectPath, 'working-on', featureName);
|
|
539
|
+
const src = path.join(cwd, 'working-on', featureName);
|
|
520
540
|
const destName = `${todayPrefix()}-${featureName}`;
|
|
521
|
-
const dest = path.join(
|
|
541
|
+
const dest = path.join(cwd, 'done', destName);
|
|
522
542
|
if (!(await fs.pathExists(src))) {
|
|
523
543
|
console.error(`Error: working-on/${featureName} does not exist.`);
|
|
524
544
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dezkareid/osddt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Package for Spec-Driven Development workflow",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spec-driven",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"test:watch": "vitest",
|
|
57
57
|
"lint": "eslint src",
|
|
58
58
|
"format": "prettier --write src",
|
|
59
|
-
"setup-local": "pnpm run build && npx osddt setup"
|
|
59
|
+
"setup-local": "pnpm run build && npx osddt setup --agents claude --repo-type single"
|
|
60
60
|
}
|
|
61
61
|
}
|