@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.
Files changed (49) hide show
  1. package/.dust/principles/{enable-flow-state.md → agentic-flow-state.md} +6 -2
  2. package/.dust/principles/human-ai-collaboration.md +1 -1
  3. package/.dust/principles/maintainable-codebase.md +1 -1
  4. package/dist/agent-events.d.ts +1 -0
  5. package/dist/agents/detection.d.ts +1 -1
  6. package/dist/agents.js +1 -1
  7. package/dist/artifacts/facts.d.ts +2 -2
  8. package/dist/artifacts/ideas.d.ts +2 -2
  9. package/dist/artifacts/index.d.ts +2 -2
  10. package/dist/artifacts/principles.d.ts +2 -2
  11. package/dist/artifacts/tasks.d.ts +2 -2
  12. package/dist/artifacts/workflow-tasks.d.ts +6 -0
  13. package/dist/artifacts.js +142 -25
  14. package/dist/audits/index.d.ts +1 -0
  15. package/dist/audits.js +24 -1
  16. package/dist/bucket/repository-loop.d.ts +4 -4
  17. package/dist/bucket/repository.d.ts +14 -0
  18. package/dist/claude/run.d.ts +3 -9
  19. package/dist/claude/spawn-claude-code.d.ts +1 -1
  20. package/dist/claude/types.d.ts +13 -0
  21. package/dist/cli/commands/focus.d.ts +2 -1
  22. package/dist/cli/shared/agent-shared.d.ts +4 -4
  23. package/dist/cli/types.d.ts +1 -1
  24. package/dist/codex/run.d.ts +3 -9
  25. package/dist/codex/spawn-codex.d.ts +6 -2
  26. package/dist/command-events.d.ts +2 -1
  27. package/dist/config/settings.d.ts +5 -5
  28. package/dist/container/apple-container-runtime.d.ts +12 -0
  29. package/dist/container/docker-runtime.d.ts +21 -0
  30. package/dist/container/runtime.d.ts +71 -0
  31. package/dist/container/select-runtime.d.ts +28 -0
  32. package/dist/core-principles.js +5 -16
  33. package/dist/docker/docker-agent.d.ts +33 -46
  34. package/dist/dust.js +959 -581
  35. package/dist/filesystem/types.d.ts +5 -1
  36. package/dist/lint/validators/audit-validator.d.ts +15 -0
  37. package/dist/lint/validators/content-validator.d.ts +1 -0
  38. package/dist/lint/validators/directory-validator.d.ts +3 -3
  39. package/dist/lint/validators/idea-validator.d.ts +3 -3
  40. package/dist/lint/validators/link-validator.d.ts +2 -2
  41. package/dist/loop/iteration.d.ts +4 -3
  42. package/dist/patch/index.d.ts +13 -0
  43. package/dist/patch.js +106 -109
  44. package/dist/proxy/helper-token.d.ts +2 -2
  45. package/dist/session.d.ts +2 -0
  46. package/dist/validation/validation-pipeline.d.ts +1 -0
  47. package/dist/validation.js +96 -109
  48. package/lib/docker/default.Dockerfile +8 -0
  49. package/package.json +3 -2
@@ -1,14 +1,18 @@
1
- # Enable Flow State
1
+ # Agentic Flow State
2
2
 
3
3
  Flow is the mental state where work becomes effortless - where you're fully immersed, losing track of time, operating at peak performance. Psychologist Mihaly Csikszentmihalyi identified three conditions that create flow: clear goals, immediate feedback, and challenge-skill balance.
4
4
 
5
+ For AI agents, achieving flow state means staying engaged and productive without interruption. Agents enter flow when they have optimal context, comprehensive guard rails, and minimal friction. Context window optimization ensures agents have exactly what they need without cognitive overload. In-session guard rails prevent agents from straying off course or making mistakes that break their momentum.
6
+
5
7
  Dust's design targets these conditions directly:
6
8
 
7
9
  - **Clear goals**: Task files and lightweight planning give you a concrete target. You know exactly what you're building next.
8
10
  - **Immediate feedback**: Fast feedback loops let you see results quickly. Each change confirms you're on track or shows you what to adjust.
9
11
  - **Challenge-skill balance**: Small units of work and agent autonomy keep you in the zone - challenged enough to stay engaged, supported enough to succeed.
12
+ - **Context window efficiency**: Progressive disclosure and artifact summarization ensure agents have the right context without overflow.
13
+ - **Comprehensive guard rails**: Lint rules, type checks, and automated validation catch mistakes before they compound.
10
14
 
11
- Everything dust does serves flow. When developers stay in flow, they produce better work, sustain their energy, and enjoy the process.
15
+ Everything dust does serves flow. When agents stay in flow, they produce better work, sustain their momentum, and complete tasks autonomously.
12
16
 
13
17
  ## Parent Principle
14
18
 
@@ -8,7 +8,7 @@ Today's AI coding tools keep humans in a tight loop with agents. Dust is designe
8
8
 
9
9
  ## Parent Principle
10
10
 
11
- - [Enable Flow State](enable-flow-state.md)
11
+ - [Agentic Flow State](agentic-flow-state.md)
12
12
 
13
13
  ## Sub-Principles
14
14
 
@@ -6,7 +6,7 @@ This principle governs how we develop and maintain dust itself, separate from th
6
6
 
7
7
  ## Parent Principle
8
8
 
9
- - [Enable Flow State](enable-flow-state.md)
9
+ - [Agentic Flow State](agentic-flow-state.md)
10
10
 
11
11
  ## Sub-Principles
12
12
 
@@ -50,6 +50,7 @@ export interface EventMessage {
50
50
  repository: string;
51
51
  repoId?: number;
52
52
  agentSessionId?: string;
53
+ traceId?: string;
53
54
  event: AgentSessionEvent;
54
55
  }
55
56
  /**
@@ -27,4 +27,4 @@ export type AgentType = Agent['type'];
27
27
  * 3. CODEX_HOME or CODEX_CI → Codex
28
28
  * 4. Fallback → unknown Agent
29
29
  */
30
- export declare function detectAgent(env?: NodeJS.ProcessEnv): Agent;
30
+ export declare function detectAgent(env: NodeJS.ProcessEnv): Agent;
package/dist/agents.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // lib/agents/detection.ts
2
- function detectAgent(env = process.env) {
2
+ function detectAgent(env) {
3
3
  if (env.CLAUDECODE) {
4
4
  if (env.CLAUDE_CODE_REMOTE) {
5
5
  return { type: "claude-code-web", name: "Claude Code Web" };
@@ -1,4 +1,4 @@
1
- import type { ReadableFileSystem } from '../filesystem/types';
1
+ import type { FileReader } from '../filesystem/types';
2
2
  export interface Fact {
3
3
  slug: string;
4
4
  title: string;
@@ -7,4 +7,4 @@ export interface Fact {
7
7
  /**
8
8
  * Parses a fact markdown file into a structured Fact object.
9
9
  */
10
- export declare function parseFact(fileSystem: ReadableFileSystem, dustPath: string, slug: string): Promise<Fact>;
10
+ export declare function parseFact(fileSystem: FileReader, dustPath: string, slug: string): Promise<Fact>;
@@ -1,4 +1,4 @@
1
- import type { ReadableFileSystem } from '../filesystem/types';
1
+ import type { FileReader } from '../filesystem/types';
2
2
  export interface IdeaOption {
3
3
  name: string;
4
4
  description: string;
@@ -27,7 +27,7 @@ export declare function parseOpenQuestions(content: string): IdeaOpenQuestion[];
27
27
  /**
28
28
  * Parses an idea markdown file into a structured Idea object.
29
29
  */
30
- export declare function parseIdea(fileSystem: ReadableFileSystem, dustPath: string, slug: string): Promise<Idea>;
30
+ export declare function parseIdea(fileSystem: FileReader, dustPath: string, slug: string): Promise<Idea>;
31
31
  /**
32
32
  * Parses idea markdown into a structured object that can be bound to a UI
33
33
  * and serialized back to markdown.
@@ -5,8 +5,8 @@ import { extractTitle } from '../markdown/markdown-utilities';
5
5
  import { type Principle } from './principles';
6
6
  import { type Task } from './tasks';
7
7
  import { type ParsedArtifact, type ParsedMarkdownLink, type ParsedSection, parseArtifact } from './parsed-artifact';
8
- import { type AllWorkflowTasks, CAPTURE_IDEA_PREFIX, type CreateIdeaTransitionTaskResult, type DecomposeIdeaOptions, findAllWorkflowTasks, type IdeaInProgress, type OpenQuestionResponse, type ParsedCaptureIdeaTask, parseResolvedQuestions, type WorkflowTaskMatch, type WorkflowTaskType } from './workflow-tasks';
9
- export type { AllWorkflowTasks, CreateIdeaTransitionTaskResult, DecomposeIdeaOptions, Fact, Idea, IdeaOpenQuestion, IdeaOption, OpenQuestionResponse, ParsedArtifact, ParsedCaptureIdeaTask, ParsedIdeaContent, ParsedMarkdownLink, ParsedSection, Principle, Task, WorkflowTaskMatch, WorkflowTaskType, };
8
+ import { type AllWorkflowTasks, CAPTURE_IDEA_PREFIX, type CreateIdeaTransitionTaskResult, type DecomposeIdeaOptions, findAllWorkflowTasks, type IdeaInProgress, type OpenQuestionResponse, type ParsedCaptureIdeaTask, parseResolvedQuestions, type TaskType, type WorkflowTaskMatch, type WorkflowTaskType } from './workflow-tasks';
9
+ export type { AllWorkflowTasks, CreateIdeaTransitionTaskResult, DecomposeIdeaOptions, Fact, Idea, IdeaOpenQuestion, IdeaOption, OpenQuestionResponse, ParsedArtifact, ParsedCaptureIdeaTask, ParsedIdeaContent, ParsedMarkdownLink, ParsedSection, Principle, Task, TaskType, WorkflowTaskMatch, WorkflowTaskType, };
10
10
  export interface TaskGraphNode {
11
11
  task: Task;
12
12
  workflowType: WorkflowTaskType | null;
@@ -1,4 +1,4 @@
1
- import type { ReadableFileSystem } from '../filesystem/types';
1
+ import type { FileReader } from '../filesystem/types';
2
2
  export interface Principle {
3
3
  slug: string;
4
4
  title: string;
@@ -9,4 +9,4 @@ export interface Principle {
9
9
  /**
10
10
  * Parses a principle markdown file into a structured Principle object.
11
11
  */
12
- export declare function parsePrinciple(fileSystem: ReadableFileSystem, dustPath: string, slug: string): Promise<Principle>;
12
+ export declare function parsePrinciple(fileSystem: FileReader, dustPath: string, slug: string): Promise<Principle>;
@@ -1,4 +1,4 @@
1
- import type { ReadableFileSystem } from '../filesystem/types';
1
+ import type { FileReader } from '../filesystem/types';
2
2
  export interface Task {
3
3
  slug: string;
4
4
  title: string;
@@ -10,4 +10,4 @@ export interface Task {
10
10
  /**
11
11
  * Parses a task markdown file into a structured Task object.
12
12
  */
13
- export declare function parseTask(fileSystem: ReadableFileSystem, dustPath: string, slug: string): Promise<Task>;
13
+ export declare function parseTask(fileSystem: FileReader, dustPath: string, slug: string): Promise<Task>;
@@ -21,6 +21,12 @@ export interface ParsedCaptureIdeaTask {
21
21
  * 6. Add .md extension
22
22
  */
23
23
  export declare function titleToFilename(title: string): string;
24
+ export type TaskType = 'implement' | 'capture' | 'refine' | 'decompose' | 'shelve';
25
+ /**
26
+ * Extracts and validates the task type from the ## Task Type section.
27
+ * Returns the task type if found and valid, null otherwise.
28
+ */
29
+ export declare function parseTaskType(content: string): TaskType | null;
24
30
  export type WorkflowTaskType = 'refine-idea' | 'decompose-idea' | 'shelve-idea' | 'expedite-idea';
25
31
  export interface WorkflowTaskMatch {
26
32
  type: WorkflowTaskType;
package/dist/artifacts.js CHANGED
@@ -522,6 +522,54 @@ var EXPEDITE_IDEA_PREFIX = "Expedite Idea: ";
522
522
  function titleToFilename(title) {
523
523
  return `${title.toLowerCase().replace(/\./g, "-").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")}.md`;
524
524
  }
525
+ var VALID_TASK_TYPES = [
526
+ "implement",
527
+ "capture",
528
+ "refine",
529
+ "decompose",
530
+ "shelve"
531
+ ];
532
+ function parseTaskType(content) {
533
+ const lines = content.split(`
534
+ `);
535
+ let inSection = false;
536
+ let inCodeFence = false;
537
+ for (const line of lines) {
538
+ if (line.startsWith("```")) {
539
+ inCodeFence = !inCodeFence;
540
+ continue;
541
+ }
542
+ if (inCodeFence)
543
+ continue;
544
+ if (line.startsWith("## ")) {
545
+ inSection = line.trimEnd() === "## Task Type";
546
+ continue;
547
+ }
548
+ if (!inSection)
549
+ continue;
550
+ if (line.startsWith("# "))
551
+ break;
552
+ const trimmed = line.trim();
553
+ if (trimmed && VALID_TASK_TYPES.includes(trimmed)) {
554
+ return trimmed;
555
+ }
556
+ }
557
+ return null;
558
+ }
559
+ function taskTypeToWorkflowType(taskType) {
560
+ switch (taskType) {
561
+ case "refine":
562
+ return "refine-idea";
563
+ case "decompose":
564
+ return "decompose-idea";
565
+ case "shelve":
566
+ return "shelve-idea";
567
+ case "implement":
568
+ return "expedite-idea";
569
+ default:
570
+ return null;
571
+ }
572
+ }
525
573
  var WORKFLOW_HINT_PATHS = {
526
574
  "refine-idea": "config/hints/refine-idea.md",
527
575
  "decompose-idea": "config/hints/decompose-idea.md",
@@ -588,16 +636,32 @@ async function findAllWorkflowTasks(fileSystem, dustPath) {
588
636
  continue;
589
637
  const title = titleMatch[1].trim();
590
638
  const taskSlug = file.replace(/\.md$/, "");
591
- if (title.startsWith(CAPTURE_IDEA_PREFIX)) {
592
- captureIdeaTasks.push({
593
- taskSlug,
594
- ideaTitle: title.slice(CAPTURE_IDEA_PREFIX.length)
595
- });
596
- } else if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
597
- captureIdeaTasks.push({
598
- taskSlug,
599
- ideaTitle: title.slice(EXPEDITE_IDEA_PREFIX.length)
600
- });
639
+ const taskType = parseTaskType(content);
640
+ if (taskType === "capture" || taskType === "implement") {
641
+ let ideaTitle = null;
642
+ if (title.startsWith(CAPTURE_IDEA_PREFIX)) {
643
+ ideaTitle = title.slice(CAPTURE_IDEA_PREFIX.length);
644
+ } else if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
645
+ ideaTitle = title.slice(EXPEDITE_IDEA_PREFIX.length);
646
+ }
647
+ if (ideaTitle) {
648
+ captureIdeaTasks.push({
649
+ taskSlug,
650
+ ideaTitle
651
+ });
652
+ }
653
+ } else if (!taskType) {
654
+ if (title.startsWith(CAPTURE_IDEA_PREFIX)) {
655
+ captureIdeaTasks.push({
656
+ taskSlug,
657
+ ideaTitle: title.slice(CAPTURE_IDEA_PREFIX.length)
658
+ });
659
+ } else if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
660
+ captureIdeaTasks.push({
661
+ taskSlug,
662
+ ideaTitle: title.slice(EXPEDITE_IDEA_PREFIX.length)
663
+ });
664
+ }
601
665
  }
602
666
  for (const { type, heading } of WORKFLOW_SECTION_HEADINGS) {
603
667
  const linkedSlug = extractIdeaSlugFromSection(content, heading);
@@ -625,17 +689,49 @@ async function findWorkflowTaskForIdea(fileSystem, dustPath, ideaSlug) {
625
689
  const files = await fileSystem.readdir(tasksPath);
626
690
  for (const file of files.filter((f) => f.endsWith(".md")).toSorted()) {
627
691
  const content = await fileSystem.readFile(`${tasksPath}/${file}`);
628
- for (const { type, heading } of WORKFLOW_SECTION_HEADINGS) {
629
- const linkedSlug = extractIdeaSlugFromSection(content, heading);
630
- if (linkedSlug === ideaSlug) {
631
- const taskSlug = file.replace(/\.md$/, "");
632
- return {
633
- type,
634
- ideaSlug,
635
- taskSlug,
636
- resolvedQuestions: parseResolvedQuestions(content)
637
- };
638
- }
692
+ const taskSlug = file.replace(/\.md$/, "");
693
+ const match = findWorkflowMatch(content, ideaSlug, taskSlug);
694
+ if (match) {
695
+ return match;
696
+ }
697
+ }
698
+ return null;
699
+ }
700
+ function findWorkflowMatch(content, ideaSlug, taskSlug) {
701
+ const taskType = parseTaskType(content);
702
+ if (taskType) {
703
+ const workflowType = taskTypeToWorkflowType(taskType);
704
+ if (workflowType) {
705
+ const match = findWorkflowMatchByType(content, ideaSlug, taskSlug, workflowType);
706
+ if (match)
707
+ return match;
708
+ }
709
+ }
710
+ for (const { type, heading } of WORKFLOW_SECTION_HEADINGS) {
711
+ const linkedSlug = extractIdeaSlugFromSection(content, heading);
712
+ if (linkedSlug === ideaSlug) {
713
+ return {
714
+ type,
715
+ ideaSlug,
716
+ taskSlug,
717
+ resolvedQuestions: parseResolvedQuestions(content)
718
+ };
719
+ }
720
+ }
721
+ return null;
722
+ }
723
+ function findWorkflowMatchByType(content, ideaSlug, taskSlug, workflowType) {
724
+ for (const { type, heading } of WORKFLOW_SECTION_HEADINGS) {
725
+ if (type !== workflowType)
726
+ continue;
727
+ const linkedSlug = extractIdeaSlugFromSection(content, heading);
728
+ if (linkedSlug === ideaSlug) {
729
+ return {
730
+ type: workflowType,
731
+ ideaSlug,
732
+ taskSlug,
733
+ resolvedQuestions: parseResolvedQuestions(content)
734
+ };
639
735
  }
640
736
  }
641
737
  return null;
@@ -719,7 +815,7 @@ function renderRepositoryHintsSection(repositoryHint) {
719
815
  ${repositoryHint}
720
816
  `;
721
817
  }
722
- function renderTask(title, openingSentence, definitionOfDone, ideaSection, options) {
818
+ function renderTask(title, openingSentence, definitionOfDone, ideaSection, taskType, options) {
723
819
  const descriptionParagraph = options?.description !== undefined ? `
724
820
  ${options.description}
725
821
  ` : "";
@@ -733,7 +829,12 @@ ${renderIdeaSection(ideaSection)}
733
829
  return `# ${title}
734
830
 
735
831
  ${openingSentence}
736
- ${descriptionParagraph}${resolvedSection}${ideaSectionContent}## Blocked By
832
+ ${descriptionParagraph}${resolvedSection}${ideaSectionContent}
833
+ ## Task Type
834
+
835
+ ${taskType}
836
+
837
+ ## Blocked By
737
838
 
738
839
  (none)
739
840
  ${repositoryHintsSection}
@@ -752,7 +853,8 @@ async function createIdeaTransitionTask(fileSystem, dustPath, workflowType, pref
752
853
  const baseOpeningSentence = openingSentenceTemplate(ideaTitle);
753
854
  const hint = await readWorkflowHint(fileSystem, dustPath, workflowType);
754
855
  const ideaSection = { heading: ideaSectionHeading, ideaTitle, ideaSlug };
755
- const content = renderTask(taskTitle, baseOpeningSentence, definitionOfDone, ideaSection, {
856
+ const taskType = workflowType === "refine-idea" ? "refine" : workflowType === "decompose-idea" ? "decompose" : workflowType === "shelve-idea" ? "shelve" : "implement";
857
+ const content = renderTask(taskTitle, baseOpeningSentence, definitionOfDone, ideaSection, taskType, {
756
858
  description: taskOptions?.description,
757
859
  resolvedQuestions: taskOptions?.resolvedQuestions,
758
860
  repositoryHint: hint ?? undefined
@@ -818,6 +920,10 @@ ${baseOpeningSentence2}
818
920
 
819
921
  ${description}
820
922
 
923
+ ## Task Type
924
+
925
+ implement
926
+
821
927
  ## Blocked By
822
928
 
823
929
  (none)
@@ -846,6 +952,10 @@ ${baseOpeningSentence}
846
952
 
847
953
  ${description}
848
954
 
955
+ ## Task Type
956
+
957
+ capture
958
+
849
959
  ## Blocked By
850
960
 
851
961
  (none)
@@ -873,9 +983,16 @@ async function parseCaptureIdeaTask(fileSystem, dustPath, taskSlug) {
873
983
  return null;
874
984
  }
875
985
  const title = titleMatch[1].trim();
986
+ const taskType = parseTaskType(content);
876
987
  let ideaTitle;
877
988
  let expedite;
878
- if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
989
+ if (taskType === "implement") {
990
+ expedite = true;
991
+ ideaTitle = title.startsWith(EXPEDITE_IDEA_PREFIX) ? title.slice(EXPEDITE_IDEA_PREFIX.length) : title;
992
+ } else if (taskType === "capture") {
993
+ expedite = false;
994
+ ideaTitle = title.startsWith(CAPTURE_IDEA_PREFIX) ? title.slice(CAPTURE_IDEA_PREFIX.length) : title;
995
+ } else if (title.startsWith(EXPEDITE_IDEA_PREFIX)) {
879
996
  ideaTitle = title.slice(EXPEDITE_IDEA_PREFIX.length);
880
997
  expedite = true;
881
998
  } else if (title.startsWith(CAPTURE_IDEA_PREFIX)) {
@@ -32,6 +32,7 @@ export interface AuditsRepository {
32
32
  /**
33
33
  * Transforms audit template content for the task file.
34
34
  * Changes the title from "# Original Title" to "# Audit: Original Title"
35
+ * and adds the Task Type section.
35
36
  */
36
37
  export declare function transformAuditContent(content: string): string;
37
38
  /**
package/dist/audits.js CHANGED
@@ -2497,7 +2497,30 @@ function transformAuditContent(content) {
2497
2497
  return content;
2498
2498
  }
2499
2499
  const originalTitle = titleMatch[1];
2500
- return content.replace(/^#\s+.+$/m, `# Audit: ${originalTitle}`);
2500
+ let transformed = content.replace(/^#\s+.+$/m, `# Audit: ${originalTitle}`);
2501
+ const lines = transformed.split(`
2502
+ `);
2503
+ let inCodeFence = false;
2504
+ let blockedByIndex = -1;
2505
+ for (let i = 0;i < lines.length; i++) {
2506
+ const line = lines[i];
2507
+ if (line.startsWith("```")) {
2508
+ inCodeFence = !inCodeFence;
2509
+ continue;
2510
+ }
2511
+ if (inCodeFence)
2512
+ continue;
2513
+ if (line === "## Blocked By") {
2514
+ blockedByIndex = i;
2515
+ break;
2516
+ }
2517
+ }
2518
+ if (blockedByIndex !== -1) {
2519
+ lines.splice(blockedByIndex, 0, "## Task Type", "", "implement", "");
2520
+ transformed = lines.join(`
2521
+ `);
2522
+ }
2523
+ return transformed;
2501
2524
  }
2502
2525
  function injectComment(content, comment) {
2503
2526
  const scopeMatch = content.match(/\n## Scope\n/);
@@ -5,8 +5,8 @@
5
5
  * for a single repository.
6
6
  */
7
7
  import type { EventMessage } from '../agent-events';
8
- import { type run as claudeRun, type RunnerDependencies } from '../claude/run';
9
- import type { OutputSink } from '../claude/types';
8
+ import { type RunnerDependencies } from '../claude/run';
9
+ import type { BoundRunFn, OutputSink } from '../claude/types';
10
10
  import { type LoopEmitFn } from '../loop/events';
11
11
  import type { SendAgentEventFn } from '../loop/wire-events';
12
12
  import { type RunnerDependencies as CodexRunnerDependencies, run as codexRun } from '../codex/run';
@@ -64,11 +64,11 @@ export declare function createStdoutSinkFactory(loopState: LoopState, logBuffer:
64
64
  /**
65
65
  * Create a run function that redirects Claude output to a log buffer.
66
66
  */
67
- export declare function createBufferRun(run: RepositoryDependencies['run'], bufferSinkDeps: RunnerDependencies): typeof claudeRun;
67
+ export declare function createBufferRun(run: RepositoryDependencies['run'], bufferSinkDeps: RunnerDependencies): BoundRunFn;
68
68
  /**
69
69
  * Create a run function that redirects Codex output to a log buffer.
70
70
  */
71
- export declare function createCodexBufferRun(run: typeof codexRun, codexBufferSinkDeps: CodexRunnerDependencies): typeof claudeRun;
71
+ export declare function createCodexBufferRun(run: typeof codexRun, codexBufferSinkDeps: CodexRunnerDependencies): BoundRunFn;
72
72
  /** No-op postEvent for LoopDependencies. */
73
73
  export declare function noOpPostEvent(): Promise<void>;
74
74
  /**
@@ -67,7 +67,21 @@ export interface RepositoryDependencies {
67
67
  revealFamily?: (familyName: string) => void;
68
68
  /** Shell runner for pre-flight commands (install, check) */
69
69
  shellRunner?: import('../cli/process-runner').ShellRunner;
70
+ /** Force Docker mode using bundled default Dockerfile */
71
+ forceDocker?: boolean;
72
+ /** Force Apple Container mode using bundled default Dockerfile */
73
+ forceAppleContainer?: boolean;
70
74
  }
75
+ /**
76
+ * Handle loop completion: transition lifecycle and reset agent status.
77
+ * Extracted as a named function for testability.
78
+ */
79
+ export declare function handleLoopFinished(repoState: RepositoryState): void;
80
+ /**
81
+ * Create a cancel function for a running repository loop.
82
+ * Extracted as a named function for testability.
83
+ */
84
+ export declare function createLoopCancel(repoState: RepositoryState): () => void;
71
85
  /**
72
86
  * Start (or restart) the per-repository loop and keep lifecycle state accurate.
73
87
  */
@@ -1,15 +1,9 @@
1
- import { spawnClaudeCode as defaultSpawnClaudeCode } from './spawn-claude-code';
2
1
  import { createStdoutSink as defaultCreateStdoutSink, streamEvents as defaultStreamEvents } from './streamer';
3
- import type { RawEventCallback, SpawnOptions } from './types';
4
- interface RunOptions {
5
- spawnOptions?: SpawnOptions;
6
- onRawEvent?: RawEventCallback;
7
- }
2
+ import type { RawEvent, RunOptions, SpawnOptions } from './types';
8
3
  export interface RunnerDependencies {
9
- spawnClaudeCode: typeof defaultSpawnClaudeCode;
4
+ spawnClaudeCode: (prompt: string, options: SpawnOptions) => AsyncGenerator<RawEvent>;
10
5
  createStdoutSink: typeof defaultCreateStdoutSink;
11
6
  streamEvents: typeof defaultStreamEvents;
12
7
  }
13
8
  export declare const defaultRunnerDependencies: RunnerDependencies;
14
- export declare function run(prompt: string, options?: SpawnOptions | RunOptions, dependencies?: RunnerDependencies): Promise<void>;
15
- export {};
9
+ export declare function run(prompt: string, options: SpawnOptions | RunOptions, dependencies: RunnerDependencies): Promise<void>;
@@ -21,4 +21,4 @@ export declare const defaultDependencies: EventSourceDependencies;
21
21
  * Build docker run arguments for spawning claude in a container.
22
22
  */
23
23
  export declare function buildDockerRunArguments(docker: DockerSpawnConfig, claudeArguments: string[], env: Record<string, string>): string[];
24
- export declare function spawnClaudeCode(prompt: string, options?: SpawnOptions, dependencies?: EventSourceDependencies): AsyncGenerator<RawEvent>;
24
+ export declare function spawnClaudeCode(prompt: string, options: SpawnOptions, dependencies: EventSourceDependencies): AsyncGenerator<RawEvent>;
@@ -48,6 +48,10 @@ export interface OutputSink {
48
48
  line(text: string): void;
49
49
  }
50
50
  export interface DockerSpawnConfig {
51
+ /** CLI command for running containers (e.g., 'docker', 'container') */
52
+ runCommand?: string;
53
+ /** Hostname or IP the container uses to reach the host */
54
+ hostAddress?: string;
51
55
  /** Docker image tag to use */
52
56
  imageTag: string;
53
57
  /** Path to the repository (used for volume mounts) */
@@ -75,3 +79,12 @@ export interface SpawnOptions {
75
79
  docker?: DockerSpawnConfig;
76
80
  }
77
81
  export type RawEventCallback = (event: RawEvent) => void;
82
+ export interface RunOptions {
83
+ spawnOptions?: SpawnOptions;
84
+ onRawEvent?: RawEventCallback;
85
+ }
86
+ /**
87
+ * A run function with its runner dependencies already bound.
88
+ * Used in LoopDependencies, AgentRunParams, etc.
89
+ */
90
+ export type BoundRunFn = (prompt: string, options: SpawnOptions | RunOptions) => Promise<void>;
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * Usage: dust focus "add login box"
8
8
  */
9
+ import type { TaskType } from '../../artifacts/workflow-tasks';
9
10
  import type { CommandDependencies, CommandResult } from '../types';
10
- export declare function buildImplementationInstructions(bin: string, hooksInstalled: boolean, taskTitle?: string, taskPath?: string, installCommand?: string, skipPreflightSteps?: boolean): string;
11
+ export declare function buildImplementationInstructions(bin: string, hooksInstalled: boolean, taskTitle?: string, taskPath?: string, installCommand?: string, skipPreflightSteps?: boolean, taskType?: TaskType): string;
11
12
  export declare function focus(dependencies: CommandDependencies): Promise<CommandResult>;
@@ -4,7 +4,7 @@
4
4
  * Provides common functionality used across all agent-* command files.
5
5
  */
6
6
  import { type AgentType } from '../../agents/detection';
7
- import type { CommandDependencies, DustSettings, ReadableFileSystem } from '../types';
7
+ import type { CommandDependencies, DustSettings, FileReader } from '../types';
8
8
  /**
9
9
  * Type-safe template variables for agent commands.
10
10
  * Uses real booleans instead of string-encoded booleans.
@@ -23,14 +23,14 @@ export interface TemplateVarsWithInstructions extends TemplateVars {
23
23
  * Loads agent-specific instructions from .dust/config/agents/{agent-type}.md
24
24
  * Returns empty string if file doesn't exist.
25
25
  */
26
- export declare function loadAgentInstructions(cwd: string, fileSystem: ReadableFileSystem, agentType: AgentType): Promise<string>;
27
- export declare function templateVariables(settings: DustSettings, hooksInstalled: boolean, env?: NodeJS.ProcessEnv, options?: {
26
+ export declare function loadAgentInstructions(cwd: string, fileSystem: FileReader, agentType: AgentType): Promise<string>;
27
+ export declare function templateVariables(settings: DustSettings, hooksInstalled: boolean, env: NodeJS.ProcessEnv, options?: {
28
28
  hasIdeaFile?: boolean;
29
29
  }): TemplateVars;
30
30
  /**
31
31
  * Creates template variables with agent-specific instructions loaded.
32
32
  */
33
- export declare function templateVariablesWithInstructions(cwd: string, fileSystem: ReadableFileSystem, settings: DustSettings, hooksInstalled: boolean, env?: NodeJS.ProcessEnv, options?: {
33
+ export declare function templateVariablesWithInstructions(cwd: string, fileSystem: FileReader, settings: DustSettings, hooksInstalled: boolean, env: NodeJS.ProcessEnv, options?: {
34
34
  hasIdeaFile?: boolean;
35
35
  }): Promise<TemplateVarsWithInstructions>;
36
36
  /**
@@ -4,7 +4,7 @@
4
4
  import type { CommandEvent } from '../command-events';
5
5
  import type { RuntimeConfig } from '../env-config';
6
6
  import type { FileSystem, GlobScanner } from '../filesystem/types';
7
- export type { FileSystem, GlobScanner, ReadableFileSystem, } from '../filesystem/types';
7
+ export type { FileReader, FileSystem, GlobScanner, ReadableFileSystem, } from '../filesystem/types';
8
8
  export interface CommandContext {
9
9
  cwd: string;
10
10
  stdout: (message: string) => void;
@@ -1,16 +1,10 @@
1
1
  import { createStdoutSink as defaultCreateStdoutSink } from '../claude/streamer';
2
- import type { RawEventCallback, SpawnOptions } from '../claude/types';
3
- import { spawnCodex as defaultSpawnCodex } from './spawn-codex';
2
+ import type { RawEvent, RunOptions, SpawnOptions } from '../claude/types';
4
3
  import { streamCodexEvents as defaultStreamCodexEvents } from './streamer';
5
- interface RunOptions {
6
- spawnOptions?: SpawnOptions;
7
- onRawEvent?: RawEventCallback;
8
- }
9
4
  export interface RunnerDependencies {
10
- spawnCodex: typeof defaultSpawnCodex;
5
+ spawnCodex: (prompt: string, options: SpawnOptions) => AsyncGenerator<RawEvent>;
11
6
  createStdoutSink: typeof defaultCreateStdoutSink;
12
7
  streamCodexEvents: typeof defaultStreamCodexEvents;
13
8
  }
14
9
  export declare const defaultRunnerDependencies: RunnerDependencies;
15
- export declare function run(prompt: string, options?: SpawnOptions | RunOptions, dependencies?: RunnerDependencies): Promise<void>;
16
- export {};
10
+ export declare function run(prompt: string, options: SpawnOptions | RunOptions, dependencies: RunnerDependencies): Promise<void>;
@@ -1,8 +1,12 @@
1
- import type { RawEvent, SpawnOptions } from '../claude/types';
1
+ import type { DockerSpawnConfig, RawEvent, SpawnOptions } from '../claude/types';
2
2
  import type { CreateReadlineForEvents, SpawnForEvents } from '../process/spawn-contract';
3
3
  export interface EventSourceDependencies {
4
4
  spawn: SpawnForEvents;
5
5
  createInterface: CreateReadlineForEvents;
6
6
  }
7
7
  export declare const defaultDependencies: EventSourceDependencies;
8
- export declare function spawnCodex(prompt: string, options?: SpawnOptions, dependencies?: EventSourceDependencies): AsyncGenerator<RawEvent>;
8
+ /**
9
+ * Build docker run arguments for spawning codex in a container.
10
+ */
11
+ export declare function buildDockerRunArguments(docker: DockerSpawnConfig, codexArguments: string[], env: Record<string, string>): string[];
12
+ export declare function spawnCodex(prompt: string, options: SpawnOptions, dependencies: EventSourceDependencies): AsyncGenerator<RawEvent>;
@@ -53,10 +53,11 @@ export type CommandEvent = {
53
53
  export interface CommandEventMessage {
54
54
  sequence: number;
55
55
  timestamp: string;
56
+ traceId?: string;
56
57
  event: CommandEvent;
57
58
  }
58
59
  /**
59
60
  * Creates an event emitter function that writes command events to a callback.
60
61
  * Each event is wrapped in a CommandEventMessage envelope with sequence and timestamp.
61
62
  */
62
- export declare function createEventEmitter(writeEvent: (message: CommandEventMessage) => void): (event: CommandEvent) => void;
63
+ export declare function createEventEmitter(writeEvent: (message: CommandEventMessage) => void, traceId?: string): (event: CommandEvent) => void;