@joshski/dust 0.1.62 → 0.1.64
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/artifacts/facts.d.ts +1 -1
- package/dist/artifacts/ideas.d.ts +1 -1
- package/dist/artifacts/index.d.ts +1 -1
- package/dist/artifacts/principles.d.ts +1 -1
- package/dist/artifacts/tasks.d.ts +1 -1
- package/dist/artifacts/workflow-tasks.d.ts +1 -1
- package/dist/audits/index.d.ts +36 -0
- package/dist/audits/stock-audits.d.ts +12 -0
- package/dist/audits.js +459 -0
- package/dist/cli/dedent.d.ts +8 -0
- package/dist/cli/types.d.ts +2 -21
- package/dist/dust.js +370 -142
- package/dist/filesystem/types.d.ts +24 -0
- package/package.json +9 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FileSystem, ReadableFileSystem } from '../
|
|
1
|
+
import type { FileSystem, ReadableFileSystem } from '../filesystem/types';
|
|
2
2
|
import { type Fact } from './facts';
|
|
3
3
|
import { type Idea, type IdeaOpenQuestion, type IdeaOption, parseOpenQuestions } from './ideas';
|
|
4
4
|
import { type Principle } from './principles';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FileSystem, ReadableFileSystem } from '../
|
|
1
|
+
import type { FileSystem, ReadableFileSystem } from '../filesystem/types';
|
|
2
2
|
export declare const IDEA_TRANSITION_PREFIXES: string[];
|
|
3
3
|
export declare const CAPTURE_IDEA_PREFIX = "Add Idea: ";
|
|
4
4
|
export declare const BUILD_IDEA_PREFIX = "Build Idea: ";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audits repository - programmatic access to audit templates.
|
|
3
|
+
*
|
|
4
|
+
* Audits are canned tasks that help maintain project health.
|
|
5
|
+
* Sources:
|
|
6
|
+
* 1. User-configured audits in .dust/config/audits/*.md (takes precedence)
|
|
7
|
+
* 2. Stock audits from lib/audits/stock-audits.ts
|
|
8
|
+
*/
|
|
9
|
+
import type { FileSystem } from '../filesystem/types';
|
|
10
|
+
export { loadStockAudits } from './stock-audits';
|
|
11
|
+
export interface Audit {
|
|
12
|
+
name: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
template: string;
|
|
16
|
+
source: 'stock' | string;
|
|
17
|
+
}
|
|
18
|
+
export interface CreateAuditTaskResult {
|
|
19
|
+
filePath: string;
|
|
20
|
+
relativePath: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AuditsRepository {
|
|
23
|
+
listAudits(): Promise<Audit[]>;
|
|
24
|
+
parseAudit(options: {
|
|
25
|
+
name: string;
|
|
26
|
+
}): Promise<Audit>;
|
|
27
|
+
createAuditTask(options: {
|
|
28
|
+
name: string;
|
|
29
|
+
}): Promise<CreateAuditTaskResult>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Transforms audit template content for the task file.
|
|
33
|
+
* Changes the title from "# Original Title" to "# Audit: Original Title"
|
|
34
|
+
*/
|
|
35
|
+
export declare function transformAuditContent(content: string): string;
|
|
36
|
+
export declare function buildAuditsRepository(fileSystem: FileSystem, dustPath: string): AuditsRepository;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stock audit templates as type-safe functions.
|
|
3
|
+
*
|
|
4
|
+
* Users can override any of these by placing a file with the same name
|
|
5
|
+
* in .dust/config/audits/.
|
|
6
|
+
*/
|
|
7
|
+
export interface StockAudit {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
template: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function loadStockAudits(): StockAudit[];
|
package/dist/audits.js
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
// lib/audits/index.ts
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
|
|
4
|
+
// lib/markdown/markdown-utilities.ts
|
|
5
|
+
function extractTitle(content) {
|
|
6
|
+
const match = content.match(/^#\s+(.+)$/m);
|
|
7
|
+
return match ? match[1].trim() : null;
|
|
8
|
+
}
|
|
9
|
+
function extractOpeningSentence(content) {
|
|
10
|
+
const lines = content.split(`
|
|
11
|
+
`);
|
|
12
|
+
let h1Index = -1;
|
|
13
|
+
for (let i = 0;i < lines.length; i++) {
|
|
14
|
+
if (lines[i].match(/^#\s+.+$/)) {
|
|
15
|
+
h1Index = i;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (h1Index === -1) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
let paragraphStart = -1;
|
|
23
|
+
for (let i = h1Index + 1;i < lines.length; i++) {
|
|
24
|
+
const line = lines[i].trim();
|
|
25
|
+
if (line !== "") {
|
|
26
|
+
paragraphStart = i;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (paragraphStart === -1) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const firstLine = lines[paragraphStart];
|
|
34
|
+
const trimmedFirstLine = firstLine.trim();
|
|
35
|
+
if (trimmedFirstLine.startsWith("#") || trimmedFirstLine.startsWith("-") || trimmedFirstLine.startsWith("*") || trimmedFirstLine.startsWith("+") || trimmedFirstLine.match(/^\d+\./) || trimmedFirstLine.startsWith("```") || trimmedFirstLine.startsWith(">")) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
let paragraph = "";
|
|
39
|
+
for (let i = paragraphStart;i < lines.length; i++) {
|
|
40
|
+
const line = lines[i].trim();
|
|
41
|
+
if (line === "")
|
|
42
|
+
break;
|
|
43
|
+
if (line.startsWith("#") || line.startsWith("```") || line.startsWith(">")) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
paragraph += (paragraph ? " " : "") + line;
|
|
47
|
+
}
|
|
48
|
+
const sentenceMatch = paragraph.match(/^(.+?[.?!])(?:\s|$)/);
|
|
49
|
+
if (!sentenceMatch) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return sentenceMatch[1];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// lib/cli/dedent.ts
|
|
56
|
+
function dedent(strings, ...values) {
|
|
57
|
+
const result = strings.reduce((acc, part, index) => acc + part + (values[index] ?? ""), "");
|
|
58
|
+
const lines = result.split(`
|
|
59
|
+
`);
|
|
60
|
+
const indent = lines.filter((line) => line.trim()).reduce((min, line) => Math.min(min, line.match(/^\s*/)[0].length), Number.POSITIVE_INFINITY);
|
|
61
|
+
return lines.map((line) => line.slice(indent)).join(`
|
|
62
|
+
`).trim();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// lib/audits/stock-audits.ts
|
|
66
|
+
function agentDeveloperExperience() {
|
|
67
|
+
return dedent`
|
|
68
|
+
# Agent Developer Experience
|
|
69
|
+
|
|
70
|
+
Review the codebase to ensure agents have everything they need to operate effectively. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
71
|
+
|
|
72
|
+
## Scope
|
|
73
|
+
|
|
74
|
+
Focus on these areas:
|
|
75
|
+
|
|
76
|
+
1. **Context window efficiency** - Are files small and well-organized?
|
|
77
|
+
2. **Test coverage** - Can agents verify correctness through tests?
|
|
78
|
+
3. **Feedback loop speed** - How fast are checks and tests?
|
|
79
|
+
4. **Debugging tools** - Can agents diagnose issues without trial and error?
|
|
80
|
+
5. **Structured logging** - Is system behavior observable through logs?
|
|
81
|
+
|
|
82
|
+
## Principles
|
|
83
|
+
|
|
84
|
+
(none)
|
|
85
|
+
|
|
86
|
+
## Blocked By
|
|
87
|
+
|
|
88
|
+
(none)
|
|
89
|
+
|
|
90
|
+
## Definition of Done
|
|
91
|
+
|
|
92
|
+
- [ ] Reviewed file sizes and organization for context window fit
|
|
93
|
+
- [ ] Verified test coverage is sufficient for agent verification
|
|
94
|
+
- [ ] Measured feedback loop speed (time from change to check result)
|
|
95
|
+
- [ ] Confirmed debugging tools and structured logging are in place
|
|
96
|
+
- [ ] Proposed ideas for any improvements identified
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
function deadCode() {
|
|
100
|
+
return dedent`
|
|
101
|
+
# Dead Code
|
|
102
|
+
|
|
103
|
+
Find and remove unused code to improve maintainability and reduce bundle size. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
104
|
+
|
|
105
|
+
## Scope
|
|
106
|
+
|
|
107
|
+
Focus on these areas:
|
|
108
|
+
|
|
109
|
+
1. **Unused exports** - Functions, classes, constants that are never imported
|
|
110
|
+
2. **Unreachable code** - Code after return statements, impossible conditions
|
|
111
|
+
3. **Orphaned files** - Files that are not imported anywhere
|
|
112
|
+
4. **Unused dependencies** - Packages in package.json not used in code
|
|
113
|
+
5. **Commented-out code** - Old code left in comments
|
|
114
|
+
|
|
115
|
+
## Principles
|
|
116
|
+
|
|
117
|
+
(none)
|
|
118
|
+
|
|
119
|
+
## Blocked By
|
|
120
|
+
|
|
121
|
+
(none)
|
|
122
|
+
|
|
123
|
+
## Definition of Done
|
|
124
|
+
|
|
125
|
+
- [ ] Ran static analysis tools to find unused exports
|
|
126
|
+
- [ ] Identified files with no incoming imports
|
|
127
|
+
- [ ] Listed unused dependencies
|
|
128
|
+
- [ ] Reviewed commented-out code blocks
|
|
129
|
+
- [ ] Created list of code safe to remove
|
|
130
|
+
- [ ] Verified removal won't break dynamic imports or reflection
|
|
131
|
+
- [ ] Proposed ideas for any dead code worth removing
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
function factsVerification() {
|
|
135
|
+
return dedent`
|
|
136
|
+
# Facts Verification
|
|
137
|
+
|
|
138
|
+
Review \`.dust/facts/\` to ensure documented facts match current reality. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
139
|
+
|
|
140
|
+
## Scope
|
|
141
|
+
|
|
142
|
+
Focus on these areas:
|
|
143
|
+
|
|
144
|
+
1. **Accuracy** - Do documented facts reflect the current codebase?
|
|
145
|
+
2. **Completeness** - Are important implementation details documented?
|
|
146
|
+
3. **Staleness** - Have facts become outdated due to recent changes?
|
|
147
|
+
4. **Relevance** - Are all facts still useful for understanding the project?
|
|
148
|
+
|
|
149
|
+
## Principles
|
|
150
|
+
|
|
151
|
+
(none)
|
|
152
|
+
|
|
153
|
+
## Blocked By
|
|
154
|
+
|
|
155
|
+
(none)
|
|
156
|
+
|
|
157
|
+
## Definition of Done
|
|
158
|
+
|
|
159
|
+
- [ ] Read each fact file in \`.dust/facts/\`
|
|
160
|
+
- [ ] Verified each fact against current codebase
|
|
161
|
+
- [ ] Identified outdated or inaccurate facts
|
|
162
|
+
- [ ] Listed missing facts that would help agents
|
|
163
|
+
- [ ] Updated or removed stale facts
|
|
164
|
+
- [ ] Proposed ideas for any facts improvements needed
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
function ideasFromCommits() {
|
|
168
|
+
return dedent`
|
|
169
|
+
# Ideas from Commits
|
|
170
|
+
|
|
171
|
+
Review recent commit history to identify follow-up improvement ideas. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues or opportunities you identify, avoiding duplication.
|
|
172
|
+
|
|
173
|
+
## Scope
|
|
174
|
+
|
|
175
|
+
Focus on these areas:
|
|
176
|
+
|
|
177
|
+
1. **Technical debt** - Did recent work introduce shortcuts?
|
|
178
|
+
2. **Incomplete work** - Are there TODO comments or partial implementations?
|
|
179
|
+
3. **Pattern opportunities** - Can recent changes be generalized?
|
|
180
|
+
4. **Test gaps** - Do recent changes have adequate test coverage?
|
|
181
|
+
|
|
182
|
+
## Principles
|
|
183
|
+
|
|
184
|
+
(none)
|
|
185
|
+
|
|
186
|
+
## Blocked By
|
|
187
|
+
|
|
188
|
+
(none)
|
|
189
|
+
|
|
190
|
+
## Definition of Done
|
|
191
|
+
|
|
192
|
+
- [ ] Reviewed commits from the last 20 commits
|
|
193
|
+
- [ ] Identified patterns or shortcuts worth addressing
|
|
194
|
+
- [ ] Listed TODO comments added in recent commits
|
|
195
|
+
- [ ] Noted areas where changes could be generalized
|
|
196
|
+
- [ ] Proposed follow-up ideas for any issues identified
|
|
197
|
+
`;
|
|
198
|
+
}
|
|
199
|
+
function ideasFromPrinciples() {
|
|
200
|
+
return dedent`
|
|
201
|
+
# Ideas from Principles
|
|
202
|
+
|
|
203
|
+
Review \`.dust/principles/\` to generate new improvement ideas. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues or opportunities you identify, avoiding duplication.
|
|
204
|
+
|
|
205
|
+
## Scope
|
|
206
|
+
|
|
207
|
+
Focus on these areas:
|
|
208
|
+
|
|
209
|
+
1. **Unmet principles** - Which principles lack supporting work?
|
|
210
|
+
2. **Gap analysis** - Where does the codebase fall short of principles?
|
|
211
|
+
3. **New opportunities** - What work would better achieve each principle?
|
|
212
|
+
4. **Principle alignment** - Are current tasks aligned with stated principles?
|
|
213
|
+
|
|
214
|
+
## Principles
|
|
215
|
+
|
|
216
|
+
(none)
|
|
217
|
+
|
|
218
|
+
## Blocked By
|
|
219
|
+
|
|
220
|
+
(none)
|
|
221
|
+
|
|
222
|
+
## Definition of Done
|
|
223
|
+
|
|
224
|
+
- [ ] Read each principle file in \`.dust/principles/\`
|
|
225
|
+
- [ ] Analyzed codebase for alignment with each principle
|
|
226
|
+
- [ ] Listed gaps between current state and principle intent
|
|
227
|
+
- [ ] Proposed new ideas for unmet or underserved principles
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
function performanceReview() {
|
|
231
|
+
return dedent`
|
|
232
|
+
# Performance Review
|
|
233
|
+
|
|
234
|
+
Review the application for performance issues and optimization opportunities. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
235
|
+
|
|
236
|
+
## Scope
|
|
237
|
+
|
|
238
|
+
Focus on these areas:
|
|
239
|
+
|
|
240
|
+
1. **Startup time** - How fast does the application start?
|
|
241
|
+
2. **Command latency** - How responsive are CLI commands?
|
|
242
|
+
3. **Memory usage** - Is memory being used efficiently?
|
|
243
|
+
4. **Build performance** - How fast is the build process?
|
|
244
|
+
5. **Test speed** - Are tests running efficiently?
|
|
245
|
+
|
|
246
|
+
## Principles
|
|
247
|
+
|
|
248
|
+
(none)
|
|
249
|
+
|
|
250
|
+
## Blocked By
|
|
251
|
+
|
|
252
|
+
(none)
|
|
253
|
+
|
|
254
|
+
## Definition of Done
|
|
255
|
+
|
|
256
|
+
- [ ] Measured startup time for common commands
|
|
257
|
+
- [ ] Profiled memory usage during typical operations
|
|
258
|
+
- [ ] Identified slow commands or operations
|
|
259
|
+
- [ ] Listed optimization opportunities by impact
|
|
260
|
+
- [ ] Proposed ideas for any performance improvements identified
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
function securityReview() {
|
|
264
|
+
return dedent`
|
|
265
|
+
# Security Review
|
|
266
|
+
|
|
267
|
+
Review the codebase for common security vulnerabilities and misconfigurations. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
268
|
+
|
|
269
|
+
## Scope
|
|
270
|
+
|
|
271
|
+
Focus on these areas:
|
|
272
|
+
|
|
273
|
+
1. **Hardcoded secrets** - API keys, passwords, tokens in source code
|
|
274
|
+
2. **Injection vulnerabilities** - SQL injection, command injection, XSS
|
|
275
|
+
3. **Authentication issues** - Weak password handling, missing auth checks
|
|
276
|
+
4. **Sensitive data exposure** - Logging sensitive data, insecure storage
|
|
277
|
+
5. **Dependency vulnerabilities** - Known CVEs in dependencies
|
|
278
|
+
|
|
279
|
+
## Principles
|
|
280
|
+
|
|
281
|
+
(none)
|
|
282
|
+
|
|
283
|
+
## Blocked By
|
|
284
|
+
|
|
285
|
+
(none)
|
|
286
|
+
|
|
287
|
+
## Definition of Done
|
|
288
|
+
|
|
289
|
+
- [ ] Searched for hardcoded secrets (API keys, passwords, tokens)
|
|
290
|
+
- [ ] Reviewed input validation and sanitization
|
|
291
|
+
- [ ] Checked authentication and authorization logic
|
|
292
|
+
- [ ] Verified sensitive data is not logged or exposed
|
|
293
|
+
- [ ] Ran dependency audit for known vulnerabilities
|
|
294
|
+
- [ ] Documented any findings with severity ratings
|
|
295
|
+
- [ ] Proposed ideas for any security issues found
|
|
296
|
+
`;
|
|
297
|
+
}
|
|
298
|
+
function staleIdeas() {
|
|
299
|
+
return dedent`
|
|
300
|
+
# Stale Ideas
|
|
301
|
+
|
|
302
|
+
Review \`.dust/ideas/\` to identify ideas that have become stale or irrelevant. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
303
|
+
|
|
304
|
+
## Scope
|
|
305
|
+
|
|
306
|
+
Focus on these areas:
|
|
307
|
+
|
|
308
|
+
1. **Age** - Ideas unchanged for many commits may need attention
|
|
309
|
+
2. **Relevance** - Has the project evolved past the idea?
|
|
310
|
+
3. **Actionability** - Can the idea be converted to a task?
|
|
311
|
+
4. **Duplication** - Are there overlapping or redundant ideas?
|
|
312
|
+
|
|
313
|
+
## Principles
|
|
314
|
+
|
|
315
|
+
(none)
|
|
316
|
+
|
|
317
|
+
## Blocked By
|
|
318
|
+
|
|
319
|
+
(none)
|
|
320
|
+
|
|
321
|
+
## Definition of Done
|
|
322
|
+
|
|
323
|
+
- [ ] Listed all ideas with their last modification date
|
|
324
|
+
- [ ] Identified ideas unchanged for 50+ commits
|
|
325
|
+
- [ ] Reviewed each stale idea for current relevance
|
|
326
|
+
- [ ] Promoted actionable ideas to tasks
|
|
327
|
+
- [ ] Deleted ideas that are no longer relevant
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
function testCoverage() {
|
|
331
|
+
return dedent`
|
|
332
|
+
# Test Coverage
|
|
333
|
+
|
|
334
|
+
Identify untested code paths and areas that need additional test coverage. Review existing ideas in \`./.ideas/\` and the recent history of \`./.dust/ideas\` to understand what has been proposed or considered historically, then create new idea files in \`./.ideas/\` for any issues you identify, avoiding duplication.
|
|
335
|
+
|
|
336
|
+
## Scope
|
|
337
|
+
|
|
338
|
+
Focus on these areas:
|
|
339
|
+
|
|
340
|
+
1. **Core business logic** - Functions that handle critical operations
|
|
341
|
+
2. **Edge cases** - Boundary conditions, error handling paths
|
|
342
|
+
3. **Integration points** - API endpoints, database operations
|
|
343
|
+
4. **User-facing features** - UI components, form validation
|
|
344
|
+
5. **Recent changes** - Code modified in the last few commits
|
|
345
|
+
|
|
346
|
+
## Principles
|
|
347
|
+
|
|
348
|
+
(none)
|
|
349
|
+
|
|
350
|
+
## Blocked By
|
|
351
|
+
|
|
352
|
+
(none)
|
|
353
|
+
|
|
354
|
+
## Definition of Done
|
|
355
|
+
|
|
356
|
+
- [ ] Identified modules with low or no test coverage
|
|
357
|
+
- [ ] Listed critical paths that lack tests
|
|
358
|
+
- [ ] Prioritized areas by risk and importance
|
|
359
|
+
- [ ] Proposed ideas for any test coverage gaps identified
|
|
360
|
+
`;
|
|
361
|
+
}
|
|
362
|
+
var stockAuditFunctions = {
|
|
363
|
+
"agent-developer-experience": agentDeveloperExperience,
|
|
364
|
+
"dead-code": deadCode,
|
|
365
|
+
"facts-verification": factsVerification,
|
|
366
|
+
"ideas-from-commits": ideasFromCommits,
|
|
367
|
+
"ideas-from-principles": ideasFromPrinciples,
|
|
368
|
+
"performance-review": performanceReview,
|
|
369
|
+
"security-review": securityReview,
|
|
370
|
+
"stale-ideas": staleIdeas,
|
|
371
|
+
"test-coverage": testCoverage
|
|
372
|
+
};
|
|
373
|
+
function loadStockAudits() {
|
|
374
|
+
return Object.entries(stockAuditFunctions).sort(([a], [b]) => a.localeCompare(b)).map(([name, render]) => {
|
|
375
|
+
const template = render();
|
|
376
|
+
const description = extractOpeningSentence(template);
|
|
377
|
+
return { name, description, template };
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// lib/audits/index.ts
|
|
382
|
+
function transformAuditContent(content) {
|
|
383
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
384
|
+
if (!titleMatch) {
|
|
385
|
+
return content;
|
|
386
|
+
}
|
|
387
|
+
const originalTitle = titleMatch[1];
|
|
388
|
+
return content.replace(/^#\s+.+$/m, `# Audit: ${originalTitle}`);
|
|
389
|
+
}
|
|
390
|
+
function buildAuditsRepository(fileSystem, dustPath) {
|
|
391
|
+
const userAuditsPath = `${dustPath}/config/audits`;
|
|
392
|
+
const tasksPath = `${dustPath}/tasks`;
|
|
393
|
+
async function loadAllAudits() {
|
|
394
|
+
const audits = new Map;
|
|
395
|
+
for (const stockAudit of loadStockAudits()) {
|
|
396
|
+
audits.set(stockAudit.name, {
|
|
397
|
+
name: stockAudit.name,
|
|
398
|
+
title: extractTitle(stockAudit.template),
|
|
399
|
+
description: stockAudit.description,
|
|
400
|
+
template: stockAudit.template,
|
|
401
|
+
source: "stock"
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
if (fileSystem.exists(userAuditsPath)) {
|
|
405
|
+
const files = await fileSystem.readdir(userAuditsPath);
|
|
406
|
+
const mdFiles = files.filter((f) => f.endsWith(".md")).sort();
|
|
407
|
+
for (const file of mdFiles) {
|
|
408
|
+
const name = basename(file, ".md");
|
|
409
|
+
const filePath = `${userAuditsPath}/${file}`;
|
|
410
|
+
const content = await fileSystem.readFile(filePath);
|
|
411
|
+
const title = extractTitle(content) || name;
|
|
412
|
+
const description = extractOpeningSentence(content) || "";
|
|
413
|
+
const relativePath = `.dust/config/audits/${file}`;
|
|
414
|
+
audits.set(name, {
|
|
415
|
+
name,
|
|
416
|
+
title,
|
|
417
|
+
description,
|
|
418
|
+
template: content,
|
|
419
|
+
source: relativePath
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return audits;
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
async listAudits() {
|
|
427
|
+
const auditsMap = await loadAllAudits();
|
|
428
|
+
return Array.from(auditsMap.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
429
|
+
},
|
|
430
|
+
async parseAudit(options) {
|
|
431
|
+
const auditsMap = await loadAllAudits();
|
|
432
|
+
const audit = auditsMap.get(options.name);
|
|
433
|
+
if (!audit) {
|
|
434
|
+
throw new Error(`Audit not found: "${options.name}"`);
|
|
435
|
+
}
|
|
436
|
+
return audit;
|
|
437
|
+
},
|
|
438
|
+
async createAuditTask(options) {
|
|
439
|
+
const audit = await this.parseAudit(options);
|
|
440
|
+
const taskFilePath = `${tasksPath}/audit-${options.name}.md`;
|
|
441
|
+
const relativeTaskPath = `.dust/tasks/audit-${options.name}.md`;
|
|
442
|
+
if (fileSystem.exists(taskFilePath)) {
|
|
443
|
+
throw new Error(`Audit task already exists at ${relativeTaskPath}`);
|
|
444
|
+
}
|
|
445
|
+
const transformedContent = transformAuditContent(audit.template);
|
|
446
|
+
await fileSystem.mkdir(tasksPath, { recursive: true });
|
|
447
|
+
await fileSystem.writeFile(taskFilePath, transformedContent);
|
|
448
|
+
return {
|
|
449
|
+
filePath: taskFilePath,
|
|
450
|
+
relativePath: relativeTaskPath
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
export {
|
|
456
|
+
transformAuditContent,
|
|
457
|
+
loadStockAudits,
|
|
458
|
+
buildAuditsRepository
|
|
459
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dedent tagged template literal helper
|
|
3
|
+
*
|
|
4
|
+
* Strips common leading whitespace from multi-line template literals,
|
|
5
|
+
* making it possible to write properly indented code while producing
|
|
6
|
+
* clean output.
|
|
7
|
+
*/
|
|
8
|
+
export declare function dedent(strings: TemplateStringsArray, ...values: unknown[]): string;
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Common types for CLI commands
|
|
3
3
|
*/
|
|
4
|
+
import type { FileSystem, GlobScanner } from '../filesystem/types';
|
|
5
|
+
export type { FileSystem, GlobScanner, ReadableFileSystem, WriteOptions, } from '../filesystem/types';
|
|
4
6
|
export interface CommandContext {
|
|
5
7
|
cwd: string;
|
|
6
8
|
stdout: (message: string) => void;
|
|
@@ -10,27 +12,6 @@ export interface CommandContext {
|
|
|
10
12
|
export interface CommandResult {
|
|
11
13
|
exitCode: number;
|
|
12
14
|
}
|
|
13
|
-
export interface WriteOptions {
|
|
14
|
-
flag?: 'w' | 'wx';
|
|
15
|
-
}
|
|
16
|
-
export interface ReadableFileSystem {
|
|
17
|
-
exists: (path: string) => boolean;
|
|
18
|
-
readFile: (path: string) => Promise<string>;
|
|
19
|
-
readdir: (path: string) => Promise<string[]>;
|
|
20
|
-
isDirectory: (path: string) => boolean;
|
|
21
|
-
}
|
|
22
|
-
export interface FileSystem extends ReadableFileSystem {
|
|
23
|
-
writeFile: (path: string, content: string, options?: WriteOptions) => Promise<void>;
|
|
24
|
-
mkdir: (path: string, options?: {
|
|
25
|
-
recursive?: boolean;
|
|
26
|
-
}) => Promise<void>;
|
|
27
|
-
chmod: (path: string, mode: number) => Promise<void>;
|
|
28
|
-
getFileCreationTime: (path: string) => number;
|
|
29
|
-
rename: (oldPath: string, newPath: string) => Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
export interface GlobScanner {
|
|
32
|
-
scan: (dir: string) => AsyncIterable<string>;
|
|
33
|
-
}
|
|
34
15
|
export interface CheckConfig {
|
|
35
16
|
name: string;
|
|
36
17
|
command: string;
|