@dezkareid/osddt 1.9.0 → 1.10.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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import path from 'path';
|
|
4
3
|
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
5
6
|
import select from '@inquirer/select';
|
|
6
7
|
import checkbox from '@inquirer/checkbox';
|
|
7
8
|
import { execSync } from 'child_process';
|
|
@@ -99,6 +100,19 @@ function getNextStepToSpec(args) {
|
|
|
99
100
|
|
|
100
101
|
> Add a short description of what you're building so the spec has the right starting point.`;
|
|
101
102
|
}
|
|
103
|
+
function getCustomContextStep(npxCommand, commandName) {
|
|
104
|
+
return `## Custom Context
|
|
105
|
+
|
|
106
|
+
Run the following command and, if it returns content, use it as additional context before proceeding:
|
|
107
|
+
|
|
108
|
+
\`\`\`
|
|
109
|
+
${npxCommand} context ${commandName}
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
If the command returns no output, skip this section and continue.
|
|
113
|
+
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
102
116
|
const COMMAND_DEFINITIONS = [
|
|
103
117
|
{
|
|
104
118
|
name: 'osddt.continue',
|
|
@@ -122,7 +136,7 @@ Report which file was found, which phase that corresponds to, and the exact comm
|
|
|
122
136
|
|
|
123
137
|
> **Open Questions check**: After reporting the phase, if the detected phase is **Spec done** or **Planning done**, also check whether \`osddt.spec.md\` contains any unanswered open questions (items in the **Open Questions** section with no corresponding entry in the **Decisions** section). If unanswered questions exist, inform the user and recommend running \`/osddt.clarify <feature-name>\` before (or in addition to) the suggested next command.
|
|
124
138
|
|
|
125
|
-
## Arguments
|
|
139
|
+
${getCustomContextStep(npxCommand, 'continue')}## Arguments
|
|
126
140
|
|
|
127
141
|
${args}
|
|
128
142
|
`,
|
|
@@ -164,7 +178,7 @@ The research file should include:
|
|
|
164
178
|
- **Constraints & Risks**: Known limitations or risks uncovered during research
|
|
165
179
|
- **Open Questions**: Ambiguities that the specification phase should resolve
|
|
166
180
|
|
|
167
|
-
## Arguments
|
|
181
|
+
${getCustomContextStep(npxCommand, 'research')}## Arguments
|
|
168
182
|
|
|
169
183
|
${args}
|
|
170
184
|
|
|
@@ -204,7 +218,7 @@ Where \`<feature-name>\` is the last segment of the branch name (after the last
|
|
|
204
218
|
|
|
205
219
|
5. Report the branch name and working directory that were created or resumed.
|
|
206
220
|
|
|
207
|
-
## Arguments
|
|
221
|
+
${getCustomContextStep(npxCommand, 'start')}## Arguments
|
|
208
222
|
|
|
209
223
|
${args}
|
|
210
224
|
|
|
@@ -214,7 +228,7 @@ ${getNextStepToSpec(args)}
|
|
|
214
228
|
{
|
|
215
229
|
name: 'osddt.spec',
|
|
216
230
|
description: 'Analyze requirements and write a feature specification',
|
|
217
|
-
body: ({ args }) => `## Instructions
|
|
231
|
+
body: ({ args, npxCommand }) => `## Instructions
|
|
218
232
|
|
|
219
233
|
1. Gather requirements from all available sources — combine them when multiple sources are present:
|
|
220
234
|
- **Arguments** (${args}): use as the primary description of the feature, if provided.
|
|
@@ -242,7 +256,7 @@ The spec should include:
|
|
|
242
256
|
> If \`osddt.research.md\` was found, add a **Research Summary** section that briefly references the key insights and user-facing constraints it identified.
|
|
243
257
|
> 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.
|
|
244
258
|
|
|
245
|
-
## Arguments
|
|
259
|
+
${getCustomContextStep(npxCommand, 'spec')}## Arguments
|
|
246
260
|
|
|
247
261
|
${args}
|
|
248
262
|
|
|
@@ -258,7 +272,7 @@ Run the following command to create the implementation plan:
|
|
|
258
272
|
{
|
|
259
273
|
name: 'osddt.clarify',
|
|
260
274
|
description: 'Resolve open questions in the spec and record decisions',
|
|
261
|
-
body: () => `## Instructions
|
|
275
|
+
body: ({ npxCommand }) => `## Instructions
|
|
262
276
|
|
|
263
277
|
1. Check whether \`osddt.spec.md\` exists in the working directory:
|
|
264
278
|
- If it **does not exist**, inform the user that no spec was found and suggest running \`/osddt.spec <brief feature description>\` first. Stop here.
|
|
@@ -287,12 +301,13 @@ Run the following command to create the implementation plan:
|
|
|
287
301
|
\`\`\`
|
|
288
302
|
|
|
289
303
|
> Note: if \`osddt.plan.md\` already exists, the plan should be regenerated to incorporate the decisions.
|
|
290
|
-
|
|
304
|
+
|
|
305
|
+
${getCustomContextStep(npxCommand, 'clarify')}`,
|
|
291
306
|
},
|
|
292
307
|
{
|
|
293
308
|
name: 'osddt.plan',
|
|
294
309
|
description: 'Create a technical implementation plan from a specification',
|
|
295
|
-
body: ({ args }) => `${RESOLVE_FEATURE_NAME}
|
|
310
|
+
body: ({ args, npxCommand }) => `${RESOLVE_FEATURE_NAME}
|
|
296
311
|
|
|
297
312
|
## Instructions
|
|
298
313
|
|
|
@@ -323,7 +338,7 @@ The plan should include:
|
|
|
323
338
|
- **Risks & Mitigations**: Known risks and how to address them
|
|
324
339
|
- **Out of Scope**: Explicitly what will not be built
|
|
325
340
|
|
|
326
|
-
## Arguments
|
|
341
|
+
${getCustomContextStep(npxCommand, 'plan')}## Arguments
|
|
327
342
|
|
|
328
343
|
${args}
|
|
329
344
|
|
|
@@ -339,7 +354,7 @@ Run the following command to generate the task list:
|
|
|
339
354
|
{
|
|
340
355
|
name: 'osddt.tasks',
|
|
341
356
|
description: 'Generate actionable tasks from an implementation plan',
|
|
342
|
-
body: () => `${RESOLVE_FEATURE_NAME}
|
|
357
|
+
body: ({ npxCommand }) => `${RESOLVE_FEATURE_NAME}
|
|
343
358
|
|
|
344
359
|
## Instructions
|
|
345
360
|
|
|
@@ -361,7 +376,7 @@ The task list should include:
|
|
|
361
376
|
- **Dependencies**: Note which tasks must complete before others
|
|
362
377
|
- **Definition of Done**: Clear completion criteria per phase
|
|
363
378
|
|
|
364
|
-
## Next Step
|
|
379
|
+
${getCustomContextStep(npxCommand, 'tasks')}## Next Step
|
|
365
380
|
|
|
366
381
|
Run the following command to start implementing tasks:
|
|
367
382
|
|
|
@@ -373,7 +388,7 @@ Run the following command to start implementing tasks:
|
|
|
373
388
|
{
|
|
374
389
|
name: 'osddt.implement',
|
|
375
390
|
description: 'Execute tasks from the task list one by one',
|
|
376
|
-
body: () => `## Instructions
|
|
391
|
+
body: ({ npxCommand }) => `## Instructions
|
|
377
392
|
|
|
378
393
|
1. Check whether \`osddt.tasks.md\` exists in the working directory:
|
|
379
394
|
- If it **does not exist**, stop and ask the user to run \`/osddt.tasks\` first.
|
|
@@ -390,7 +405,7 @@ Run the following command to start implementing tasks:
|
|
|
390
405
|
- Write tests for new functionality when applicable
|
|
391
406
|
- Ask for clarification if requirements are ambiguous
|
|
392
407
|
|
|
393
|
-
## Next Step
|
|
408
|
+
${getCustomContextStep(npxCommand, 'implement')}## Next Step
|
|
394
409
|
|
|
395
410
|
Once all tasks are checked off, run the following command to mark the feature as done:
|
|
396
411
|
|
|
@@ -476,7 +491,7 @@ Display the full contents of \`osddt.tasks.md\` to the user. Then prompt them to
|
|
|
476
491
|
|
|
477
492
|
> You can optionally run \`/osddt.clarify\` before implementing to resolve any Open Questions recorded in the spec.
|
|
478
493
|
|
|
479
|
-
## Arguments
|
|
494
|
+
${getCustomContextStep(npxCommand, 'fast')}## Arguments
|
|
480
495
|
|
|
481
496
|
${args}
|
|
482
497
|
`,
|
|
@@ -497,7 +512,8 @@ ${npxCommand} done <feature-name> --dir <project-path>
|
|
|
497
512
|
For example, \`working-on/feature-a\` will be moved to \`done/YYYY-MM-DD-feature-a\`.
|
|
498
513
|
|
|
499
514
|
3. Report the result of the command, including the full destination path
|
|
500
|
-
|
|
515
|
+
|
|
516
|
+
${getCustomContextStep(npxCommand, 'done')}`,
|
|
501
517
|
},
|
|
502
518
|
];
|
|
503
519
|
|
|
@@ -794,13 +810,76 @@ function updateCommand() {
|
|
|
794
810
|
return cmd;
|
|
795
811
|
}
|
|
796
812
|
|
|
813
|
+
const CONTEXT_DIR = 'osddt-context';
|
|
814
|
+
function stubContent(name) {
|
|
815
|
+
return `<!-- osddt context: ${name}
|
|
816
|
+
The content of this file will be shown to the agent under the "## Custom Context" section
|
|
817
|
+
when the osddt.${name} command is invoked. Add your project-specific instructions below. -->
|
|
818
|
+
`;
|
|
819
|
+
}
|
|
820
|
+
async function runRead(name, cwd) {
|
|
821
|
+
const filePath = path.join(cwd, CONTEXT_DIR, `${name}.md`);
|
|
822
|
+
let content;
|
|
823
|
+
try {
|
|
824
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
825
|
+
}
|
|
826
|
+
catch (err) {
|
|
827
|
+
if (err.code === 'ENOENT') {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
throw err;
|
|
831
|
+
}
|
|
832
|
+
process.stdout.write(content);
|
|
833
|
+
}
|
|
834
|
+
async function runInit(cwd) {
|
|
835
|
+
const contextDir = path.join(cwd, CONTEXT_DIR);
|
|
836
|
+
await fs.ensureDir(contextDir);
|
|
837
|
+
for (const cmd of COMMAND_DEFINITIONS) {
|
|
838
|
+
const name = cmd.name.replace(/^osddt\./, '');
|
|
839
|
+
const filePath = path.join(contextDir, `${name}.md`);
|
|
840
|
+
if (await fs.pathExists(filePath)) {
|
|
841
|
+
console.log(` Skipped (exists): ${CONTEXT_DIR}/${name}.md`);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
await fs.writeFile(filePath, stubContent(name), 'utf-8');
|
|
845
|
+
console.log(` Created: ${CONTEXT_DIR}/${name}.md`);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function contextCommand() {
|
|
850
|
+
const cmd = new Command('context');
|
|
851
|
+
cmd
|
|
852
|
+
.description('Output a custom context file or scaffold context stubs')
|
|
853
|
+
.argument('[name]', 'command name to read context for (e.g. plan, spec)')
|
|
854
|
+
.option('-d, --dir <directory>', 'project directory', process.cwd())
|
|
855
|
+
.option('--init', 'scaffold osddt-context/ with stub files for all commands')
|
|
856
|
+
.action(async (name, options) => {
|
|
857
|
+
const targetDir = path.resolve(options.dir);
|
|
858
|
+
if (options.init) {
|
|
859
|
+
await runInit(targetDir);
|
|
860
|
+
}
|
|
861
|
+
else if (name) {
|
|
862
|
+
await runRead(name, targetDir);
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
cmd.help();
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
return cmd;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
872
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
873
|
+
const pkgPath = path.join(__dirname$1, '..', 'package.json');
|
|
874
|
+
const pkg = fs.readJsonSync(pkgPath);
|
|
797
875
|
const program = new Command();
|
|
798
876
|
program
|
|
799
877
|
.name('osddt')
|
|
800
878
|
.description('Spec-Driven Development tooling for monorepos and single-package repos')
|
|
801
|
-
.version(
|
|
879
|
+
.version(pkg.version);
|
|
802
880
|
program.addCommand(setupCommand());
|
|
803
881
|
program.addCommand(metaInfoCommand());
|
|
804
882
|
program.addCommand(doneCommand());
|
|
805
883
|
program.addCommand(updateCommand());
|
|
884
|
+
program.addCommand(contextCommand());
|
|
806
885
|
program.parse(process.argv);
|
|
@@ -3,6 +3,7 @@ export declare const FEATURE_NAME_RULES = "### Feature Name Constraints\n\nWhen
|
|
|
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
5
|
export declare function getNextStepToSpec(args: ArgPlaceholder): string;
|
|
6
|
+
export declare function getCustomContextStep(npxCommand: string, commandName: string): string;
|
|
6
7
|
export type ArgPlaceholder = '$ARGUMENTS' | '{{args}}';
|
|
7
8
|
export interface CommandDefinitionContext {
|
|
8
9
|
args: ArgPlaceholder;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dezkareid/osddt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "Package for Spec-Driven Development workflow",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spec-driven",
|
|
@@ -40,10 +40,14 @@
|
|
|
40
40
|
"tslib": "2.8.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
+
"@commitlint/cli": "20.5.0",
|
|
44
|
+
"@commitlint/config-conventional": "20.5.0",
|
|
45
|
+
"@dezkareid/eslint-config-ts-base": "1.0.0",
|
|
43
46
|
"@rollup/plugin-typescript": "12.1.4",
|
|
44
47
|
"@types/fs-extra": "11.0.4",
|
|
45
48
|
"@types/node": "25.0.10",
|
|
46
49
|
"eslint": "9.39.2",
|
|
50
|
+
"husky": "9.1.7",
|
|
47
51
|
"prettier": "3.8.1",
|
|
48
52
|
"rollup": "4.56.0",
|
|
49
53
|
"typescript": "5.9.3",
|
|
@@ -56,6 +60,7 @@
|
|
|
56
60
|
"test:watch": "vitest",
|
|
57
61
|
"lint": "eslint src",
|
|
58
62
|
"format": "prettier --write src",
|
|
59
|
-
"setup-local": "pnpm run build && npx osddt setup --agents claude --repo-type single"
|
|
63
|
+
"setup-local": "pnpm run build && npx osddt setup --agents claude --repo-type single",
|
|
64
|
+
"update-local": "pnpm run build && npx osddt update"
|
|
60
65
|
}
|
|
61
66
|
}
|