@joshski/dust 0.1.70 → 0.1.72
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/index.d.ts +2 -2
- package/dist/artifacts/workflow-tasks.d.ts +4 -4
- package/dist/artifacts.js +21 -21
- package/dist/dust.js +3 -3
- package/dist/filesystem/emulator.d.ts +41 -0
- package/dist/filesystem-emulator.js +137 -0
- package/package.json +5 -1
|
@@ -33,10 +33,10 @@ export interface ArtifactsRepository {
|
|
|
33
33
|
ideaSlug: string;
|
|
34
34
|
description?: string;
|
|
35
35
|
}): Promise<CreateIdeaTransitionTaskResult>;
|
|
36
|
-
|
|
36
|
+
createIdeaTask(options: {
|
|
37
37
|
title: string;
|
|
38
38
|
description: string;
|
|
39
|
-
|
|
39
|
+
expedite?: boolean;
|
|
40
40
|
}): Promise<CreateIdeaTransitionTaskResult>;
|
|
41
41
|
findWorkflowTaskForIdea(options: {
|
|
42
42
|
ideaSlug: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
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
|
-
export declare const
|
|
4
|
+
export declare const EXPEDITE_IDEA_PREFIX = "Expedite Idea: ";
|
|
5
5
|
export interface IdeaInProgress {
|
|
6
6
|
taskSlug: string;
|
|
7
7
|
ideaTitle: string;
|
|
@@ -9,7 +9,7 @@ export interface IdeaInProgress {
|
|
|
9
9
|
export interface ParsedCaptureIdeaTask {
|
|
10
10
|
ideaTitle: string;
|
|
11
11
|
ideaDescription: string;
|
|
12
|
-
|
|
12
|
+
expedite: boolean;
|
|
13
13
|
}
|
|
14
14
|
export declare function findAllCaptureIdeaTasks(fileSystem: ReadableFileSystem, dustPath: string): Promise<IdeaInProgress[]>;
|
|
15
15
|
/**
|
|
@@ -49,9 +49,9 @@ export interface DecomposeIdeaOptions {
|
|
|
49
49
|
export declare function createRefineIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
|
|
50
50
|
export declare function decomposeIdea(fileSystem: FileSystem, dustPath: string, options: DecomposeIdeaOptions): Promise<CreateIdeaTransitionTaskResult>;
|
|
51
51
|
export declare function createShelveIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string): Promise<CreateIdeaTransitionTaskResult>;
|
|
52
|
-
export declare function
|
|
52
|
+
export declare function createIdeaTask(fileSystem: FileSystem, dustPath: string, options: {
|
|
53
53
|
title: string;
|
|
54
54
|
description: string;
|
|
55
|
-
|
|
55
|
+
expedite?: boolean;
|
|
56
56
|
}): Promise<CreateIdeaTransitionTaskResult>;
|
|
57
57
|
export declare function parseCaptureIdeaTask(fileSystem: ReadableFileSystem, dustPath: string, taskSlug: string): Promise<ParsedCaptureIdeaTask | null>;
|
package/dist/artifacts.js
CHANGED
|
@@ -272,7 +272,7 @@ async function parseTask(fileSystem, dustPath, slug) {
|
|
|
272
272
|
|
|
273
273
|
// lib/artifacts/workflow-tasks.ts
|
|
274
274
|
var CAPTURE_IDEA_PREFIX = "Add Idea: ";
|
|
275
|
-
var
|
|
275
|
+
var EXPEDITE_IDEA_PREFIX = "Expedite Idea: ";
|
|
276
276
|
async function findAllCaptureIdeaTasks(fileSystem, dustPath) {
|
|
277
277
|
const tasksPath = `${dustPath}/tasks`;
|
|
278
278
|
if (!fileSystem.exists(tasksPath))
|
|
@@ -290,10 +290,10 @@ async function findAllCaptureIdeaTasks(fileSystem, dustPath) {
|
|
|
290
290
|
taskSlug: file.replace(/\.md$/, ""),
|
|
291
291
|
ideaTitle: title.slice(CAPTURE_IDEA_PREFIX.length)
|
|
292
292
|
});
|
|
293
|
-
} else if (title.startsWith(
|
|
293
|
+
} else if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
|
|
294
294
|
results.push({
|
|
295
295
|
taskSlug: file.replace(/\.md$/, ""),
|
|
296
|
-
ideaTitle: title.slice(
|
|
296
|
+
ideaTitle: title.slice(EXPEDITE_IDEA_PREFIX.length)
|
|
297
297
|
});
|
|
298
298
|
}
|
|
299
299
|
}
|
|
@@ -351,10 +351,10 @@ async function findAllWorkflowTasks(fileSystem, dustPath) {
|
|
|
351
351
|
taskSlug,
|
|
352
352
|
ideaTitle: title.slice(CAPTURE_IDEA_PREFIX.length)
|
|
353
353
|
});
|
|
354
|
-
} else if (title.startsWith(
|
|
354
|
+
} else if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
|
|
355
355
|
captureIdeaTasks.push({
|
|
356
356
|
taskSlug,
|
|
357
|
-
ideaTitle: title.slice(
|
|
357
|
+
ideaTitle: title.slice(EXPEDITE_IDEA_PREFIX.length)
|
|
358
358
|
});
|
|
359
359
|
}
|
|
360
360
|
for (const { type, heading } of WORKFLOW_SECTION_HEADINGS) {
|
|
@@ -444,7 +444,7 @@ ${definitionOfDone.map((item) => `- [ ] ${item}`).join(`
|
|
|
444
444
|
`)}
|
|
445
445
|
`;
|
|
446
446
|
}
|
|
447
|
-
async function
|
|
447
|
+
async function createIdeaTransitionTask(fileSystem, dustPath, prefix, ideaSlug, openingSentenceTemplate, definitionOfDone, ideaSectionHeading, taskOptions) {
|
|
448
448
|
const ideaTitle = await readIdeaTitle(fileSystem, dustPath, ideaSlug);
|
|
449
449
|
const taskTitle = `${prefix}${ideaTitle}`;
|
|
450
450
|
const filename = titleToFilename(taskTitle);
|
|
@@ -459,7 +459,7 @@ async function createIdeaTask(fileSystem, dustPath, prefix, ideaSlug, openingSen
|
|
|
459
459
|
return { filePath };
|
|
460
460
|
}
|
|
461
461
|
async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description) {
|
|
462
|
-
return
|
|
462
|
+
return createIdeaTransitionTask(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/principles/\` for alignment and \`.dust/facts/\` for relevant design decisions. See [${ideaTitle}](../ideas/${ideaSlug}.md). If you add open questions, use \`## Open Questions\` with \`### Question?\` headings and one or more \`#### Option\` headings beneath each question, and only add questions that are meaningful decisions worth asking.`, [
|
|
463
463
|
"Idea is thoroughly researched with relevant codebase context",
|
|
464
464
|
"Open questions are added for any ambiguous or underspecified aspects",
|
|
465
465
|
"Open questions follow the required heading format and focus on high-value decisions",
|
|
@@ -467,7 +467,7 @@ async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description)
|
|
|
467
467
|
], "Refines Idea", { description });
|
|
468
468
|
}
|
|
469
469
|
async function decomposeIdea(fileSystem, dustPath, options) {
|
|
470
|
-
return
|
|
470
|
+
return createIdeaTransitionTask(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).`, [
|
|
471
471
|
"One or more new tasks are created in .dust/tasks/",
|
|
472
472
|
"Task's Principles section links to relevant principles from .dust/principles/",
|
|
473
473
|
"The original idea is deleted or updated to reflect remaining scope"
|
|
@@ -477,18 +477,18 @@ async function decomposeIdea(fileSystem, dustPath, options) {
|
|
|
477
477
|
});
|
|
478
478
|
}
|
|
479
479
|
async function createShelveIdeaTask(fileSystem, dustPath, ideaSlug, description) {
|
|
480
|
-
return
|
|
480
|
+
return createIdeaTransitionTask(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 });
|
|
481
481
|
}
|
|
482
|
-
async function
|
|
483
|
-
const { title, description,
|
|
482
|
+
async function createIdeaTask(fileSystem, dustPath, options) {
|
|
483
|
+
const { title, description, expedite } = options;
|
|
484
484
|
if (!title || !title.trim()) {
|
|
485
485
|
throw new Error("title is required and must not be whitespace-only");
|
|
486
486
|
}
|
|
487
487
|
if (!description || !description.trim()) {
|
|
488
488
|
throw new Error("description is required and must not be whitespace-only");
|
|
489
489
|
}
|
|
490
|
-
if (
|
|
491
|
-
const taskTitle2 = `${
|
|
490
|
+
if (expedite) {
|
|
491
|
+
const taskTitle2 = `${EXPEDITE_IDEA_PREFIX}${title}`;
|
|
492
492
|
const filename2 = titleToFilename(taskTitle2);
|
|
493
493
|
const filePath2 = `${dustPath}/tasks/${filename2}`;
|
|
494
494
|
const content2 = `# ${taskTitle2}
|
|
@@ -550,13 +550,13 @@ async function parseCaptureIdeaTask(fileSystem, dustPath, taskSlug) {
|
|
|
550
550
|
}
|
|
551
551
|
const title = titleMatch[1].trim();
|
|
552
552
|
let ideaTitle;
|
|
553
|
-
let
|
|
554
|
-
if (title.startsWith(
|
|
555
|
-
ideaTitle = title.slice(
|
|
556
|
-
|
|
553
|
+
let expedite;
|
|
554
|
+
if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
|
|
555
|
+
ideaTitle = title.slice(EXPEDITE_IDEA_PREFIX.length);
|
|
556
|
+
expedite = true;
|
|
557
557
|
} else if (title.startsWith(CAPTURE_IDEA_PREFIX)) {
|
|
558
558
|
ideaTitle = title.slice(CAPTURE_IDEA_PREFIX.length);
|
|
559
|
-
|
|
559
|
+
expedite = false;
|
|
560
560
|
} else {
|
|
561
561
|
return null;
|
|
562
562
|
}
|
|
@@ -565,7 +565,7 @@ async function parseCaptureIdeaTask(fileSystem, dustPath, taskSlug) {
|
|
|
565
565
|
return null;
|
|
566
566
|
}
|
|
567
567
|
const ideaDescription = descriptionMatch[1];
|
|
568
|
-
return { ideaTitle, ideaDescription,
|
|
568
|
+
return { ideaTitle, ideaDescription, expedite };
|
|
569
569
|
}
|
|
570
570
|
|
|
571
571
|
// lib/artifacts/index.ts
|
|
@@ -624,8 +624,8 @@ function buildArtifactsRepository(fileSystem, dustPath) {
|
|
|
624
624
|
async createShelveIdeaTask(options) {
|
|
625
625
|
return createShelveIdeaTask(fileSystem, dustPath, options.ideaSlug, options.description);
|
|
626
626
|
},
|
|
627
|
-
async
|
|
628
|
-
return
|
|
627
|
+
async createIdeaTask(options) {
|
|
628
|
+
return createIdeaTask(fileSystem, dustPath, options);
|
|
629
629
|
},
|
|
630
630
|
async findWorkflowTaskForIdea(options) {
|
|
631
631
|
return findWorkflowTaskForIdea(fileSystem, dustPath, options.ideaSlug);
|
package/dist/dust.js
CHANGED
|
@@ -275,7 +275,7 @@ 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.72";
|
|
279
279
|
|
|
280
280
|
// lib/session.ts
|
|
281
281
|
var DUST_UNATTENDED = "DUST_UNATTENDED";
|
|
@@ -2285,7 +2285,7 @@ var IDEA_TRANSITION_PREFIXES = [
|
|
|
2285
2285
|
"Decompose Idea: ",
|
|
2286
2286
|
"Shelve Idea: "
|
|
2287
2287
|
];
|
|
2288
|
-
var
|
|
2288
|
+
var EXPEDITE_IDEA_PREFIX = "Expedite Idea: ";
|
|
2289
2289
|
function titleToFilename(title) {
|
|
2290
2290
|
return `${title.toLowerCase().replace(/\./g, "-").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
2291
2291
|
}
|
|
@@ -2294,7 +2294,7 @@ function titleToFilename(title) {
|
|
|
2294
2294
|
function buildImplementationInstructions(bin, hooksInstalled, taskTitle) {
|
|
2295
2295
|
const steps = [];
|
|
2296
2296
|
let step = 1;
|
|
2297
|
-
const hasIdeaFile = !taskTitle?.startsWith(
|
|
2297
|
+
const hasIdeaFile = !taskTitle?.startsWith(EXPEDITE_IDEA_PREFIX);
|
|
2298
2298
|
steps.push(`Note: Do NOT run \`${bin} agent\`.`, "");
|
|
2299
2299
|
steps.push(`${step}. Run \`${bin} check\` to verify the project is in a good state`);
|
|
2300
2300
|
step++;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory FileSystem emulator for testing and cache-backed use cases.
|
|
3
|
+
*
|
|
4
|
+
* Provides a complete FileSystem + GlobScanner implementation backed by
|
|
5
|
+
* an in-memory file tree, with write tracking for test assertions.
|
|
6
|
+
*/
|
|
7
|
+
import type { FileSystem, GlobScanner } from './types';
|
|
8
|
+
export type FileSystemTree = {
|
|
9
|
+
[name: string]: string | FileSystemTree;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Extended file system with write tracking for assertions.
|
|
13
|
+
* Also implements GlobScanner by scanning over known files.
|
|
14
|
+
*/
|
|
15
|
+
export interface FileSystemEmulator extends FileSystem, GlobScanner {
|
|
16
|
+
createdDirs: string[];
|
|
17
|
+
writtenFiles: Map<string, string>;
|
|
18
|
+
/** Internal files map - exposed for tests that need to modify file system state */
|
|
19
|
+
files: Map<string, string>;
|
|
20
|
+
/** File permissions set via chmod - maps path to mode */
|
|
21
|
+
permissions: Map<string, number>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a file system emulator with optional file contents and write tracking.
|
|
25
|
+
* Implements both FileSystem and GlobScanner interfaces - the scan() method
|
|
26
|
+
* iterates over the files the emulator knows about.
|
|
27
|
+
*
|
|
28
|
+
* @param tree - Nested object representing file system hierarchy
|
|
29
|
+
* @returns FileSystemEmulator with tracking for created directories and written files
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* createFileSystemEmulator({
|
|
33
|
+
* project: {
|
|
34
|
+
* '.dust': {
|
|
35
|
+
* principles: { 'my-principle.md': '# My Principle' },
|
|
36
|
+
* ideas: {} // empty directory
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
* })
|
|
40
|
+
*/
|
|
41
|
+
export declare function createFileSystemEmulator(tree?: FileSystemTree): FileSystemEmulator;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// lib/filesystem/emulator.ts
|
|
2
|
+
function flattenFileSystemTree(tree, basePath = "") {
|
|
3
|
+
const files = new Map;
|
|
4
|
+
const paths = new Set;
|
|
5
|
+
for (const [name, value] of Object.entries(tree)) {
|
|
6
|
+
const fullPath = basePath ? `${basePath}/${name}` : `/${name}`;
|
|
7
|
+
if (typeof value === "string") {
|
|
8
|
+
files.set(fullPath, value);
|
|
9
|
+
paths.add(fullPath);
|
|
10
|
+
} else {
|
|
11
|
+
paths.add(fullPath);
|
|
12
|
+
const nested = flattenFileSystemTree(value, fullPath);
|
|
13
|
+
for (const [path, content] of nested.files) {
|
|
14
|
+
files.set(path, content);
|
|
15
|
+
}
|
|
16
|
+
for (const path of nested.paths) {
|
|
17
|
+
paths.add(path);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const path of [...files.keys(), ...paths]) {
|
|
22
|
+
let dir = path;
|
|
23
|
+
while (dir.includes("/")) {
|
|
24
|
+
dir = dir.substring(0, dir.lastIndexOf("/"));
|
|
25
|
+
if (dir)
|
|
26
|
+
paths.add(dir);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { files, paths };
|
|
30
|
+
}
|
|
31
|
+
function createFileSystemEmulator(tree = {}) {
|
|
32
|
+
const { files, paths } = flattenFileSystemTree(tree);
|
|
33
|
+
const createdDirs = [];
|
|
34
|
+
const writtenFiles = new Map;
|
|
35
|
+
const permissions = new Map;
|
|
36
|
+
const creationTimes = new Map;
|
|
37
|
+
let nextCreationTime = 1000;
|
|
38
|
+
for (const path of files.keys()) {
|
|
39
|
+
creationTimes.set(path, nextCreationTime++);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
exists: (path) => paths.has(path),
|
|
43
|
+
isDirectory: (path) => paths.has(path) && !files.has(path),
|
|
44
|
+
readFile: async (path) => {
|
|
45
|
+
if (!files.has(path)) {
|
|
46
|
+
const error = new Error(`ENOENT: no such file or directory, open '${path}'`);
|
|
47
|
+
error.code = "ENOENT";
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
return files.get(path);
|
|
51
|
+
},
|
|
52
|
+
writeFile: async (path, content, options) => {
|
|
53
|
+
if (options?.flag === "wx" && paths.has(path)) {
|
|
54
|
+
const error = new Error(`EEXIST: file already exists, open '${path}'`);
|
|
55
|
+
error.code = "EEXIST";
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
writtenFiles.set(path, content);
|
|
59
|
+
paths.add(path);
|
|
60
|
+
files.set(path, content);
|
|
61
|
+
if (!creationTimes.has(path)) {
|
|
62
|
+
creationTimes.set(path, nextCreationTime++);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
mkdir: async (path) => {
|
|
66
|
+
createdDirs.push(path);
|
|
67
|
+
},
|
|
68
|
+
readdir: async (path) => {
|
|
69
|
+
const prefix = `${path}/`;
|
|
70
|
+
const entries = new Set;
|
|
71
|
+
for (const f of files.keys()) {
|
|
72
|
+
if (f.startsWith(prefix)) {
|
|
73
|
+
const relativePath = f.slice(prefix.length);
|
|
74
|
+
if (!relativePath.includes("/")) {
|
|
75
|
+
entries.add(relativePath);
|
|
76
|
+
} else {
|
|
77
|
+
entries.add(relativePath.split("/")[0]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return Array.from(entries);
|
|
82
|
+
},
|
|
83
|
+
chmod: async (path, mode) => {
|
|
84
|
+
permissions.set(path, mode);
|
|
85
|
+
},
|
|
86
|
+
getFileCreationTime: (path) => {
|
|
87
|
+
return creationTimes.get(path) ?? 0;
|
|
88
|
+
},
|
|
89
|
+
scan: async function* (dir) {
|
|
90
|
+
if (!paths.has(dir)) {
|
|
91
|
+
const error = new Error(`ENOENT: no such file or directory, scandir '${dir}'`);
|
|
92
|
+
error.code = "ENOENT";
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
const prefix = `${dir}/`;
|
|
96
|
+
for (const file of files.keys()) {
|
|
97
|
+
if (file.startsWith(prefix)) {
|
|
98
|
+
yield file.slice(prefix.length);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
rename: async (oldPath, newPath) => {
|
|
103
|
+
const entriesToMove = [];
|
|
104
|
+
const pathsToUpdate = [];
|
|
105
|
+
for (const [path, content] of files.entries()) {
|
|
106
|
+
if (path === oldPath || path.startsWith(`${oldPath}/`)) {
|
|
107
|
+
const relativePath = path.slice(oldPath.length);
|
|
108
|
+
const newFilePath = `${newPath}${relativePath}`;
|
|
109
|
+
entriesToMove.push([path, newFilePath]);
|
|
110
|
+
files.set(newFilePath, content);
|
|
111
|
+
paths.add(newFilePath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const path of paths) {
|
|
115
|
+
if (path === oldPath || path.startsWith(`${oldPath}/`)) {
|
|
116
|
+
pathsToUpdate.push(path);
|
|
117
|
+
const relativePath = path.slice(oldPath.length);
|
|
118
|
+
paths.add(`${newPath}${relativePath}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const [oldFilePath] of entriesToMove) {
|
|
122
|
+
files.delete(oldFilePath);
|
|
123
|
+
paths.delete(oldFilePath);
|
|
124
|
+
}
|
|
125
|
+
for (const oldPathEntry of pathsToUpdate) {
|
|
126
|
+
paths.delete(oldPathEntry);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
createdDirs,
|
|
130
|
+
writtenFiles,
|
|
131
|
+
files,
|
|
132
|
+
permissions
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
createFileSystemEmulator
|
|
137
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joshski/dust",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.72",
|
|
4
4
|
"description": "Flow state for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"./filesystem": {
|
|
30
30
|
"types": "./dist/filesystem/types.d.ts"
|
|
31
31
|
},
|
|
32
|
+
"./filesystem/emulator": {
|
|
33
|
+
"import": "./dist/filesystem-emulator.js",
|
|
34
|
+
"types": "./dist/filesystem/emulator.d.ts"
|
|
35
|
+
},
|
|
32
36
|
"./istanbul/minimal-reporter": "./lib/istanbul/minimal-reporter.cjs",
|
|
33
37
|
"./biome": {
|
|
34
38
|
"import": "./dist/biome.js",
|