@joshski/dust 0.1.102 → 0.1.104
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/agents/detection.d.ts +1 -1
- package/dist/agents.js +1 -1
- package/dist/artifacts/facts.d.ts +2 -2
- package/dist/artifacts/ideas.d.ts +2 -2
- package/dist/artifacts/index.d.ts +2 -2
- package/dist/artifacts/principles.d.ts +2 -2
- package/dist/artifacts/tasks.d.ts +2 -2
- package/dist/artifacts/workflow-tasks.d.ts +6 -0
- package/dist/artifacts.js +142 -25
- package/dist/audits/index.d.ts +1 -0
- package/dist/audits.js +24 -1
- package/dist/bucket/repository-loop.d.ts +4 -4
- package/dist/bucket/repository.d.ts +14 -0
- package/dist/claude/run.d.ts +3 -9
- package/dist/claude/spawn-claude-code.d.ts +1 -1
- package/dist/claude/types.d.ts +13 -0
- package/dist/cli/commands/focus.d.ts +2 -1
- package/dist/cli/shared/agent-shared.d.ts +4 -4
- package/dist/cli/types.d.ts +1 -1
- package/dist/codex/run.d.ts +3 -9
- package/dist/codex/spawn-codex.d.ts +6 -2
- package/dist/command-events.d.ts +2 -1
- package/dist/config/settings.d.ts +5 -5
- 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/core-principles.js +5 -16
- package/dist/docker/docker-agent.d.ts +33 -46
- package/dist/dust.js +959 -581
- package/dist/filesystem/types.d.ts +5 -1
- package/dist/lint/validators/audit-validator.d.ts +15 -0
- package/dist/lint/validators/content-validator.d.ts +1 -0
- package/dist/lint/validators/directory-validator.d.ts +3 -3
- package/dist/lint/validators/idea-validator.d.ts +3 -3
- package/dist/lint/validators/link-validator.d.ts +2 -2
- package/dist/loop/iteration.d.ts +4 -3
- package/dist/patch/index.d.ts +13 -0
- package/dist/patch.js +106 -109
- package/dist/proxy/helper-token.d.ts +2 -2
- package/dist/session.d.ts +2 -0
- package/dist/validation/validation-pipeline.d.ts +1 -0
- package/dist/validation.js +96 -109
- package/lib/docker/default.Dockerfile +8 -0
- package/package.json +3 -2
|
@@ -4,12 +4,16 @@
|
|
|
4
4
|
export interface WriteOptions {
|
|
5
5
|
flag?: 'w' | 'wx';
|
|
6
6
|
}
|
|
7
|
-
export interface
|
|
7
|
+
export interface FileReader {
|
|
8
8
|
exists: (path: string) => boolean;
|
|
9
9
|
readFile: (path: string) => Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
export interface DirectoryReader {
|
|
10
12
|
readdir: (path: string) => Promise<string[]>;
|
|
11
13
|
isDirectory: (path: string) => boolean;
|
|
12
14
|
}
|
|
15
|
+
export interface ReadableFileSystem extends FileReader, DirectoryReader {
|
|
16
|
+
}
|
|
13
17
|
export interface FileSystem extends ReadableFileSystem {
|
|
14
18
|
writeFile: (path: string, content: string, options?: WriteOptions) => Promise<void>;
|
|
15
19
|
mkdir: (path: string, options?: {
|
|
@@ -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[];
|
|
@@ -7,3 +7,4 @@ export declare function validateOpeningSentence(artifact: ParsedArtifact): Viola
|
|
|
7
7
|
export declare function validateOpeningSentenceLength(artifact: ParsedArtifact): Violation | null;
|
|
8
8
|
export declare function validateImperativeOpeningSentence(artifact: ParsedArtifact): Violation | null;
|
|
9
9
|
export declare function validateTaskHeadings(artifact: ParsedArtifact): Violation[];
|
|
10
|
+
export declare function validateTaskType(artifact: ParsedArtifact): Violation | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Directory structure validation for .dust
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { DirectoryReader } from '../../filesystem/types';
|
|
5
5
|
import type { Violation } from './types';
|
|
6
|
-
export declare function validateContentDirectoryFiles(dirPath: string, fileSystem:
|
|
7
|
-
export declare function validateDirectoryStructure(dustPath: string, fileSystem:
|
|
6
|
+
export declare function validateContentDirectoryFiles(dirPath: string, fileSystem: DirectoryReader): Promise<Violation[]>;
|
|
7
|
+
export declare function validateDirectoryStructure(dustPath: string, fileSystem: DirectoryReader): Promise<Violation[]>;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Idea file validation for .dust markdown files
|
|
3
3
|
*/
|
|
4
4
|
import type { ParsedArtifact } from '../../artifacts/parsed-artifact';
|
|
5
|
-
import type {
|
|
5
|
+
import type { FileReader } from '../../filesystem/types';
|
|
6
6
|
import type { Violation } from './types';
|
|
7
7
|
export declare function validateIdeaOpenQuestions(artifact: ParsedArtifact): Violation[];
|
|
8
|
-
export declare function validateIdeaTransitionTitle(
|
|
9
|
-
export declare function validateWorkflowTaskBodySection(
|
|
8
|
+
export declare function validateIdeaTransitionTitle(_artifact: ParsedArtifact, _ideasPath: string, _fileSystem: FileReader): Violation | null;
|
|
9
|
+
export declare function validateWorkflowTaskBodySection(_artifact: ParsedArtifact, _ideasPath: string, _fileSystem: FileReader): Violation[];
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Link validation for .dust markdown files
|
|
3
3
|
*/
|
|
4
4
|
import type { ParsedArtifact } from '../../artifacts/parsed-artifact';
|
|
5
|
-
import type {
|
|
5
|
+
import type { FileReader } from '../../filesystem/types';
|
|
6
6
|
import type { Violation } from './types';
|
|
7
|
-
export declare function validateLinks(artifact: ParsedArtifact, fileSystem:
|
|
7
|
+
export declare function validateLinks(artifact: ParsedArtifact, fileSystem: FileReader): Violation[];
|
|
8
8
|
export declare function validateSemanticLinks(artifact: ParsedArtifact): Violation[];
|
|
9
9
|
export declare function validatePrincipleHierarchyLinks(artifact: ParsedArtifact): Violation[];
|
package/dist/loop/iteration.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { spawn as nodeSpawn } from 'node:child_process';
|
|
2
|
-
import {
|
|
3
|
-
import type { DockerSpawnConfig } from '../claude/types';
|
|
2
|
+
import type { BoundRunFn, DockerSpawnConfig } from '../claude/types';
|
|
4
3
|
import type { DockerDependencies } from '../docker/docker-agent';
|
|
5
4
|
import { type SessionConfig } from '../env-config';
|
|
6
5
|
import { type ShellRunner } from '../cli/process-runner';
|
|
@@ -11,7 +10,7 @@ import type { PostEventFn, SendAgentEventFn } from './wire-events';
|
|
|
11
10
|
export declare const DUST_QUICK_REFERENCE = "## Dust Quick Reference\n\nDust stores project context in `.dust/` as markdown artifacts. Use these commands to explore:\n\n- `dust ideas` \u2014 list ideas for future work\n- `dust principles` \u2014 show guiding values and design constraints\n- `dust facts` \u2014 show current state documentation\n- `dust help` \u2014 see all available commands\n\nUse dust commands instead of manually searching `.dust/` directories.";
|
|
12
11
|
export interface LoopDependencies {
|
|
13
12
|
spawn: typeof nodeSpawn;
|
|
14
|
-
run:
|
|
13
|
+
run: BoundRunFn;
|
|
15
14
|
sleep: (ms: number) => Promise<void>;
|
|
16
15
|
postEvent: PostEventFn;
|
|
17
16
|
session: SessionConfig;
|
|
@@ -39,6 +38,8 @@ export interface IterationOptions {
|
|
|
39
38
|
proxyPort?: number;
|
|
40
39
|
/** Branch name when working on a non-default branch */
|
|
41
40
|
branch?: string;
|
|
41
|
+
/** Trace ID for correlating events across processes */
|
|
42
|
+
traceId?: string;
|
|
42
43
|
}
|
|
43
44
|
export declare function findAvailableTasks(dependencies: CommandDependencies): Promise<{
|
|
44
45
|
tasks: UnblockedTask[];
|
package/dist/patch/index.d.ts
CHANGED
|
@@ -42,6 +42,19 @@ export interface BuildArtifactPatchResult {
|
|
|
42
42
|
interface ValidatePatchOptions {
|
|
43
43
|
cwd?: string;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Parses artifact type and slug from a file path.
|
|
47
|
+
* E.g., 'facts/my-fact.md' → { type: 'fact', slug: 'my-fact' }
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseArtifactPath(path: string): {
|
|
50
|
+
type: ArtifactType;
|
|
51
|
+
slug: string;
|
|
52
|
+
} | null;
|
|
53
|
+
/**
|
|
54
|
+
* Builds preview objects from patch files.
|
|
55
|
+
* For create vs update determination, checks filesystem existence.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildPreviews(fileSystem: ReadableFileSystem, dustPath: string, files: Record<string, string | null>): Promise<ArtifactPreview[]>;
|
|
45
58
|
/**
|
|
46
59
|
* Builds an artifact patch from structured input objects.
|
|
47
60
|
*
|
package/dist/patch.js
CHANGED
|
@@ -139,12 +139,6 @@ function extractFirstSentence(paragraph) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// lib/artifacts/workflow-tasks.ts
|
|
142
|
-
var IDEA_TRANSITION_PREFIXES = [
|
|
143
|
-
"Refine Idea: ",
|
|
144
|
-
"Decompose Idea: ",
|
|
145
|
-
"Shelve Idea: ",
|
|
146
|
-
"Expedite Idea: "
|
|
147
|
-
];
|
|
148
142
|
function titleToFilename(title) {
|
|
149
143
|
return `${title.toLowerCase().replace(/\./g, "-").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
150
144
|
}
|
|
@@ -225,8 +219,31 @@ function createOverlayFileSystem(base, patchFiles, deletedPaths = new Set) {
|
|
|
225
219
|
};
|
|
226
220
|
}
|
|
227
221
|
|
|
222
|
+
// lib/lint/validators/audit-validator.ts
|
|
223
|
+
var REQUIRED_AUDIT_HEADINGS = ["Scope", "Blocked By", "Definition of Done"];
|
|
224
|
+
function validateAuditHeadings(artifact) {
|
|
225
|
+
const violations = [];
|
|
226
|
+
const sectionHeadings = new Set(artifact.sections.map((s) => s.heading));
|
|
227
|
+
for (const heading of REQUIRED_AUDIT_HEADINGS) {
|
|
228
|
+
if (!sectionHeadings.has(heading)) {
|
|
229
|
+
violations.push({
|
|
230
|
+
file: artifact.filePath,
|
|
231
|
+
message: `Missing required heading: "## ${heading}"`
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return violations;
|
|
236
|
+
}
|
|
237
|
+
|
|
228
238
|
// lib/lint/validators/content-validator.ts
|
|
229
|
-
var REQUIRED_TASK_HEADINGS = ["Blocked By", "Definition of Done"];
|
|
239
|
+
var REQUIRED_TASK_HEADINGS = ["Task Type", "Blocked By", "Definition of Done"];
|
|
240
|
+
var ALLOWED_TASK_TYPES = new Set([
|
|
241
|
+
"implement",
|
|
242
|
+
"capture",
|
|
243
|
+
"refine",
|
|
244
|
+
"decompose",
|
|
245
|
+
"shelve"
|
|
246
|
+
]);
|
|
230
247
|
var MAX_OPENING_SENTENCE_LENGTH = 150;
|
|
231
248
|
var NON_IMPERATIVE_STARTERS = new Set([
|
|
232
249
|
"the",
|
|
@@ -296,6 +313,32 @@ function validateTaskHeadings(artifact) {
|
|
|
296
313
|
}
|
|
297
314
|
return violations;
|
|
298
315
|
}
|
|
316
|
+
function validateTaskType(artifact) {
|
|
317
|
+
const taskTypeSection = artifact.sections.find((s) => s.heading === "Task Type");
|
|
318
|
+
if (!taskTypeSection) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
const lines = artifact.rawContent.split(`
|
|
322
|
+
`);
|
|
323
|
+
const sectionLines = lines.slice(taskTypeSection.startLine, taskTypeSection.endLine + 1);
|
|
324
|
+
const content = sectionLines.join(`
|
|
325
|
+
`).trim();
|
|
326
|
+
if (!content) {
|
|
327
|
+
return {
|
|
328
|
+
file: artifact.filePath,
|
|
329
|
+
line: taskTypeSection.startLine,
|
|
330
|
+
message: "Task Type section must contain one of: implement, capture, refine, decompose, shelve"
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
if (!ALLOWED_TASK_TYPES.has(content)) {
|
|
334
|
+
return {
|
|
335
|
+
file: artifact.filePath,
|
|
336
|
+
line: taskTypeSection.startLine,
|
|
337
|
+
message: `Invalid task type "${content}". Must be one of: implement, capture, refine, decompose, shelve`
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
299
342
|
|
|
300
343
|
// lib/lint/validators/directory-validator.ts
|
|
301
344
|
var EXPECTED_DIRECTORIES = [...ARTIFACT_TYPES, "config"];
|
|
@@ -367,12 +410,6 @@ function validateTitleFilenameMatch(artifact) {
|
|
|
367
410
|
}
|
|
368
411
|
|
|
369
412
|
// lib/lint/validators/idea-validator.ts
|
|
370
|
-
var WORKFLOW_PREFIX_TO_SECTION = {
|
|
371
|
-
"Refine Idea: ": "Refines Idea",
|
|
372
|
-
"Decompose Idea: ": "Decomposes Idea",
|
|
373
|
-
"Shelve Idea: ": "Shelves Idea",
|
|
374
|
-
"Expedite Idea: ": "Expedites Idea"
|
|
375
|
-
};
|
|
376
413
|
function validateH2Heading(filePath, line, lineNumber, inOpenQuestions, currentQuestionLine) {
|
|
377
414
|
const violations = [];
|
|
378
415
|
if (inOpenQuestions && currentQuestionLine !== null) {
|
|
@@ -479,96 +516,6 @@ function validateIdeaOpenQuestions(artifact) {
|
|
|
479
516
|
}
|
|
480
517
|
return violations;
|
|
481
518
|
}
|
|
482
|
-
function validateIdeaTransitionTitle(artifact, ideasPath, fileSystem) {
|
|
483
|
-
const title = artifact.title;
|
|
484
|
-
if (!title) {
|
|
485
|
-
return null;
|
|
486
|
-
}
|
|
487
|
-
for (const prefix of IDEA_TRANSITION_PREFIXES) {
|
|
488
|
-
if (title.startsWith(prefix)) {
|
|
489
|
-
if (prefix === "Expedite Idea: ") {
|
|
490
|
-
const hasIdeaDescriptionSection = artifact.sections.some((s) => s.heading === "Idea Description" && s.level === 2);
|
|
491
|
-
if (hasIdeaDescriptionSection) {
|
|
492
|
-
return null;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
const ideaTitle = title.slice(prefix.length);
|
|
496
|
-
const ideaFilename = titleToFilename(ideaTitle);
|
|
497
|
-
if (!fileSystem.exists(`${ideasPath}/${ideaFilename}`)) {
|
|
498
|
-
return {
|
|
499
|
-
file: artifact.filePath,
|
|
500
|
-
message: `Idea transition task references non-existent idea: "${ideaTitle}" (expected file "${ideaFilename}" in ideas/)`
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
return null;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
return null;
|
|
507
|
-
}
|
|
508
|
-
function validateWorkflowTaskBodySection(artifact, ideasPath, fileSystem) {
|
|
509
|
-
const violations = [];
|
|
510
|
-
const title = artifact.title;
|
|
511
|
-
if (!title)
|
|
512
|
-
return violations;
|
|
513
|
-
let matchedPrefix = null;
|
|
514
|
-
for (const prefix of IDEA_TRANSITION_PREFIXES) {
|
|
515
|
-
if (title.startsWith(prefix)) {
|
|
516
|
-
matchedPrefix = prefix;
|
|
517
|
-
break;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
if (!matchedPrefix)
|
|
521
|
-
return violations;
|
|
522
|
-
const expectedHeading = WORKFLOW_PREFIX_TO_SECTION[matchedPrefix];
|
|
523
|
-
const section = artifact.sections.find((s) => s.heading === expectedHeading && s.level === 2);
|
|
524
|
-
if (!section) {
|
|
525
|
-
violations.push({
|
|
526
|
-
file: artifact.filePath,
|
|
527
|
-
message: `Workflow task with "${matchedPrefix.trim()}" prefix is missing required "## ${expectedHeading}" section. Add a section with a link to the idea file, e.g.:
|
|
528
|
-
|
|
529
|
-
## ${expectedHeading}
|
|
530
|
-
|
|
531
|
-
- [Idea Title](../ideas/idea-slug.md)`
|
|
532
|
-
});
|
|
533
|
-
return violations;
|
|
534
|
-
}
|
|
535
|
-
if (section.links.length === 0) {
|
|
536
|
-
violations.push({
|
|
537
|
-
file: artifact.filePath,
|
|
538
|
-
message: `"## ${expectedHeading}" section contains no link. Add a markdown link to the idea file, e.g.:
|
|
539
|
-
|
|
540
|
-
- [Idea Title](../ideas/idea-slug.md)`,
|
|
541
|
-
line: section.startLine
|
|
542
|
-
});
|
|
543
|
-
return violations;
|
|
544
|
-
}
|
|
545
|
-
const ideaLinks = section.links.filter((l) => l.target.includes("/ideas/") || l.target.startsWith("../ideas/"));
|
|
546
|
-
if (ideaLinks.length === 0) {
|
|
547
|
-
violations.push({
|
|
548
|
-
file: artifact.filePath,
|
|
549
|
-
message: `"## ${expectedHeading}" section contains no link to an idea file. Links must point to a file in ../ideas/, e.g.:
|
|
550
|
-
|
|
551
|
-
- [Idea Title](../ideas/idea-slug.md)`,
|
|
552
|
-
line: section.startLine
|
|
553
|
-
});
|
|
554
|
-
return violations;
|
|
555
|
-
}
|
|
556
|
-
for (const link of ideaLinks) {
|
|
557
|
-
const slugMatch = link.target.match(/([^/]+)\.md$/);
|
|
558
|
-
if (!slugMatch)
|
|
559
|
-
continue;
|
|
560
|
-
const ideaSlug = slugMatch[1];
|
|
561
|
-
const ideaFilePath = `${ideasPath}/${ideaSlug}.md`;
|
|
562
|
-
if (!fileSystem.exists(ideaFilePath)) {
|
|
563
|
-
violations.push({
|
|
564
|
-
file: artifact.filePath,
|
|
565
|
-
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.`,
|
|
566
|
-
line: link.line
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
return violations;
|
|
571
|
-
}
|
|
572
519
|
|
|
573
520
|
// lib/lint/validators/link-validator.ts
|
|
574
521
|
import { dirname, resolve } from "node:path";
|
|
@@ -816,6 +763,7 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
816
763
|
tasks: []
|
|
817
764
|
};
|
|
818
765
|
const rootFiles = [];
|
|
766
|
+
const customAudits = [];
|
|
819
767
|
const violations = [];
|
|
820
768
|
let rootEntries;
|
|
821
769
|
try {
|
|
@@ -874,11 +822,40 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
874
822
|
byType[dir].push(artifact);
|
|
875
823
|
}
|
|
876
824
|
}
|
|
825
|
+
const auditsPath = `${dustPath}/config/audits`;
|
|
826
|
+
let auditEntries;
|
|
827
|
+
try {
|
|
828
|
+
auditEntries = await fileSystem.readdir(auditsPath);
|
|
829
|
+
} catch (error) {
|
|
830
|
+
if (error.code === "ENOENT") {
|
|
831
|
+
auditEntries = [];
|
|
832
|
+
} else {
|
|
833
|
+
throw error;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
for (const entry of auditEntries) {
|
|
837
|
+
if (!entry.endsWith(".md"))
|
|
838
|
+
continue;
|
|
839
|
+
const filePath = `${auditsPath}/${entry}`;
|
|
840
|
+
let content;
|
|
841
|
+
try {
|
|
842
|
+
content = await fileSystem.readFile(filePath);
|
|
843
|
+
} catch (error) {
|
|
844
|
+
if (error.code === "ENOENT") {
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
throw error;
|
|
848
|
+
}
|
|
849
|
+
const artifact = parseArtifact(filePath, content);
|
|
850
|
+
artifacts.set(filePath, artifact);
|
|
851
|
+
customAudits.push(artifact);
|
|
852
|
+
}
|
|
877
853
|
return {
|
|
878
854
|
context: {
|
|
879
855
|
artifacts,
|
|
880
856
|
byType,
|
|
881
857
|
rootFiles,
|
|
858
|
+
customAudits,
|
|
882
859
|
dustPath,
|
|
883
860
|
fileSystem
|
|
884
861
|
},
|
|
@@ -887,8 +864,7 @@ async function parseArtifacts(fileSystem, dustPath) {
|
|
|
887
864
|
}
|
|
888
865
|
function validateArtifacts(context) {
|
|
889
866
|
const violations = [];
|
|
890
|
-
const { byType, rootFiles,
|
|
891
|
-
const ideasPath = `${dustPath}/ideas`;
|
|
867
|
+
const { byType, rootFiles, customAudits, fileSystem } = context;
|
|
892
868
|
for (const artifact of rootFiles) {
|
|
893
869
|
violations.push(...validateLinks(artifact, fileSystem));
|
|
894
870
|
}
|
|
@@ -918,10 +894,9 @@ function validateArtifacts(context) {
|
|
|
918
894
|
const imperativeViolation = validateImperativeOpeningSentence(artifact);
|
|
919
895
|
if (imperativeViolation)
|
|
920
896
|
violations.push(imperativeViolation);
|
|
921
|
-
const
|
|
922
|
-
if (
|
|
923
|
-
violations.push(
|
|
924
|
-
violations.push(...validateWorkflowTaskBodySection(artifact, ideasPath, fileSystem));
|
|
897
|
+
const taskTypeViolation = validateTaskType(artifact);
|
|
898
|
+
if (taskTypeViolation)
|
|
899
|
+
violations.push(taskTypeViolation);
|
|
925
900
|
}
|
|
926
901
|
const allPrincipleRelationships = [];
|
|
927
902
|
for (const artifact of byType.principles) {
|
|
@@ -931,6 +906,18 @@ function validateArtifacts(context) {
|
|
|
931
906
|
}
|
|
932
907
|
violations.push(...validateBidirectionalLinks(allPrincipleRelationships));
|
|
933
908
|
violations.push(...validateNoCycles(allPrincipleRelationships));
|
|
909
|
+
for (const artifact of customAudits) {
|
|
910
|
+
const filenameViolation = validateFilename(artifact.filePath);
|
|
911
|
+
if (filenameViolation)
|
|
912
|
+
violations.push(filenameViolation);
|
|
913
|
+
const openingSentenceViolation = validateOpeningSentence(artifact);
|
|
914
|
+
if (openingSentenceViolation)
|
|
915
|
+
violations.push(openingSentenceViolation);
|
|
916
|
+
const lengthViolation = validateOpeningSentenceLength(artifact);
|
|
917
|
+
if (lengthViolation)
|
|
918
|
+
violations.push(lengthViolation);
|
|
919
|
+
violations.push(...validateAuditHeadings(artifact));
|
|
920
|
+
}
|
|
934
921
|
return violations;
|
|
935
922
|
}
|
|
936
923
|
|
|
@@ -1194,6 +1181,9 @@ function serializeStandardTask(input) {
|
|
|
1194
1181
|
if (input.principles && input.principles.length > 0) {
|
|
1195
1182
|
sections.push(renderPrinciplesSection(input.principles));
|
|
1196
1183
|
}
|
|
1184
|
+
sections.push(`## Task Type
|
|
1185
|
+
|
|
1186
|
+
implement`);
|
|
1197
1187
|
sections.push(renderBlockedBySection(input.blockedBy ?? []));
|
|
1198
1188
|
sections.push(renderDefinitionOfDoneSection(input.definitionOfDone));
|
|
1199
1189
|
return sections.join(`
|
|
@@ -1210,12 +1200,17 @@ function serializeWorkflowTask(input) {
|
|
|
1210
1200
|
const ideaSection = `## ${sectionHeading}
|
|
1211
1201
|
|
|
1212
1202
|
- [${ideaTitle}](../ideas/${input.ideaSlug}.md)`;
|
|
1203
|
+
const taskType = input.type === "capture-idea" ? "capture" : input.type === "refine-idea" ? "refine" : input.type === "decompose-idea" ? "decompose" : "shelve";
|
|
1213
1204
|
return `# ${title}
|
|
1214
1205
|
|
|
1215
1206
|
${openingSentence}
|
|
1216
1207
|
|
|
1217
1208
|
${ideaSection}
|
|
1218
1209
|
|
|
1210
|
+
## Task Type
|
|
1211
|
+
|
|
1212
|
+
${taskType}
|
|
1213
|
+
|
|
1219
1214
|
## Blocked By
|
|
1220
1215
|
|
|
1221
1216
|
(none)
|
|
@@ -1694,5 +1689,7 @@ export {
|
|
|
1694
1689
|
serializePrinciple,
|
|
1695
1690
|
serializeIdea,
|
|
1696
1691
|
serializeFact,
|
|
1692
|
+
parseArtifactPath,
|
|
1693
|
+
buildPreviews,
|
|
1697
1694
|
buildArtifactPatch
|
|
1698
1695
|
};
|
|
@@ -44,7 +44,7 @@ export declare function generateHelperToken(now?: number): HelperToken;
|
|
|
44
44
|
* @param ttlMs - Time-to-live in milliseconds (defaults to HELPER_TOKEN_TTL_MS)
|
|
45
45
|
* @returns true if the token is valid, false otherwise
|
|
46
46
|
*/
|
|
47
|
-
export declare function isHelperTokenValid(token: string, issued: HelperToken, now
|
|
47
|
+
export declare function isHelperTokenValid(token: string, issued: HelperToken, now: number, ttlMs: number): boolean;
|
|
48
48
|
/**
|
|
49
49
|
* Create a new helper token state object.
|
|
50
50
|
* The state starts with no current token.
|
|
@@ -60,7 +60,7 @@ export declare function createHelperTokenState(): HelperTokenState;
|
|
|
60
60
|
* @param now - Current timestamp in milliseconds (defaults to Date.now())
|
|
61
61
|
* @returns A new HelperTokenState with a fresh token
|
|
62
62
|
*/
|
|
63
|
-
export declare function rotateHelperToken(
|
|
63
|
+
export declare function rotateHelperToken(_state: HelperTokenState, now?: number): HelperTokenState;
|
|
64
64
|
/**
|
|
65
65
|
* Check if the current helper token in state is valid.
|
|
66
66
|
* Returns false if there is no current token.
|
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>;
|