@joshski/dust 0.1.87 → 0.1.89

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.
@@ -4,6 +4,7 @@
4
4
  * These types define the transport-agnostic event format used by both
5
5
  * the HTTP (loop) and WebSocket (bucket) paths.
6
6
  */
7
+ import type { CommandEvent } from './command-events';
7
8
  export type AgentSessionEvent = {
8
9
  type: 'agent-session-started';
9
10
  title: string;
@@ -25,6 +26,9 @@ export type AgentSessionEvent = {
25
26
  type: 'agent-event';
26
27
  provider: string;
27
28
  rawEvent: Record<string, unknown>;
29
+ } | {
30
+ type: 'command-event';
31
+ commandEvent: CommandEvent;
28
32
  };
29
33
  export interface EventMessage {
30
34
  sequence: number;
@@ -21,7 +21,7 @@ export interface ParsedCaptureIdeaTask {
21
21
  * 6. Add .md extension
22
22
  */
23
23
  export declare function titleToFilename(title: string): string;
24
- export type WorkflowTaskType = 'refine' | 'decompose-idea' | 'shelve';
24
+ export type WorkflowTaskType = 'refine-idea' | 'decompose-idea' | 'shelve-idea';
25
25
  export interface WorkflowTaskMatch {
26
26
  type: WorkflowTaskType;
27
27
  ideaSlug: string;
package/dist/artifacts.js CHANGED
@@ -277,9 +277,11 @@ function titleToFilename(title) {
277
277
  return `${title.toLowerCase().replace(/\./g, "-").replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")}.md`;
278
278
  }
279
279
  var WORKFLOW_HINT_PATHS = {
280
- refine: "config/workflow-hints/refine.md",
281
- "decompose-idea": "config/workflow-hints/decompose-idea.md",
282
- shelve: "config/workflow-hints/shelve.md"
280
+ "refine-idea": "config/hints/refine-idea.md",
281
+ "decompose-idea": "config/hints/decompose-idea.md",
282
+ "shelve-idea": "config/hints/shelve-idea.md",
283
+ "add-idea": "config/hints/add-idea.md",
284
+ "expedite-idea": "config/hints/expedite-idea.md"
283
285
  };
284
286
  async function readWorkflowHint(fileSystem, dustPath, workflowType) {
285
287
  const hintPath = `${dustPath}/${WORKFLOW_HINT_PATHS[workflowType]}`;
@@ -289,9 +291,9 @@ async function readWorkflowHint(fileSystem, dustPath, workflowType) {
289
291
  return fileSystem.readFile(hintPath);
290
292
  }
291
293
  var WORKFLOW_SECTION_HEADINGS = [
292
- { type: "refine", heading: "Refines Idea" },
294
+ { type: "refine-idea", heading: "Refines Idea" },
293
295
  { type: "decompose-idea", heading: "Decomposes Idea" },
294
- { type: "shelve", heading: "Shelves Idea" }
296
+ { type: "shelve-idea", heading: "Shelves Idea" }
295
297
  ];
296
298
  function extractIdeaSlugFromSection(content, sectionHeading) {
297
299
  const lines = content.split(`
@@ -450,7 +452,7 @@ ${hint}` : baseOpeningSentence;
450
452
  }
451
453
  async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description, dustCommand) {
452
454
  const cmd = dustCommand ?? "dust";
453
- return createIdeaTransitionTask(fileSystem, dustPath, "refine", "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. Run \`${cmd} principles\` for alignment and \`${cmd} 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.`, [
455
+ return createIdeaTransitionTask(fileSystem, dustPath, "refine-idea", "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. Run \`${cmd} principles\` for alignment and \`${cmd} 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.`, [
454
456
  "Idea is thoroughly researched with relevant codebase context",
455
457
  "Open questions are added for any ambiguous or underspecified aspects",
456
458
  "Open questions follow the required heading format and focus on high-value decisions",
@@ -469,7 +471,7 @@ async function decomposeIdea(fileSystem, dustPath, options, dustCommand) {
469
471
  });
470
472
  }
471
473
  async function createShelveIdeaTask(fileSystem, dustPath, ideaSlug, description, _dustCommand) {
472
- return createIdeaTransitionTask(fileSystem, dustPath, "shelve", "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 });
474
+ return createIdeaTransitionTask(fileSystem, dustPath, "shelve-idea", "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 });
473
475
  }
474
476
  async function createIdeaTask(fileSystem, dustPath, options) {
475
477
  const { title, description, expedite, dustCommand } = options;
@@ -484,9 +486,14 @@ async function createIdeaTask(fileSystem, dustPath, options) {
484
486
  const taskTitle2 = `${EXPEDITE_IDEA_PREFIX}${title}`;
485
487
  const filename2 = titleToFilename(taskTitle2);
486
488
  const filePath2 = `${dustPath}/tasks/${filename2}`;
489
+ const baseOpeningSentence2 = `Research this idea briefly. If confident the implementation is straightforward (clear scope, minimal risk, no open questions), implement directly and commit. Otherwise, create one or more narrowly-scoped task files in \`.dust/tasks/\`. Run \`${cmd} principles\` and \`${cmd} facts\` for relevant context.`;
490
+ const hint2 = await readWorkflowHint(fileSystem, dustPath, "expedite-idea");
491
+ const openingSentence2 = hint2 ? `${baseOpeningSentence2}
492
+
493
+ ${hint2}` : baseOpeningSentence2;
487
494
  const content2 = `# ${taskTitle2}
488
495
 
489
- Research this idea briefly. If confident the implementation is straightforward (clear scope, minimal risk, no open questions), implement directly and commit. Otherwise, create one or more narrowly-scoped task files in \`.dust/tasks/\`. Run \`${cmd} principles\` and \`${cmd} facts\` for relevant context.
496
+ ${openingSentence2}
490
497
 
491
498
  ## Idea Description
492
499
 
@@ -508,9 +515,14 @@ ${description}
508
515
  const taskTitle = `${CAPTURE_IDEA_PREFIX}${title}`;
509
516
  const filename = titleToFilename(taskTitle);
510
517
  const filePath = `${dustPath}/tasks/${filename}`;
518
+ const baseOpeningSentence = `Research this idea thoroughly, then create one or more idea files in \`.dust/ideas/\`. Read the codebase for relevant context, flesh out the description, and identify any ambiguity. Where aspects are unclear or could go multiple ways, add open questions to the idea file. 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. Run \`${cmd} principles\` and \`${cmd} facts\` for relevant context.`;
519
+ const hint = await readWorkflowHint(fileSystem, dustPath, "add-idea");
520
+ const openingSentence = hint ? `${baseOpeningSentence}
521
+
522
+ ${hint}` : baseOpeningSentence;
511
523
  const content = `# ${taskTitle}
512
524
 
513
- Research this idea thoroughly, then create one or more idea files in \`.dust/ideas/\`. Read the codebase for relevant context, flesh out the description, and identify any ambiguity. Where aspects are unclear or could go multiple ways, add open questions to the idea file. 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. Run \`${cmd} principles\` and \`${cmd} facts\` for relevant context.
525
+ ${openingSentence}
514
526
 
515
527
  ## Idea Description
516
528
 
@@ -0,0 +1,29 @@
1
+ import type { CommandEventMessage } from '../command-events';
2
+ import type { ToolDefinition } from './server-messages';
3
+ export interface CommandEventsProxy {
4
+ port: number;
5
+ stop: () => Promise<void>;
6
+ }
7
+ export interface ToolExecutionRequest {
8
+ toolName: string;
9
+ arguments: string[];
10
+ repositoryId: string;
11
+ }
12
+ export type ToolExecutionStatus = 'success' | 'tool-not-found' | 'error';
13
+ export interface ToolExecutionResult {
14
+ status: ToolExecutionStatus;
15
+ output?: string;
16
+ error?: string;
17
+ }
18
+ interface CommandEventsProxyHandlers {
19
+ forwardEvent: (event: CommandEventMessage) => void;
20
+ getTools: () => ToolDefinition[];
21
+ forwardToolExecution: (request: ToolExecutionRequest) => Promise<ToolExecutionResult>;
22
+ }
23
+ export declare function isCommandEventMessage(payload: unknown): payload is CommandEventMessage;
24
+ /**
25
+ * Start a local HTTP proxy that accepts command events on POST /events.
26
+ * Accepted payloads are forwarded to the bucket WebSocket channel.
27
+ */
28
+ export declare function startCommandEventsProxy(handlers: CommandEventsProxyHandlers): Promise<CommandEventsProxy>;
29
+ export {};
@@ -4,7 +4,7 @@
4
4
  * Manages the async loop that picks tasks and runs Claude sessions
5
5
  * for a single repository.
6
6
  */
7
- import type { AgentSessionEvent, EventMessage } from '../agent-events';
7
+ import type { EventMessage } from '../agent-events';
8
8
  import { type run as claudeRun, type RunnerDependencies } from '../claude/run';
9
9
  import type { OutputSink } from '../claude/types';
10
10
  import { type LoopEmitFn, type SendAgentEventFn } from '../cli/commands/loop';
@@ -35,7 +35,7 @@ export declare function buildEventMessage(parameters: {
35
35
  sessionId: string;
36
36
  repository: string;
37
37
  repoId?: number;
38
- event: AgentSessionEvent;
38
+ event: EventMessage['event'];
39
39
  agentSessionId?: string;
40
40
  }): EventMessage;
41
41
  /**
@@ -8,6 +8,7 @@ import { spawn as nodeSpawn } from 'node:child_process';
8
8
  import { run as claudeRun } from '../claude/run';
9
9
  import type { CommandDependencies, FileSystem } from '../cli/types';
10
10
  import type { DockerDependencies } from '../docker/docker-agent';
11
+ import type { ToolExecutionRequest, ToolExecutionResult } from './command-events-proxy';
11
12
  import { type BucketEmitFn, type SendEventFn } from './events';
12
13
  import { type LogBuffer } from './log-buffer';
13
14
  import type { ToolDefinition } from './server-messages';
@@ -53,6 +54,8 @@ export interface RepositoryDependencies {
53
54
  dockerDeps?: Partial<DockerDependencies>;
54
55
  /** Function to get current tool definitions */
55
56
  getTools?: () => ToolDefinition[];
57
+ /** Forward tool execution requests to the bucket server */
58
+ forwardToolExecution?: (request: ToolExecutionRequest) => Promise<ToolExecutionResult>;
56
59
  }
57
60
  /**
58
61
  * Start (or restart) the per-repository loop and keep loopPromise state accurate.
@@ -109,6 +109,8 @@ interface IterationOptions {
109
109
  docker?: DockerSpawnConfig;
110
110
  /** Pre-formatted tools section to inject into the prompt */
111
111
  toolsSection?: string;
112
+ /** Port of the command events proxy for this iteration */
113
+ proxyPort?: number;
112
114
  }
113
115
  export declare function runOneIteration(dependencies: CommandDependencies, loopDependencies: LoopDependencies, onLoopEvent: LoopEmitFn, onAgentEvent?: SendAgentEventFn, options?: IterationOptions): Promise<IterationResult>;
114
116
  export declare function parseMaxIterations(commandArguments: string[]): number;
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Command event types for the dust back channel protocol.
3
3
  *
4
- * These types define structured events emitted by dust commands
5
- * to a file descriptor specified by DUST_EVENTS_FD. Events are
6
- * written as newline-delimited JSON using the CommandEventMessage envelope.
4
+ * These types define structured events emitted by dust commands.
5
+ * Events are transported via DUST_PROXY_PORT (HTTP POST /events),
6
+ * using the same envelope.
7
7
  */
8
8
  /**
9
9
  * Events emitted by dust commands.