@joshski/dust 0.1.102 → 0.1.103
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/.dust/principles/{enable-flow-state.md → agentic-flow-state.md} +6 -2
- package/.dust/principles/human-ai-collaboration.md +1 -1
- package/.dust/principles/maintainable-codebase.md +1 -1
- package/dist/agent-events.d.ts +1 -0
- package/dist/bucket/repository.d.ts +4 -0
- package/dist/claude/types.d.ts +4 -0
- package/dist/codex/spawn-codex.d.ts +5 -1
- package/dist/command-events.d.ts +2 -1
- package/dist/container/apple-container-runtime.d.ts +12 -0
- package/dist/container/docker-runtime.d.ts +21 -0
- package/dist/container/runtime.d.ts +71 -0
- package/dist/container/select-runtime.d.ts +28 -0
- package/dist/docker/docker-agent.d.ts +35 -44
- package/dist/dust.js +641 -216
- package/dist/lint/validators/audit-validator.d.ts +15 -0
- package/dist/loop/iteration.d.ts +2 -0
- package/dist/patch.js +65 -1
- package/dist/session.d.ts +2 -0
- package/dist/validation/validation-pipeline.d.ts +1 -0
- package/dist/validation.js +65 -1
- package/lib/docker/default.Dockerfile +8 -0
- package/package.json +2 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit file validation for .dust/config/audits/ markdown files.
|
|
3
|
+
*
|
|
4
|
+
* Custom audits must follow the same structure as stock audits:
|
|
5
|
+
* - Opening description after H1 title
|
|
6
|
+
* - ## Scope section
|
|
7
|
+
* - ## Blocked By section
|
|
8
|
+
* - ## Definition of Done section
|
|
9
|
+
*/
|
|
10
|
+
import type { ParsedArtifact } from '../../artifacts/parsed-artifact';
|
|
11
|
+
import type { Violation } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Validates that an audit file contains all required section headings.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateAuditHeadings(artifact: ParsedArtifact): Violation[];
|
package/dist/loop/iteration.d.ts
CHANGED
|
@@ -39,6 +39,8 @@ export interface IterationOptions {
|
|
|
39
39
|
proxyPort?: number;
|
|
40
40
|
/** Branch name when working on a non-default branch */
|
|
41
41
|
branch?: string;
|
|
42
|
+
/** Trace ID for correlating events across processes */
|
|
43
|
+
traceId?: string;
|
|
42
44
|
}
|
|
43
45
|
export declare function findAvailableTasks(dependencies: CommandDependencies): Promise<{
|
|
44
46
|
tasks: UnblockedTask[];
|
package/dist/patch.js
CHANGED
|
@@ -225,6 +225,22 @@ function createOverlayFileSystem(base, patchFiles, deletedPaths = new Set) {
|
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
// lib/lint/validators/audit-validator.ts
|
|
229
|
+
var REQUIRED_AUDIT_HEADINGS = ["Scope", "Blocked By", "Definition of Done"];
|
|
230
|
+
function validateAuditHeadings(artifact) {
|
|
231
|
+
const violations = [];
|
|
232
|
+
const sectionHeadings = new Set(artifact.sections.map((s) => s.heading));
|
|
233
|
+
for (const heading of REQUIRED_AUDIT_HEADINGS) {
|
|
234
|
+
if (!sectionHeadings.has(heading)) {
|
|
235
|
+
violations.push({
|
|
236
|
+
file: artifact.filePath,
|
|
237
|
+
message: `Missing required heading: "## ${heading}"`
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return violations;
|
|
242
|
+
}
|
|
243
|
+
|
|
228
244
|
// lib/lint/validators/content-validator.ts
|
|
229
245
|
var REQUIRED_TASK_HEADINGS = ["Blocked By", "Definition of Done"];
|
|
230
246
|
var MAX_OPENING_SENTENCE_LENGTH = 150;
|
|
@@ -519,6 +535,12 @@ function validateWorkflowTaskBodySection(artifact, ideasPath, fileSystem) {
|
|
|
519
535
|
}
|
|
520
536
|
if (!matchedPrefix)
|
|
521
537
|
return violations;
|
|
538
|
+
if (matchedPrefix === "Expedite Idea: ") {
|
|
539
|
+
const hasIdeaDescriptionSection = artifact.sections.some((s) => s.heading === "Idea Description" && s.level === 2);
|
|
540
|
+
if (hasIdeaDescriptionSection) {
|
|
541
|
+
return violations;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
522
544
|
const expectedHeading = WORKFLOW_PREFIX_TO_SECTION[matchedPrefix];
|
|
523
545
|
const section = artifact.sections.find((s) => s.heading === expectedHeading && s.level === 2);
|
|
524
546
|
if (!section) {
|
|
@@ -816,6 +838,7 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
816
838
|
tasks: []
|
|
817
839
|
};
|
|
818
840
|
const rootFiles = [];
|
|
841
|
+
const customAudits = [];
|
|
819
842
|
const violations = [];
|
|
820
843
|
let rootEntries;
|
|
821
844
|
try {
|
|
@@ -874,11 +897,40 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
874
897
|
byType[dir].push(artifact);
|
|
875
898
|
}
|
|
876
899
|
}
|
|
900
|
+
const auditsPath = `${dustPath}/config/audits`;
|
|
901
|
+
let auditEntries;
|
|
902
|
+
try {
|
|
903
|
+
auditEntries = await fileSystem.readdir(auditsPath);
|
|
904
|
+
} catch (error) {
|
|
905
|
+
if (error.code === "ENOENT") {
|
|
906
|
+
auditEntries = [];
|
|
907
|
+
} else {
|
|
908
|
+
throw error;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
for (const entry of auditEntries) {
|
|
912
|
+
if (!entry.endsWith(".md"))
|
|
913
|
+
continue;
|
|
914
|
+
const filePath = `${auditsPath}/${entry}`;
|
|
915
|
+
let content;
|
|
916
|
+
try {
|
|
917
|
+
content = await fileSystem.readFile(filePath);
|
|
918
|
+
} catch (error) {
|
|
919
|
+
if (error.code === "ENOENT") {
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
throw error;
|
|
923
|
+
}
|
|
924
|
+
const artifact = parseArtifact(filePath, content);
|
|
925
|
+
artifacts.set(filePath, artifact);
|
|
926
|
+
customAudits.push(artifact);
|
|
927
|
+
}
|
|
877
928
|
return {
|
|
878
929
|
context: {
|
|
879
930
|
artifacts,
|
|
880
931
|
byType,
|
|
881
932
|
rootFiles,
|
|
933
|
+
customAudits,
|
|
882
934
|
dustPath,
|
|
883
935
|
fileSystem
|
|
884
936
|
},
|
|
@@ -887,7 +939,7 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
887
939
|
}
|
|
888
940
|
function validateArtifacts(context) {
|
|
889
941
|
const violations = [];
|
|
890
|
-
const { byType, rootFiles, dustPath, fileSystem } = context;
|
|
942
|
+
const { byType, rootFiles, customAudits, dustPath, fileSystem } = context;
|
|
891
943
|
const ideasPath = `${dustPath}/ideas`;
|
|
892
944
|
for (const artifact of rootFiles) {
|
|
893
945
|
violations.push(...validateLinks(artifact, fileSystem));
|
|
@@ -931,6 +983,18 @@ function validateArtifacts(context) {
|
|
|
931
983
|
}
|
|
932
984
|
violations.push(...validateBidirectionalLinks(allPrincipleRelationships));
|
|
933
985
|
violations.push(...validateNoCycles(allPrincipleRelationships));
|
|
986
|
+
for (const artifact of customAudits) {
|
|
987
|
+
const filenameViolation = validateFilename(artifact.filePath);
|
|
988
|
+
if (filenameViolation)
|
|
989
|
+
violations.push(filenameViolation);
|
|
990
|
+
const openingSentenceViolation = validateOpeningSentence(artifact);
|
|
991
|
+
if (openingSentenceViolation)
|
|
992
|
+
violations.push(openingSentenceViolation);
|
|
993
|
+
const lengthViolation = validateOpeningSentenceLength(artifact);
|
|
994
|
+
if (lengthViolation)
|
|
995
|
+
violations.push(lengthViolation);
|
|
996
|
+
violations.push(...validateAuditHeadings(artifact));
|
|
997
|
+
}
|
|
934
998
|
return violations;
|
|
935
999
|
}
|
|
936
1000
|
|
package/dist/session.d.ts
CHANGED
|
@@ -3,9 +3,11 @@ export declare const DUST_UNATTENDED = "DUST_UNATTENDED";
|
|
|
3
3
|
export declare const DUST_SKIP_AGENT = "DUST_SKIP_AGENT";
|
|
4
4
|
export declare const DUST_REPOSITORY_ID = "DUST_REPOSITORY_ID";
|
|
5
5
|
export declare const DUST_PROXY_PORT = "DUST_PROXY_PORT";
|
|
6
|
+
export declare const DUST_TRACE_ID = "DUST_TRACE_ID";
|
|
6
7
|
export declare function isUnattended(session: SessionConfig): boolean;
|
|
7
8
|
export declare function buildUnattendedEnv(options: {
|
|
8
9
|
repositoryId?: string;
|
|
9
10
|
proxyPort?: number;
|
|
11
|
+
traceId?: string;
|
|
10
12
|
session: SessionConfig;
|
|
11
13
|
}): Record<string, string>;
|
package/dist/validation.js
CHANGED
|
@@ -222,6 +222,22 @@ var ARTIFACT_TYPES = [
|
|
|
222
222
|
"tasks"
|
|
223
223
|
];
|
|
224
224
|
|
|
225
|
+
// lib/lint/validators/audit-validator.ts
|
|
226
|
+
var REQUIRED_AUDIT_HEADINGS = ["Scope", "Blocked By", "Definition of Done"];
|
|
227
|
+
function validateAuditHeadings(artifact) {
|
|
228
|
+
const violations = [];
|
|
229
|
+
const sectionHeadings = new Set(artifact.sections.map((s) => s.heading));
|
|
230
|
+
for (const heading of REQUIRED_AUDIT_HEADINGS) {
|
|
231
|
+
if (!sectionHeadings.has(heading)) {
|
|
232
|
+
violations.push({
|
|
233
|
+
file: artifact.filePath,
|
|
234
|
+
message: `Missing required heading: "## ${heading}"`
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return violations;
|
|
239
|
+
}
|
|
240
|
+
|
|
225
241
|
// lib/lint/validators/content-validator.ts
|
|
226
242
|
var REQUIRED_TASK_HEADINGS = ["Blocked By", "Definition of Done"];
|
|
227
243
|
var MAX_OPENING_SENTENCE_LENGTH = 150;
|
|
@@ -516,6 +532,12 @@ function validateWorkflowTaskBodySection(artifact, ideasPath, fileSystem) {
|
|
|
516
532
|
}
|
|
517
533
|
if (!matchedPrefix)
|
|
518
534
|
return violations;
|
|
535
|
+
if (matchedPrefix === "Expedite Idea: ") {
|
|
536
|
+
const hasIdeaDescriptionSection = artifact.sections.some((s) => s.heading === "Idea Description" && s.level === 2);
|
|
537
|
+
if (hasIdeaDescriptionSection) {
|
|
538
|
+
return violations;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
519
541
|
const expectedHeading = WORKFLOW_PREFIX_TO_SECTION[matchedPrefix];
|
|
520
542
|
const section = artifact.sections.find((s) => s.heading === expectedHeading && s.level === 2);
|
|
521
543
|
if (!section) {
|
|
@@ -813,6 +835,7 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
813
835
|
tasks: []
|
|
814
836
|
};
|
|
815
837
|
const rootFiles = [];
|
|
838
|
+
const customAudits = [];
|
|
816
839
|
const violations = [];
|
|
817
840
|
let rootEntries;
|
|
818
841
|
try {
|
|
@@ -871,11 +894,40 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
871
894
|
byType[dir].push(artifact);
|
|
872
895
|
}
|
|
873
896
|
}
|
|
897
|
+
const auditsPath = `${dustPath}/config/audits`;
|
|
898
|
+
let auditEntries;
|
|
899
|
+
try {
|
|
900
|
+
auditEntries = await fileSystem.readdir(auditsPath);
|
|
901
|
+
} catch (error) {
|
|
902
|
+
if (error.code === "ENOENT") {
|
|
903
|
+
auditEntries = [];
|
|
904
|
+
} else {
|
|
905
|
+
throw error;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
for (const entry of auditEntries) {
|
|
909
|
+
if (!entry.endsWith(".md"))
|
|
910
|
+
continue;
|
|
911
|
+
const filePath = `${auditsPath}/${entry}`;
|
|
912
|
+
let content;
|
|
913
|
+
try {
|
|
914
|
+
content = await fileSystem.readFile(filePath);
|
|
915
|
+
} catch (error) {
|
|
916
|
+
if (error.code === "ENOENT") {
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
throw error;
|
|
920
|
+
}
|
|
921
|
+
const artifact = parseArtifact(filePath, content);
|
|
922
|
+
artifacts.set(filePath, artifact);
|
|
923
|
+
customAudits.push(artifact);
|
|
924
|
+
}
|
|
874
925
|
return {
|
|
875
926
|
context: {
|
|
876
927
|
artifacts,
|
|
877
928
|
byType,
|
|
878
929
|
rootFiles,
|
|
930
|
+
customAudits,
|
|
879
931
|
dustPath,
|
|
880
932
|
fileSystem
|
|
881
933
|
},
|
|
@@ -884,7 +936,7 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
884
936
|
}
|
|
885
937
|
function validateArtifacts(context) {
|
|
886
938
|
const violations = [];
|
|
887
|
-
const { byType, rootFiles, dustPath, fileSystem } = context;
|
|
939
|
+
const { byType, rootFiles, customAudits, dustPath, fileSystem } = context;
|
|
888
940
|
const ideasPath = `${dustPath}/ideas`;
|
|
889
941
|
for (const artifact of rootFiles) {
|
|
890
942
|
violations.push(...validateLinks(artifact, fileSystem));
|
|
@@ -928,6 +980,18 @@ function validateArtifacts(context) {
|
|
|
928
980
|
}
|
|
929
981
|
violations.push(...validateBidirectionalLinks(allPrincipleRelationships));
|
|
930
982
|
violations.push(...validateNoCycles(allPrincipleRelationships));
|
|
983
|
+
for (const artifact of customAudits) {
|
|
984
|
+
const filenameViolation = validateFilename(artifact.filePath);
|
|
985
|
+
if (filenameViolation)
|
|
986
|
+
violations.push(filenameViolation);
|
|
987
|
+
const openingSentenceViolation = validateOpeningSentence(artifact);
|
|
988
|
+
if (openingSentenceViolation)
|
|
989
|
+
violations.push(openingSentenceViolation);
|
|
990
|
+
const lengthViolation = validateOpeningSentenceLength(artifact);
|
|
991
|
+
if (lengthViolation)
|
|
992
|
+
violations.push(lengthViolation);
|
|
993
|
+
violations.push(...validateAuditHeadings(artifact));
|
|
994
|
+
}
|
|
931
995
|
return violations;
|
|
932
996
|
}
|
|
933
997
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
FROM oven/bun:1
|
|
2
|
+
RUN apt-get update && apt-get install -y git nodejs npm curl && rm -rf /var/lib/apt/lists/*
|
|
3
|
+
RUN npm install -g @anthropic-ai/claude-code @openai/codex
|
|
4
|
+
# Install system libraries required by Playwright browsers (Chromium, Firefox, WebKit)
|
|
5
|
+
RUN npx -y playwright install-deps
|
|
6
|
+
RUN useradd -m -s /bin/bash user
|
|
7
|
+
USER user
|
|
8
|
+
WORKDIR /workspace
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joshski/dust",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.103",
|
|
4
4
|
"description": "Flow state for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"dist",
|
|
56
56
|
"bin",
|
|
57
57
|
"lib/istanbul/minimal-reporter.cjs",
|
|
58
|
+
"lib/docker/default.Dockerfile",
|
|
58
59
|
"biome",
|
|
59
60
|
".dust/principles"
|
|
60
61
|
],
|