@joshski/dust 0.1.30 → 0.1.31
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 +8 -0
- package/dist/workflow-tasks.js +4 -3
- package/lib/istanbul/minimal-reporter.cjs +90 -0
- package/package.json +5 -3
package/dist/dust.js
CHANGED
|
@@ -589,6 +589,14 @@ function validateIdeaOpenQuestions(filePath, content) {
|
|
|
589
589
|
line: currentQuestionLine
|
|
590
590
|
});
|
|
591
591
|
}
|
|
592
|
+
const headingText = line.slice(3).trimEnd();
|
|
593
|
+
if (headingText.toLowerCase() === "open questions" && headingText !== "Open Questions") {
|
|
594
|
+
violations.push({
|
|
595
|
+
file: filePath,
|
|
596
|
+
message: `Heading "${line.trimEnd()}" should be "## Open Questions"`,
|
|
597
|
+
line: i + 1
|
|
598
|
+
});
|
|
599
|
+
}
|
|
592
600
|
inOpenQuestions = line === "## Open Questions";
|
|
593
601
|
currentQuestionLine = null;
|
|
594
602
|
continue;
|
package/dist/workflow-tasks.js
CHANGED
|
@@ -105,15 +105,16 @@ async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSen
|
|
|
105
105
|
return { filePath };
|
|
106
106
|
}
|
|
107
107
|
async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description) {
|
|
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).`, [
|
|
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. Review \`.dust/goals/\` for alignment and \`.dust/facts/\` for relevant design decisions. See [${ideaTitle}](../ideas/${ideaSlug}.md).`, [
|
|
109
109
|
"Idea is thoroughly researched with relevant codebase context",
|
|
110
110
|
"Open questions are added for any ambiguous or underspecified aspects",
|
|
111
111
|
"Idea file is updated with findings"
|
|
112
112
|
], { description });
|
|
113
113
|
}
|
|
114
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).`, [
|
|
115
|
+
return createIdeaTask(fileSystem, dustPath, "Create Task From Idea: ", options.ideaSlug, (ideaTitle) => `Create a well-defined task from this idea. Review \`.dust/goals/\` to link relevant goals and \`.dust/facts/\` for design decisions that should inform the task. See [${ideaTitle}](../ideas/${options.ideaSlug}.md).`, [
|
|
116
116
|
"A new task is created in .dust/tasks/",
|
|
117
|
+
"Task's Goals section links to relevant goals from .dust/goals/",
|
|
117
118
|
"The original idea is deleted or updated to reflect remaining scope"
|
|
118
119
|
], {
|
|
119
120
|
description: options.description,
|
|
@@ -135,7 +136,7 @@ async function createCaptureIdeaTask(fileSystem, dustPath, title, description) {
|
|
|
135
136
|
const filePath = `${dustPath}/tasks/${filename}`;
|
|
136
137
|
const ideaFilename = titleToFilename(title);
|
|
137
138
|
const ideaPath = `.dust/ideas/${ideaFilename}`;
|
|
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:`, [
|
|
139
|
+
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. Review \`.dust/goals/\` and \`.dust/facts/\` for relevant context. The idea should have the title "${title}" and start from the following description:`, [
|
|
139
140
|
`Idea file exists at ${ideaPath}`,
|
|
140
141
|
`Idea file has an H1 title matching "${title}"`,
|
|
141
142
|
"Idea includes relevant context from codebase exploration",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const { ReportBase } = require('istanbul-lib-report')
|
|
2
|
+
|
|
3
|
+
function isFull(metrics) {
|
|
4
|
+
return (
|
|
5
|
+
metrics.statements.pct === 100 &&
|
|
6
|
+
metrics.branches.pct === 100 &&
|
|
7
|
+
metrics.functions.pct === 100 &&
|
|
8
|
+
metrics.lines.pct === 100
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function formatMetrics(metrics) {
|
|
13
|
+
const parts = []
|
|
14
|
+
if (metrics.lines.pct < 100) parts.push(`${metrics.lines.pct}% lines`)
|
|
15
|
+
if (metrics.statements.pct < 100)
|
|
16
|
+
parts.push(`${metrics.statements.pct}% statements`)
|
|
17
|
+
if (metrics.branches.pct < 100)
|
|
18
|
+
parts.push(`${metrics.branches.pct}% branches`)
|
|
19
|
+
if (metrics.functions.pct < 100)
|
|
20
|
+
parts.push(`${metrics.functions.pct}% functions`)
|
|
21
|
+
return parts.join(', ')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getUncoveredLines(fileCoverage) {
|
|
25
|
+
const lineCoverage = fileCoverage.getLineCoverage()
|
|
26
|
+
const ranges = []
|
|
27
|
+
let rangeStart = null
|
|
28
|
+
let rangeEnd = null
|
|
29
|
+
|
|
30
|
+
for (const [lineStr, hits] of Object.entries(lineCoverage)) {
|
|
31
|
+
const line = Number.parseInt(lineStr, 10)
|
|
32
|
+
if (hits === 0) {
|
|
33
|
+
if (rangeStart === null) {
|
|
34
|
+
rangeStart = line
|
|
35
|
+
rangeEnd = line
|
|
36
|
+
} else if (line === rangeEnd + 1) {
|
|
37
|
+
rangeEnd = line
|
|
38
|
+
} else {
|
|
39
|
+
ranges.push([rangeStart, rangeEnd])
|
|
40
|
+
rangeStart = line
|
|
41
|
+
rangeEnd = line
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (rangeStart !== null) {
|
|
47
|
+
ranges.push([rangeStart, rangeEnd])
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return ranges.map(([start, end]) =>
|
|
51
|
+
start === end ? `Line ${start}` : `Lines ${start}-${end}`
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class IncompleteCoverageReporter extends ReportBase {
|
|
56
|
+
execute(context) {
|
|
57
|
+
const incompleteFiles = []
|
|
58
|
+
context.getTree().visit({
|
|
59
|
+
onDetail(node) {
|
|
60
|
+
const metrics = node.getCoverageSummary()
|
|
61
|
+
if (!metrics.isEmpty() && !isFull(metrics)) {
|
|
62
|
+
incompleteFiles.push({
|
|
63
|
+
name: node.getQualifiedName(),
|
|
64
|
+
metrics,
|
|
65
|
+
fileCoverage: node.getFileCoverage(),
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
if (incompleteFiles.length === 0) return
|
|
72
|
+
|
|
73
|
+
const cw = context.writer.writeFile(null)
|
|
74
|
+
const count = incompleteFiles.length
|
|
75
|
+
const label = count === 1 ? '1 file has' : `${count} files have`
|
|
76
|
+
cw.println(`${label} < 100% coverage:`)
|
|
77
|
+
|
|
78
|
+
for (const file of incompleteFiles) {
|
|
79
|
+
cw.println('')
|
|
80
|
+
cw.println(`${file.name} (${formatMetrics(file.metrics)})`)
|
|
81
|
+
for (const line of getUncoveredLines(file.fileCoverage)) {
|
|
82
|
+
cw.println(`- ${line}`)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
cw.close()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = IncompleteCoverageReporter
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joshski/dust",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"description": "Flow state for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
"./workflow-tasks": {
|
|
11
11
|
"import": "./dist/workflow-tasks.js",
|
|
12
12
|
"types": "./dist/workflow-tasks.d.ts"
|
|
13
|
-
}
|
|
13
|
+
},
|
|
14
|
+
"./istanbul/minimal-reporter": "./lib/istanbul/minimal-reporter.cjs"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
17
|
"dist",
|
|
17
18
|
"bin",
|
|
18
|
-
"templates"
|
|
19
|
+
"templates",
|
|
20
|
+
"lib/istanbul/minimal-reporter.cjs"
|
|
19
21
|
],
|
|
20
22
|
"repository": {
|
|
21
23
|
"type": "git",
|