@joshski/dust 0.1.26 → 0.1.29
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 +4 -1
- package/dist/workflow-tasks.d.ts +16 -1
- package/dist/workflow-tasks.js +61 -17
- package/package.json +1 -1
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.");
|
package/dist/workflow-tasks.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { FileSystem } from './cli/types';
|
|
2
2
|
export declare const IDEA_TRANSITION_PREFIXES: string[];
|
|
3
|
+
export declare const CAPTURE_IDEA_PREFIX = "Add Idea: ";
|
|
4
|
+
export interface IdeaInProgress {
|
|
5
|
+
taskSlug: string;
|
|
6
|
+
ideaTitle: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function findAllCaptureIdeaTasks(fileSystem: FileSystem, dustPath: string): Promise<IdeaInProgress[]>;
|
|
3
9
|
/**
|
|
4
10
|
* Converts a markdown title to the expected filename using deterministic rules:
|
|
5
11
|
* 1. Convert to lowercase
|
|
@@ -19,7 +25,16 @@ export declare function findWorkflowTask(fileSystem: FileSystem, dustPath: strin
|
|
|
19
25
|
export interface CreateIdeaTransitionTaskResult {
|
|
20
26
|
filePath: string;
|
|
21
27
|
}
|
|
28
|
+
export interface OpenQuestionResponse {
|
|
29
|
+
question: string;
|
|
30
|
+
chosenOption: string;
|
|
31
|
+
}
|
|
32
|
+
export interface CreateTaskFromIdeaOptions {
|
|
33
|
+
ideaSlug: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
openQuestionResponses?: OpenQuestionResponse[];
|
|
36
|
+
}
|
|
22
37
|
export declare function createRefineIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
|
|
23
|
-
export declare function createTaskFromIdea(fileSystem: FileSystem, dustPath: string,
|
|
38
|
+
export declare function createTaskFromIdea(fileSystem: FileSystem, dustPath: string, options: CreateTaskFromIdeaOptions): Promise<CreateIdeaTransitionTaskResult>;
|
|
24
39
|
export declare function createShelveIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
|
|
25
40
|
export declare function createCaptureIdeaTask(fileSystem: FileSystem, dustPath: string, title: string, description: string): Promise<CreateIdeaTransitionTaskResult>;
|
package/dist/workflow-tasks.js
CHANGED
|
@@ -4,6 +4,28 @@ var IDEA_TRANSITION_PREFIXES = [
|
|
|
4
4
|
"Create Task From Idea: ",
|
|
5
5
|
"Shelve Idea: "
|
|
6
6
|
];
|
|
7
|
+
var CAPTURE_IDEA_PREFIX = "Add Idea: ";
|
|
8
|
+
async function findAllCaptureIdeaTasks(fileSystem, dustPath) {
|
|
9
|
+
const tasksPath = `${dustPath}/tasks`;
|
|
10
|
+
if (!fileSystem.exists(tasksPath))
|
|
11
|
+
return [];
|
|
12
|
+
const files = await fileSystem.readdir(tasksPath);
|
|
13
|
+
const results = [];
|
|
14
|
+
for (const file of files.filter((f) => f.endsWith(".md")).sort()) {
|
|
15
|
+
const content = await fileSystem.readFile(`${tasksPath}/${file}`);
|
|
16
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
17
|
+
if (!titleMatch)
|
|
18
|
+
continue;
|
|
19
|
+
const title = titleMatch[1].trim();
|
|
20
|
+
if (title.startsWith(CAPTURE_IDEA_PREFIX)) {
|
|
21
|
+
results.push({
|
|
22
|
+
taskSlug: file.replace(/\.md$/, ""),
|
|
23
|
+
ideaTitle: title.slice(CAPTURE_IDEA_PREFIX.length)
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
7
29
|
function titleToFilename(title) {
|
|
8
30
|
return `${title.toLowerCase().replace(/\./g, "-").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
9
31
|
}
|
|
@@ -36,14 +58,28 @@ async function readIdeaTitle(fileSystem, dustPath, ideaSlug) {
|
|
|
36
58
|
}
|
|
37
59
|
return ideaTitleMatch[1].trim();
|
|
38
60
|
}
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
|
|
61
|
+
function renderResolvedQuestions(responses) {
|
|
62
|
+
const sections = responses.map((r) => `### ${r.question}
|
|
63
|
+
|
|
64
|
+
**Decision:** ${r.chosenOption}`);
|
|
65
|
+
return `## Resolved Questions
|
|
66
|
+
|
|
67
|
+
${sections.join(`
|
|
68
|
+
|
|
69
|
+
`)}
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
function renderTask(title, openingSentence, definitionOfDone, options) {
|
|
73
|
+
const descriptionParagraph = options?.description !== undefined ? `
|
|
74
|
+
${options.description}
|
|
75
|
+
` : "";
|
|
76
|
+
const resolvedSection = options?.resolvedQuestions && options.resolvedQuestions.length > 0 ? `
|
|
77
|
+
${renderResolvedQuestions(options.resolvedQuestions)}
|
|
42
78
|
` : "";
|
|
43
79
|
return `# ${title}
|
|
44
80
|
|
|
45
81
|
${openingSentence}
|
|
46
|
-
${descriptionParagraph}
|
|
82
|
+
${descriptionParagraph}${resolvedSection}
|
|
47
83
|
## Goals
|
|
48
84
|
|
|
49
85
|
(none)
|
|
@@ -58,30 +94,34 @@ ${definitionOfDone.map((item) => `- [ ] ${item}`).join(`
|
|
|
58
94
|
`)}
|
|
59
95
|
`;
|
|
60
96
|
}
|
|
61
|
-
async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone,
|
|
97
|
+
async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone, taskOptions) {
|
|
62
98
|
const ideaTitle = await readIdeaTitle(fileSystem, dustPath, ideaSlug);
|
|
63
99
|
const taskTitle = `${prefix}${ideaTitle}`;
|
|
64
100
|
const filename = titleToFilename(taskTitle);
|
|
65
101
|
const filePath = `${dustPath}/tasks/${filename}`;
|
|
66
102
|
const openingSentence = openingSentenceTemplate(ideaTitle);
|
|
67
|
-
const content = renderTask(taskTitle, openingSentence, definitionOfDone,
|
|
103
|
+
const content = renderTask(taskTitle, openingSentence, definitionOfDone, taskOptions);
|
|
68
104
|
await fileSystem.writeFile(filePath, content);
|
|
69
105
|
return { filePath };
|
|
70
106
|
}
|
|
71
107
|
async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description) {
|
|
72
|
-
return createIdeaTask(fileSystem, dustPath, "Refine Idea: ", ideaSlug, (ideaTitle) => `
|
|
73
|
-
"
|
|
108
|
+
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).`, [
|
|
109
|
+
"Idea is thoroughly researched with relevant codebase context",
|
|
110
|
+
"Open questions are added for any ambiguous or underspecified aspects",
|
|
74
111
|
"Idea file is updated with findings"
|
|
75
|
-
], description);
|
|
112
|
+
], { description });
|
|
76
113
|
}
|
|
77
|
-
async function createTaskFromIdea(fileSystem, dustPath,
|
|
78
|
-
return createIdeaTask(fileSystem, dustPath, "Create Task From Idea: ", ideaSlug, (ideaTitle) => `Create a well-defined task from this idea. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, [
|
|
114
|
+
async function createTaskFromIdea(fileSystem, dustPath, options) {
|
|
115
|
+
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
116
|
"A new task is created in .dust/tasks/",
|
|
80
117
|
"The original idea is deleted or updated to reflect remaining scope"
|
|
81
|
-
],
|
|
118
|
+
], {
|
|
119
|
+
description: options.description,
|
|
120
|
+
resolvedQuestions: options.openQuestionResponses
|
|
121
|
+
});
|
|
82
122
|
}
|
|
83
123
|
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);
|
|
124
|
+
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
125
|
}
|
|
86
126
|
async function createCaptureIdeaTask(fileSystem, dustPath, title, description) {
|
|
87
127
|
if (!title || !title.trim()) {
|
|
@@ -95,19 +135,23 @@ async function createCaptureIdeaTask(fileSystem, dustPath, title, description) {
|
|
|
95
135
|
const filePath = `${dustPath}/tasks/${filename}`;
|
|
96
136
|
const ideaFilename = titleToFilename(title);
|
|
97
137
|
const ideaPath = `.dust/ideas/${ideaFilename}`;
|
|
98
|
-
const content = renderTask(taskTitle, `
|
|
138
|
+
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
139
|
`Idea file exists at ${ideaPath}`,
|
|
100
|
-
`Idea file has an H1 title matching "${title}"
|
|
101
|
-
|
|
140
|
+
`Idea file has an H1 title matching "${title}"`,
|
|
141
|
+
"Idea includes relevant context from codebase exploration",
|
|
142
|
+
"Open questions are added for any ambiguous or underspecified aspects"
|
|
143
|
+
], { description });
|
|
102
144
|
await fileSystem.writeFile(filePath, content);
|
|
103
145
|
return { filePath };
|
|
104
146
|
}
|
|
105
147
|
export {
|
|
106
148
|
titleToFilename,
|
|
107
149
|
findWorkflowTask,
|
|
150
|
+
findAllCaptureIdeaTasks,
|
|
108
151
|
createTaskFromIdea,
|
|
109
152
|
createShelveIdeaTask,
|
|
110
153
|
createRefineIdeaTask,
|
|
111
154
|
createCaptureIdeaTask,
|
|
112
|
-
IDEA_TRANSITION_PREFIXES
|
|
155
|
+
IDEA_TRANSITION_PREFIXES,
|
|
156
|
+
CAPTURE_IDEA_PREFIX
|
|
113
157
|
};
|