@joshski/dust 0.1.26 → 0.1.28

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/dist/dust.js CHANGED
@@ -2209,6 +2209,10 @@ async function getUncommittedFiles(cwd, gitRunner) {
2209
2209
  }
2210
2210
  async function prePush(dependencies, gitRunner = defaultGitRunner, env = process.env) {
2211
2211
  const { context } = dependencies;
2212
+ const agent2 = detectAgent(env);
2213
+ if (agent2.type === "unknown") {
2214
+ return { exitCode: 0 };
2215
+ }
2212
2216
  if (env.DUST_UNATTENDED) {
2213
2217
  const uncommittedFiles = await getUncommittedFiles(context.cwd, gitRunner);
2214
2218
  if (uncommittedFiles.length > 0) {
@@ -2228,7 +2232,6 @@ async function prePush(dependencies, gitRunner = defaultGitRunner, env = process
2228
2232
  const changes = await getChangesFromRemote(context.cwd, gitRunner);
2229
2233
  if (changes.length > 0) {
2230
2234
  const analysis = analyzeChangesForTaskOnlyPattern(changes);
2231
- const agent2 = detectAgent(env);
2232
2235
  if (analysis.isTaskOnly && agent2.type === "claude-code-web") {
2233
2236
  context.stderr("");
2234
2237
  context.stderr("⚠️ Task-only commit detected! You added a task but did not implement it.");
@@ -19,7 +19,16 @@ export declare function findWorkflowTask(fileSystem: FileSystem, dustPath: strin
19
19
  export interface CreateIdeaTransitionTaskResult {
20
20
  filePath: string;
21
21
  }
22
+ export interface OpenQuestionResponse {
23
+ question: string;
24
+ chosenOption: string;
25
+ }
26
+ export interface CreateTaskFromIdeaOptions {
27
+ ideaSlug: string;
28
+ description?: string;
29
+ openQuestionResponses?: OpenQuestionResponse[];
30
+ }
22
31
  export declare function createRefineIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
23
- export declare function createTaskFromIdea(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
32
+ export declare function createTaskFromIdea(fileSystem: FileSystem, dustPath: string, options: CreateTaskFromIdeaOptions): Promise<CreateIdeaTransitionTaskResult>;
24
33
  export declare function createShelveIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
25
34
  export declare function createCaptureIdeaTask(fileSystem: FileSystem, dustPath: string, title: string, description: string): Promise<CreateIdeaTransitionTaskResult>;
@@ -36,14 +36,28 @@ async function readIdeaTitle(fileSystem, dustPath, ideaSlug) {
36
36
  }
37
37
  return ideaTitleMatch[1].trim();
38
38
  }
39
- function renderTask(title, openingSentence, definitionOfDone, description) {
40
- const descriptionParagraph = description !== undefined ? `
41
- ${description}
39
+ function renderResolvedQuestions(responses) {
40
+ const sections = responses.map((r) => `### ${r.question}
41
+
42
+ **Decision:** ${r.chosenOption}`);
43
+ return `## Resolved Questions
44
+
45
+ ${sections.join(`
46
+
47
+ `)}
48
+ `;
49
+ }
50
+ function renderTask(title, openingSentence, definitionOfDone, options) {
51
+ const descriptionParagraph = options?.description !== undefined ? `
52
+ ${options.description}
53
+ ` : "";
54
+ const resolvedSection = options?.resolvedQuestions && options.resolvedQuestions.length > 0 ? `
55
+ ${renderResolvedQuestions(options.resolvedQuestions)}
42
56
  ` : "";
43
57
  return `# ${title}
44
58
 
45
59
  ${openingSentence}
46
- ${descriptionParagraph}
60
+ ${descriptionParagraph}${resolvedSection}
47
61
  ## Goals
48
62
 
49
63
  (none)
@@ -58,30 +72,34 @@ ${definitionOfDone.map((item) => `- [ ] ${item}`).join(`
58
72
  `)}
59
73
  `;
60
74
  }
61
- async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone, description) {
75
+ async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone, taskOptions) {
62
76
  const ideaTitle = await readIdeaTitle(fileSystem, dustPath, ideaSlug);
63
77
  const taskTitle = `${prefix}${ideaTitle}`;
64
78
  const filename = titleToFilename(taskTitle);
65
79
  const filePath = `${dustPath}/tasks/${filename}`;
66
80
  const openingSentence = openingSentenceTemplate(ideaTitle);
67
- const content = renderTask(taskTitle, openingSentence, definitionOfDone, description);
81
+ const content = renderTask(taskTitle, openingSentence, definitionOfDone, taskOptions);
68
82
  await fileSystem.writeFile(filePath, content);
69
83
  return { filePath };
70
84
  }
71
85
  async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description) {
72
- return createIdeaTask(fileSystem, dustPath, "Refine Idea: ", ideaSlug, (ideaTitle) => `Research and refine this idea into a well-defined proposal. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, [
73
- "Open questions are identified and resolved",
86
+ return createIdeaTask(fileSystem, dustPath, "Refine Idea: ", ideaSlug, (ideaTitle) => `Thoroughly research this idea and refine it into a well-defined proposal. Read the idea file, explore the codebase for relevant context, and identify any ambiguity. Where aspects are unclear or could go multiple ways, add open questions to the idea file. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, [
87
+ "Idea is thoroughly researched with relevant codebase context",
88
+ "Open questions are added for any ambiguous or underspecified aspects",
74
89
  "Idea file is updated with findings"
75
- ], description);
90
+ ], { description });
76
91
  }
77
- async function createTaskFromIdea(fileSystem, dustPath, ideaSlug, description) {
78
- return createIdeaTask(fileSystem, dustPath, "Create Task From Idea: ", ideaSlug, (ideaTitle) => `Create a well-defined task from this idea. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, [
92
+ async function createTaskFromIdea(fileSystem, dustPath, options) {
93
+ return createIdeaTask(fileSystem, dustPath, "Create Task From Idea: ", options.ideaSlug, (ideaTitle) => `Create a well-defined task from this idea. See [${ideaTitle}](../ideas/${options.ideaSlug}.md).`, [
79
94
  "A new task is created in .dust/tasks/",
80
95
  "The original idea is deleted or updated to reflect remaining scope"
81
- ], description);
96
+ ], {
97
+ description: options.description,
98
+ resolvedQuestions: options.openQuestionResponses
99
+ });
82
100
  }
83
101
  async function createShelveIdeaTask(fileSystem, dustPath, ideaSlug, description) {
84
- return createIdeaTask(fileSystem, dustPath, "Shelve Idea: ", ideaSlug, (ideaTitle) => `Archive this idea and remove it from the active backlog. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, ["Idea file is deleted", "Rationale is recorded in the commit message"], description);
102
+ return createIdeaTask(fileSystem, dustPath, "Shelve Idea: ", ideaSlug, (ideaTitle) => `Archive this idea and remove it from the active backlog. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, ["Idea file is deleted", "Rationale is recorded in the commit message"], { description });
85
103
  }
86
104
  async function createCaptureIdeaTask(fileSystem, dustPath, title, description) {
87
105
  if (!title || !title.trim()) {
@@ -95,10 +113,12 @@ async function createCaptureIdeaTask(fileSystem, dustPath, title, description) {
95
113
  const filePath = `${dustPath}/tasks/${filename}`;
96
114
  const ideaFilename = titleToFilename(title);
97
115
  const ideaPath = `.dust/ideas/${ideaFilename}`;
98
- const content = renderTask(taskTitle, `Create a new idea file at \`${ideaPath}\` with the title "${title}" and the following description:`, [
116
+ const content = renderTask(taskTitle, `Research this idea thoroughly, then create an idea file at \`${ideaPath}\`. Read the codebase for relevant context, flesh out the description, and identify any ambiguity. Where aspects are unclear or could go multiple ways, add open questions to the idea file. The idea should have the title "${title}" and start from the following description:`, [
99
117
  `Idea file exists at ${ideaPath}`,
100
- `Idea file has an H1 title matching "${title}"`
101
- ], description);
118
+ `Idea file has an H1 title matching "${title}"`,
119
+ "Idea includes relevant context from codebase exploration",
120
+ "Open questions are added for any ambiguous or underspecified aspects"
121
+ ], { description });
102
122
  await fileSystem.writeFile(filePath, content);
103
123
  return { filePath };
104
124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joshski/dust",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Flow state for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {