@dezkareid/osddt 1.9.0 → 1.10.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.
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function contextCommand(): Command;
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js CHANGED
@@ -99,6 +99,19 @@ function getNextStepToSpec(args) {
99
99
 
100
100
  > Add a short description of what you're building so the spec has the right starting point.`;
101
101
  }
102
+ function getCustomContextStep(npxCommand, commandName) {
103
+ return `## Custom Context
104
+
105
+ Run the following command and, if it returns content, use it as additional context before proceeding:
106
+
107
+ \`\`\`
108
+ ${npxCommand} context ${commandName}
109
+ \`\`\`
110
+
111
+ If the command returns no output, skip this section and continue.
112
+
113
+ `;
114
+ }
102
115
  const COMMAND_DEFINITIONS = [
103
116
  {
104
117
  name: 'osddt.continue',
@@ -122,7 +135,7 @@ Report which file was found, which phase that corresponds to, and the exact comm
122
135
 
123
136
  > **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
137
 
125
- ## Arguments
138
+ ${getCustomContextStep(npxCommand, 'continue')}## Arguments
126
139
 
127
140
  ${args}
128
141
  `,
@@ -164,7 +177,7 @@ The research file should include:
164
177
  - **Constraints & Risks**: Known limitations or risks uncovered during research
165
178
  - **Open Questions**: Ambiguities that the specification phase should resolve
166
179
 
167
- ## Arguments
180
+ ${getCustomContextStep(npxCommand, 'research')}## Arguments
168
181
 
169
182
  ${args}
170
183
 
@@ -204,7 +217,7 @@ Where \`<feature-name>\` is the last segment of the branch name (after the last
204
217
 
205
218
  5. Report the branch name and working directory that were created or resumed.
206
219
 
207
- ## Arguments
220
+ ${getCustomContextStep(npxCommand, 'start')}## Arguments
208
221
 
209
222
  ${args}
210
223
 
@@ -214,7 +227,7 @@ ${getNextStepToSpec(args)}
214
227
  {
215
228
  name: 'osddt.spec',
216
229
  description: 'Analyze requirements and write a feature specification',
217
- body: ({ args }) => `## Instructions
230
+ body: ({ args, npxCommand }) => `## Instructions
218
231
 
219
232
  1. Gather requirements from all available sources — combine them when multiple sources are present:
220
233
  - **Arguments** (${args}): use as the primary description of the feature, if provided.
@@ -242,7 +255,7 @@ The spec should include:
242
255
  > If \`osddt.research.md\` was found, add a **Research Summary** section that briefly references the key insights and user-facing constraints it identified.
243
256
  > 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
257
 
245
- ## Arguments
258
+ ${getCustomContextStep(npxCommand, 'spec')}## Arguments
246
259
 
247
260
  ${args}
248
261
 
@@ -258,7 +271,7 @@ Run the following command to create the implementation plan:
258
271
  {
259
272
  name: 'osddt.clarify',
260
273
  description: 'Resolve open questions in the spec and record decisions',
261
- body: () => `## Instructions
274
+ body: ({ npxCommand }) => `## Instructions
262
275
 
263
276
  1. Check whether \`osddt.spec.md\` exists in the working directory:
264
277
  - 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 +300,13 @@ Run the following command to create the implementation plan:
287
300
  \`\`\`
288
301
 
289
302
  > Note: if \`osddt.plan.md\` already exists, the plan should be regenerated to incorporate the decisions.
290
- `,
303
+
304
+ ${getCustomContextStep(npxCommand, 'clarify')}`,
291
305
  },
292
306
  {
293
307
  name: 'osddt.plan',
294
308
  description: 'Create a technical implementation plan from a specification',
295
- body: ({ args }) => `${RESOLVE_FEATURE_NAME}
309
+ body: ({ args, npxCommand }) => `${RESOLVE_FEATURE_NAME}
296
310
 
297
311
  ## Instructions
298
312
 
@@ -323,7 +337,7 @@ The plan should include:
323
337
  - **Risks & Mitigations**: Known risks and how to address them
324
338
  - **Out of Scope**: Explicitly what will not be built
325
339
 
326
- ## Arguments
340
+ ${getCustomContextStep(npxCommand, 'plan')}## Arguments
327
341
 
328
342
  ${args}
329
343
 
@@ -339,7 +353,7 @@ Run the following command to generate the task list:
339
353
  {
340
354
  name: 'osddt.tasks',
341
355
  description: 'Generate actionable tasks from an implementation plan',
342
- body: () => `${RESOLVE_FEATURE_NAME}
356
+ body: ({ npxCommand }) => `${RESOLVE_FEATURE_NAME}
343
357
 
344
358
  ## Instructions
345
359
 
@@ -361,7 +375,7 @@ The task list should include:
361
375
  - **Dependencies**: Note which tasks must complete before others
362
376
  - **Definition of Done**: Clear completion criteria per phase
363
377
 
364
- ## Next Step
378
+ ${getCustomContextStep(npxCommand, 'tasks')}## Next Step
365
379
 
366
380
  Run the following command to start implementing tasks:
367
381
 
@@ -373,7 +387,7 @@ Run the following command to start implementing tasks:
373
387
  {
374
388
  name: 'osddt.implement',
375
389
  description: 'Execute tasks from the task list one by one',
376
- body: () => `## Instructions
390
+ body: ({ npxCommand }) => `## Instructions
377
391
 
378
392
  1. Check whether \`osddt.tasks.md\` exists in the working directory:
379
393
  - If it **does not exist**, stop and ask the user to run \`/osddt.tasks\` first.
@@ -390,7 +404,7 @@ Run the following command to start implementing tasks:
390
404
  - Write tests for new functionality when applicable
391
405
  - Ask for clarification if requirements are ambiguous
392
406
 
393
- ## Next Step
407
+ ${getCustomContextStep(npxCommand, 'implement')}## Next Step
394
408
 
395
409
  Once all tasks are checked off, run the following command to mark the feature as done:
396
410
 
@@ -476,7 +490,7 @@ Display the full contents of \`osddt.tasks.md\` to the user. Then prompt them to
476
490
 
477
491
  > You can optionally run \`/osddt.clarify\` before implementing to resolve any Open Questions recorded in the spec.
478
492
 
479
- ## Arguments
493
+ ${getCustomContextStep(npxCommand, 'fast')}## Arguments
480
494
 
481
495
  ${args}
482
496
  `,
@@ -497,7 +511,8 @@ ${npxCommand} done <feature-name> --dir <project-path>
497
511
  For example, \`working-on/feature-a\` will be moved to \`done/YYYY-MM-DD-feature-a\`.
498
512
 
499
513
  3. Report the result of the command, including the full destination path
500
- `,
514
+
515
+ ${getCustomContextStep(npxCommand, 'done')}`,
501
516
  },
502
517
  ];
503
518
 
@@ -794,6 +809,64 @@ function updateCommand() {
794
809
  return cmd;
795
810
  }
796
811
 
812
+ const CONTEXT_DIR = 'osddt-context';
813
+ function stubContent(name) {
814
+ return `<!-- osddt context: ${name}
815
+ The content of this file will be shown to the agent under the "## Custom Context" section
816
+ when the osddt.${name} command is invoked. Add your project-specific instructions below. -->
817
+ `;
818
+ }
819
+ async function runRead(name, cwd) {
820
+ const filePath = path.join(cwd, CONTEXT_DIR, `${name}.md`);
821
+ let content;
822
+ try {
823
+ content = await fs.readFile(filePath, 'utf-8');
824
+ }
825
+ catch (err) {
826
+ if (err.code === 'ENOENT') {
827
+ return;
828
+ }
829
+ throw err;
830
+ }
831
+ process.stdout.write(content);
832
+ }
833
+ async function runInit(cwd) {
834
+ const contextDir = path.join(cwd, CONTEXT_DIR);
835
+ await fs.ensureDir(contextDir);
836
+ for (const cmd of COMMAND_DEFINITIONS) {
837
+ const name = cmd.name.replace(/^osddt\./, '');
838
+ const filePath = path.join(contextDir, `${name}.md`);
839
+ if (await fs.pathExists(filePath)) {
840
+ console.log(` Skipped (exists): ${CONTEXT_DIR}/${name}.md`);
841
+ }
842
+ else {
843
+ await fs.writeFile(filePath, stubContent(name), 'utf-8');
844
+ console.log(` Created: ${CONTEXT_DIR}/${name}.md`);
845
+ }
846
+ }
847
+ }
848
+ function contextCommand() {
849
+ const cmd = new Command('context');
850
+ cmd
851
+ .description('Output a custom context file or scaffold context stubs')
852
+ .argument('[name]', 'command name to read context for (e.g. plan, spec)')
853
+ .option('-d, --dir <directory>', 'project directory', process.cwd())
854
+ .option('--init', 'scaffold osddt-context/ with stub files for all commands')
855
+ .action(async (name, options) => {
856
+ const targetDir = path.resolve(options.dir);
857
+ if (options.init) {
858
+ await runInit(targetDir);
859
+ }
860
+ else if (name) {
861
+ await runRead(name, targetDir);
862
+ }
863
+ else {
864
+ cmd.help();
865
+ }
866
+ });
867
+ return cmd;
868
+ }
869
+
797
870
  const program = new Command();
798
871
  program
799
872
  .name('osddt')
@@ -803,4 +876,5 @@ program.addCommand(setupCommand());
803
876
  program.addCommand(metaInfoCommand());
804
877
  program.addCommand(doneCommand());
805
878
  program.addCommand(updateCommand());
879
+ program.addCommand(contextCommand());
806
880
  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.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Package for Spec-Driven Development workflow",
5
5
  "keywords": [
6
6
  "spec-driven",