@joshski/dust 0.1.65 → 0.1.67
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.js +65 -19
- package/dist/audits/stock-audits.d.ts +2 -1
- package/dist/cli/types.d.ts +1 -1
- package/dist/dust.js +146 -12
- package/package.json +3 -4
package/dist/artifacts.js
CHANGED
|
@@ -302,19 +302,53 @@ async function findAllCaptureIdeaTasks(fileSystem, dustPath) {
|
|
|
302
302
|
function titleToFilename(title) {
|
|
303
303
|
return `${title.toLowerCase().replace(/\./g, "-").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
304
304
|
}
|
|
305
|
-
var
|
|
306
|
-
{ type: "refine",
|
|
307
|
-
{ type: "decompose-idea",
|
|
308
|
-
{ type: "shelve",
|
|
305
|
+
var WORKFLOW_SECTION_HEADINGS = [
|
|
306
|
+
{ type: "refine", heading: "Refines Idea" },
|
|
307
|
+
{ type: "decompose-idea", heading: "Decomposes Idea" },
|
|
308
|
+
{ type: "shelve", heading: "Shelves Idea" }
|
|
309
309
|
];
|
|
310
|
+
function extractIdeaSlugFromSection(content, sectionHeading) {
|
|
311
|
+
const lines = content.split(`
|
|
312
|
+
`);
|
|
313
|
+
let inSection = false;
|
|
314
|
+
for (const line of lines) {
|
|
315
|
+
if (line.startsWith("## ")) {
|
|
316
|
+
inSection = line.trimEnd() === `## ${sectionHeading}`;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (!inSection)
|
|
320
|
+
continue;
|
|
321
|
+
if (line.startsWith("# "))
|
|
322
|
+
break;
|
|
323
|
+
const linkMatch = line.match(MARKDOWN_LINK_PATTERN);
|
|
324
|
+
if (linkMatch) {
|
|
325
|
+
const target = linkMatch[2];
|
|
326
|
+
const slugMatch = target.match(/([^/]+)\.md$/);
|
|
327
|
+
if (slugMatch) {
|
|
328
|
+
return slugMatch[1];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
310
334
|
async function findWorkflowTaskForIdea(fileSystem, dustPath, ideaSlug) {
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
335
|
+
const ideaPath = `${dustPath}/ideas/${ideaSlug}.md`;
|
|
336
|
+
if (!fileSystem.exists(ideaPath)) {
|
|
337
|
+
throw new Error(`Idea not found: "${ideaSlug}" (expected file at ${ideaPath})`);
|
|
338
|
+
}
|
|
339
|
+
const tasksPath = `${dustPath}/tasks`;
|
|
340
|
+
if (!fileSystem.exists(tasksPath)) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const files = await fileSystem.readdir(tasksPath);
|
|
344
|
+
for (const file of files.filter((f) => f.endsWith(".md")).sort()) {
|
|
345
|
+
const content = await fileSystem.readFile(`${tasksPath}/${file}`);
|
|
346
|
+
for (const { type, heading } of WORKFLOW_SECTION_HEADINGS) {
|
|
347
|
+
const linkedSlug = extractIdeaSlugFromSection(content, heading);
|
|
348
|
+
if (linkedSlug === ideaSlug) {
|
|
349
|
+
const taskSlug = file.replace(/\.md$/, "");
|
|
350
|
+
return { type, ideaSlug, taskSlug };
|
|
351
|
+
}
|
|
318
352
|
}
|
|
319
353
|
}
|
|
320
354
|
return null;
|
|
@@ -342,18 +376,26 @@ ${sections.join(`
|
|
|
342
376
|
`)}
|
|
343
377
|
`;
|
|
344
378
|
}
|
|
345
|
-
function
|
|
379
|
+
function renderIdeaSection(ideaSection) {
|
|
380
|
+
return `## ${ideaSection.heading}
|
|
381
|
+
|
|
382
|
+
- [${ideaSection.ideaTitle}](../ideas/${ideaSection.ideaSlug}.md)
|
|
383
|
+
`;
|
|
384
|
+
}
|
|
385
|
+
function renderTask(title, openingSentence, definitionOfDone, ideaSection, options) {
|
|
346
386
|
const descriptionParagraph = options?.description !== undefined ? `
|
|
347
387
|
${options.description}
|
|
348
388
|
` : "";
|
|
349
389
|
const resolvedSection = options?.resolvedQuestions && options.resolvedQuestions.length > 0 ? `
|
|
350
390
|
${renderResolvedQuestions(options.resolvedQuestions)}
|
|
351
391
|
` : "";
|
|
392
|
+
const ideaSectionContent = `
|
|
393
|
+
${renderIdeaSection(ideaSection)}
|
|
394
|
+
`;
|
|
352
395
|
return `# ${title}
|
|
353
396
|
|
|
354
397
|
${openingSentence}
|
|
355
|
-
${descriptionParagraph}${resolvedSection}
|
|
356
|
-
## Blocked By
|
|
398
|
+
${descriptionParagraph}${resolvedSection}${ideaSectionContent}## Blocked By
|
|
357
399
|
|
|
358
400
|
(none)
|
|
359
401
|
|
|
@@ -363,13 +405,17 @@ ${definitionOfDone.map((item) => `- [ ] ${item}`).join(`
|
|
|
363
405
|
`)}
|
|
364
406
|
`;
|
|
365
407
|
}
|
|
366
|
-
async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone, taskOptions) {
|
|
408
|
+
async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone, ideaSectionHeading, taskOptions) {
|
|
367
409
|
const ideaTitle = await readIdeaTitle(fileSystem, dustPath, ideaSlug);
|
|
368
410
|
const taskTitle = `${prefix}${ideaTitle}`;
|
|
369
411
|
const filename = titleToFilename(taskTitle);
|
|
370
412
|
const filePath = `${dustPath}/tasks/${filename}`;
|
|
371
413
|
const openingSentence = openingSentenceTemplate(ideaTitle);
|
|
372
|
-
const
|
|
414
|
+
const ideaSection = { heading: ideaSectionHeading, ideaTitle, ideaSlug };
|
|
415
|
+
const content = renderTask(taskTitle, openingSentence, definitionOfDone, ideaSection, {
|
|
416
|
+
description: taskOptions?.description,
|
|
417
|
+
resolvedQuestions: taskOptions?.resolvedQuestions
|
|
418
|
+
});
|
|
373
419
|
await fileSystem.writeFile(filePath, content);
|
|
374
420
|
return { filePath };
|
|
375
421
|
}
|
|
@@ -379,20 +425,20 @@ async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description)
|
|
|
379
425
|
"Open questions are added for any ambiguous or underspecified aspects",
|
|
380
426
|
"Open questions follow the required heading format and focus on high-value decisions",
|
|
381
427
|
"Idea file is updated with findings"
|
|
382
|
-
], { description });
|
|
428
|
+
], "Refines Idea", { description });
|
|
383
429
|
}
|
|
384
430
|
async function decomposeIdea(fileSystem, dustPath, options) {
|
|
385
431
|
return createIdeaTask(fileSystem, dustPath, "Decompose Idea: ", options.ideaSlug, (ideaTitle) => `Create one or more well-defined tasks from this idea. Prefer smaller, narrowly scoped tasks that each deliver a thin but complete vertical slice of working software -- a path through the system that can be tested end-to-end -- rather than component-oriented tasks (like "add schema" or "build endpoint") that only work once all tasks are done. Split the idea into multiple tasks if it covers more than one logical change. Review \`.dust/principles/\` to link relevant principles and \`.dust/facts/\` for design decisions that should inform the task. See [${ideaTitle}](../ideas/${options.ideaSlug}.md).`, [
|
|
386
432
|
"One or more new tasks are created in .dust/tasks/",
|
|
387
433
|
"Task's Principles section links to relevant principles from .dust/principles/",
|
|
388
434
|
"The original idea is deleted or updated to reflect remaining scope"
|
|
389
|
-
], {
|
|
435
|
+
], "Decomposes Idea", {
|
|
390
436
|
description: options.description,
|
|
391
437
|
resolvedQuestions: options.openQuestionResponses
|
|
392
438
|
});
|
|
393
439
|
}
|
|
394
440
|
async function createShelveIdeaTask(fileSystem, dustPath, ideaSlug, description) {
|
|
395
|
-
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 });
|
|
441
|
+
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"], "Shelves Idea", { description });
|
|
396
442
|
}
|
|
397
443
|
async function createCaptureIdeaTask(fileSystem, dustPath, options) {
|
|
398
444
|
const { title, description, buildItNow } = options;
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Users can override any of these by placing a file with the same name
|
|
5
5
|
* in .dust/config/audits/.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
interface StockAudit {
|
|
8
8
|
name: string;
|
|
9
9
|
description: string;
|
|
10
10
|
template: string;
|
|
11
11
|
}
|
|
12
12
|
export declare function loadStockAudits(): StockAudit[];
|
|
13
|
+
export {};
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Common types for CLI commands
|
|
3
3
|
*/
|
|
4
4
|
import type { FileSystem, GlobScanner } from '../filesystem/types';
|
|
5
|
-
export type { FileSystem, GlobScanner, ReadableFileSystem,
|
|
5
|
+
export type { FileSystem, GlobScanner, ReadableFileSystem, } from '../filesystem/types';
|
|
6
6
|
export interface CommandContext {
|
|
7
7
|
cwd: string;
|
|
8
8
|
stdout: (message: string) => void;
|
package/dist/dust.js
CHANGED
|
@@ -275,7 +275,25 @@ async function loadSettings(cwd, fileSystem) {
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
// lib/version.ts
|
|
278
|
-
var DUST_VERSION = "0.1.
|
|
278
|
+
var DUST_VERSION = "0.1.67";
|
|
279
|
+
|
|
280
|
+
// lib/session.ts
|
|
281
|
+
var DUST_UNATTENDED = "DUST_UNATTENDED";
|
|
282
|
+
var DUST_SKIP_AGENT = "DUST_SKIP_AGENT";
|
|
283
|
+
var DUST_REPOSITORY_ID = "DUST_REPOSITORY_ID";
|
|
284
|
+
function isUnattended(env = process.env) {
|
|
285
|
+
return !!env[DUST_UNATTENDED];
|
|
286
|
+
}
|
|
287
|
+
function buildUnattendedEnv(options) {
|
|
288
|
+
const env = {
|
|
289
|
+
[DUST_UNATTENDED]: "1",
|
|
290
|
+
[DUST_SKIP_AGENT]: "1"
|
|
291
|
+
};
|
|
292
|
+
if (options?.repositoryId) {
|
|
293
|
+
env[DUST_REPOSITORY_ID] = options.repositoryId;
|
|
294
|
+
}
|
|
295
|
+
return env;
|
|
296
|
+
}
|
|
279
297
|
|
|
280
298
|
// lib/cli/dedent.ts
|
|
281
299
|
function dedent(strings, ...values) {
|
|
@@ -524,7 +542,7 @@ ${vars.agentInstructions}` : "";
|
|
|
524
542
|
}
|
|
525
543
|
async function agent(dependencies, env = process.env) {
|
|
526
544
|
const { context, fileSystem, settings } = dependencies;
|
|
527
|
-
if (env
|
|
545
|
+
if (env[DUST_SKIP_AGENT] === "1") {
|
|
528
546
|
context.stdout("You're running in an automated loop - proceeding to implement the assigned task.");
|
|
529
547
|
return { exitCode: 0 };
|
|
530
548
|
}
|
|
@@ -2189,13 +2207,7 @@ async function runOneIteration(dependencies, loopDependencies, onLoopEvent, onAg
|
|
|
2189
2207
|
logger = log,
|
|
2190
2208
|
repositoryId
|
|
2191
2209
|
} = options;
|
|
2192
|
-
const baseEnv = {
|
|
2193
|
-
DUST_UNATTENDED: "1",
|
|
2194
|
-
DUST_SKIP_AGENT: "1"
|
|
2195
|
-
};
|
|
2196
|
-
if (repositoryId) {
|
|
2197
|
-
baseEnv.DUST_REPOSITORY_ID = repositoryId;
|
|
2198
|
-
}
|
|
2210
|
+
const baseEnv = buildUnattendedEnv({ repositoryId });
|
|
2199
2211
|
log("syncing with remote");
|
|
2200
2212
|
onLoopEvent({ type: "loop.syncing" });
|
|
2201
2213
|
const pullResult = await gitPull(context.cwd, spawn);
|
|
@@ -2319,6 +2331,10 @@ function parseMaxIterations(commandArguments) {
|
|
|
2319
2331
|
async function loopClaude(dependencies, loopDependencies = createDefaultDependencies()) {
|
|
2320
2332
|
enableFileLogs("loop");
|
|
2321
2333
|
const { context, settings } = dependencies;
|
|
2334
|
+
if (isUnattended()) {
|
|
2335
|
+
context.stderr("dust loop cannot run inside an unattended session (DUST_UNATTENDED is set)");
|
|
2336
|
+
return { exitCode: 1 };
|
|
2337
|
+
}
|
|
2322
2338
|
const { postEvent } = loopDependencies;
|
|
2323
2339
|
const maxIterations = parseMaxIterations(dependencies.arguments);
|
|
2324
2340
|
const eventsUrl = settings.eventsUrl;
|
|
@@ -3502,9 +3518,13 @@ async function resolveToken(authDeps, context) {
|
|
|
3502
3518
|
return null;
|
|
3503
3519
|
}
|
|
3504
3520
|
}
|
|
3505
|
-
async function
|
|
3521
|
+
async function bucketWorker(dependencies, bucketDeps = createDefaultBucketDependencies()) {
|
|
3506
3522
|
enableFileLogs("bucket");
|
|
3507
3523
|
const { context, fileSystem } = dependencies;
|
|
3524
|
+
if (isUnattended()) {
|
|
3525
|
+
context.stderr("dust bucket cannot run inside an unattended session (DUST_UNATTENDED is set)");
|
|
3526
|
+
return { exitCode: 1 };
|
|
3527
|
+
}
|
|
3508
3528
|
const token = await resolveToken(bucketDeps.auth, context);
|
|
3509
3529
|
if (!token) {
|
|
3510
3530
|
return { exitCode: 1 };
|
|
@@ -3964,6 +3984,11 @@ function validateTitleFilenameMatch(filePath, content) {
|
|
|
3964
3984
|
}
|
|
3965
3985
|
|
|
3966
3986
|
// lib/lint/validators/idea-validator.ts
|
|
3987
|
+
var WORKFLOW_PREFIX_TO_SECTION = {
|
|
3988
|
+
"Refine Idea: ": "Refines Idea",
|
|
3989
|
+
"Decompose Idea: ": "Decomposes Idea",
|
|
3990
|
+
"Shelve Idea: ": "Shelves Idea"
|
|
3991
|
+
};
|
|
3967
3992
|
function validateIdeaOpenQuestions(filePath, content) {
|
|
3968
3993
|
const violations = [];
|
|
3969
3994
|
const lines = content.split(`
|
|
@@ -4077,6 +4102,114 @@ function validateIdeaTransitionTitle(filePath, content, ideasPath, fileSystem) {
|
|
|
4077
4102
|
}
|
|
4078
4103
|
return null;
|
|
4079
4104
|
}
|
|
4105
|
+
function extractSectionContent(content, sectionHeading) {
|
|
4106
|
+
const lines = content.split(`
|
|
4107
|
+
`);
|
|
4108
|
+
let inSection = false;
|
|
4109
|
+
let sectionContent = "";
|
|
4110
|
+
let startLine = 0;
|
|
4111
|
+
for (let i = 0;i < lines.length; i++) {
|
|
4112
|
+
const line = lines[i];
|
|
4113
|
+
if (line.startsWith("## ")) {
|
|
4114
|
+
if (inSection)
|
|
4115
|
+
break;
|
|
4116
|
+
if (line.trimEnd() === `## ${sectionHeading}`) {
|
|
4117
|
+
inSection = true;
|
|
4118
|
+
startLine = i + 1;
|
|
4119
|
+
}
|
|
4120
|
+
continue;
|
|
4121
|
+
}
|
|
4122
|
+
if (line.startsWith("# ") && inSection)
|
|
4123
|
+
break;
|
|
4124
|
+
if (inSection) {
|
|
4125
|
+
sectionContent += `${line}
|
|
4126
|
+
`;
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
if (!inSection)
|
|
4130
|
+
return null;
|
|
4131
|
+
return { content: sectionContent, startLine };
|
|
4132
|
+
}
|
|
4133
|
+
function validateWorkflowTaskBodySection(filePath, content, ideasPath, fileSystem) {
|
|
4134
|
+
const violations = [];
|
|
4135
|
+
const title = extractTitle(content);
|
|
4136
|
+
if (!title)
|
|
4137
|
+
return violations;
|
|
4138
|
+
let matchedPrefix = null;
|
|
4139
|
+
for (const prefix of IDEA_TRANSITION_PREFIXES) {
|
|
4140
|
+
if (title.startsWith(prefix)) {
|
|
4141
|
+
matchedPrefix = prefix;
|
|
4142
|
+
break;
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
if (!matchedPrefix)
|
|
4146
|
+
return violations;
|
|
4147
|
+
const expectedHeading = WORKFLOW_PREFIX_TO_SECTION[matchedPrefix];
|
|
4148
|
+
const section = extractSectionContent(content, expectedHeading);
|
|
4149
|
+
if (!section) {
|
|
4150
|
+
violations.push({
|
|
4151
|
+
file: filePath,
|
|
4152
|
+
message: `Workflow task with "${matchedPrefix.trim()}" prefix is missing required "## ${expectedHeading}" section. Add a section with a link to the idea file, e.g.:
|
|
4153
|
+
|
|
4154
|
+
## ${expectedHeading}
|
|
4155
|
+
|
|
4156
|
+
- [Idea Title](../ideas/idea-slug.md)`
|
|
4157
|
+
});
|
|
4158
|
+
return violations;
|
|
4159
|
+
}
|
|
4160
|
+
const linkRegex = new RegExp(MARKDOWN_LINK_PATTERN.source, "g");
|
|
4161
|
+
const links = [];
|
|
4162
|
+
const sectionLines = section.content.split(`
|
|
4163
|
+
`);
|
|
4164
|
+
for (let i = 0;i < sectionLines.length; i++) {
|
|
4165
|
+
const line = sectionLines[i];
|
|
4166
|
+
let match = linkRegex.exec(line);
|
|
4167
|
+
while (match !== null) {
|
|
4168
|
+
links.push({
|
|
4169
|
+
text: match[1],
|
|
4170
|
+
target: match[2],
|
|
4171
|
+
line: section.startLine + i + 1
|
|
4172
|
+
});
|
|
4173
|
+
match = linkRegex.exec(line);
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
if (links.length === 0) {
|
|
4177
|
+
violations.push({
|
|
4178
|
+
file: filePath,
|
|
4179
|
+
message: `"## ${expectedHeading}" section contains no link. Add a markdown link to the idea file, e.g.:
|
|
4180
|
+
|
|
4181
|
+
- [Idea Title](../ideas/idea-slug.md)`,
|
|
4182
|
+
line: section.startLine
|
|
4183
|
+
});
|
|
4184
|
+
return violations;
|
|
4185
|
+
}
|
|
4186
|
+
const ideaLinks = links.filter((l) => l.target.includes("/ideas/") || l.target.startsWith("../ideas/"));
|
|
4187
|
+
if (ideaLinks.length === 0) {
|
|
4188
|
+
violations.push({
|
|
4189
|
+
file: filePath,
|
|
4190
|
+
message: `"## ${expectedHeading}" section contains no link to an idea file. Links must point to a file in ../ideas/, e.g.:
|
|
4191
|
+
|
|
4192
|
+
- [Idea Title](../ideas/idea-slug.md)`,
|
|
4193
|
+
line: section.startLine
|
|
4194
|
+
});
|
|
4195
|
+
return violations;
|
|
4196
|
+
}
|
|
4197
|
+
for (const link of ideaLinks) {
|
|
4198
|
+
const slugMatch = link.target.match(/([^/]+)\.md$/);
|
|
4199
|
+
if (!slugMatch)
|
|
4200
|
+
continue;
|
|
4201
|
+
const ideaSlug = slugMatch[1];
|
|
4202
|
+
const ideaFilePath = `${ideasPath}/${ideaSlug}.md`;
|
|
4203
|
+
if (!fileSystem.exists(ideaFilePath)) {
|
|
4204
|
+
violations.push({
|
|
4205
|
+
file: filePath,
|
|
4206
|
+
message: `Link to idea "${link.text}" points to non-existent file: ${ideaSlug}.md. Either create the idea file at ideas/${ideaSlug}.md or update the link to point to an existing idea.`,
|
|
4207
|
+
line: link.line
|
|
4208
|
+
});
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
return violations;
|
|
4212
|
+
}
|
|
4080
4213
|
|
|
4081
4214
|
// lib/lint/validators/link-validator.ts
|
|
4082
4215
|
import { dirname as dirname3, resolve } from "node:path";
|
|
@@ -4480,6 +4613,7 @@ async function lintMarkdown(dependencies) {
|
|
|
4480
4613
|
if (ideaTransitionViolation) {
|
|
4481
4614
|
violations.push(ideaTransitionViolation);
|
|
4482
4615
|
}
|
|
4616
|
+
violations.push(...validateWorkflowTaskBodySection(filePath, content, ideasPath, fileSystem));
|
|
4483
4617
|
}
|
|
4484
4618
|
}
|
|
4485
4619
|
const principlesPath = `${dustPath}/principles`;
|
|
@@ -5428,7 +5562,7 @@ async function prePush(dependencies, gitRunner = defaultGitRunner, env = process
|
|
|
5428
5562
|
if (agent2.type === "unknown") {
|
|
5429
5563
|
return { exitCode: 0 };
|
|
5430
5564
|
}
|
|
5431
|
-
if (env
|
|
5565
|
+
if (isUnattended(env)) {
|
|
5432
5566
|
const uncommittedFiles = await getUncommittedFiles(context.cwd, gitRunner);
|
|
5433
5567
|
if (uncommittedFiles.length > 0) {
|
|
5434
5568
|
context.stderr("");
|
|
@@ -5498,7 +5632,7 @@ var commandRegistry = {
|
|
|
5498
5632
|
check,
|
|
5499
5633
|
agent,
|
|
5500
5634
|
audit,
|
|
5501
|
-
bucket,
|
|
5635
|
+
"bucket worker": bucketWorker,
|
|
5502
5636
|
"bucket asset upload": bucketAssetUpload,
|
|
5503
5637
|
focus,
|
|
5504
5638
|
"new task": newTask,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joshski/dust",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
4
4
|
"description": "Flow state for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -63,9 +63,8 @@
|
|
|
63
63
|
"@biomejs/biome": "^2.3.13",
|
|
64
64
|
"@types/bun": "^1.3.6",
|
|
65
65
|
"@vitest/coverage-v8": "^4.0.18",
|
|
66
|
+
"istanbul-lib-coverage": "^3.2.2",
|
|
67
|
+
"istanbul-lib-report": "^3.0.1",
|
|
66
68
|
"vitest": "^4.0.18"
|
|
67
|
-
},
|
|
68
|
-
"dependencies": {
|
|
69
|
-
"@joshski/dust": "^0.1.49"
|
|
70
69
|
}
|
|
71
70
|
}
|