@joshski/dust 0.1.92 → 0.1.93

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.
@@ -40,6 +40,7 @@ export interface ArtifactsRepository {
40
40
  createRefineIdeaTask(options: {
41
41
  ideaSlug: string;
42
42
  description?: string;
43
+ openQuestionResponses?: OpenQuestionResponse[];
43
44
  dustCommand?: string;
44
45
  }): Promise<CreateIdeaTransitionTaskResult>;
45
46
  createDecomposeIdeaTask(options: DecomposeIdeaOptions & {
@@ -45,7 +45,7 @@ export interface DecomposeIdeaOptions {
45
45
  description?: string;
46
46
  openQuestionResponses?: OpenQuestionResponse[];
47
47
  }
48
- export declare function createRefineIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string, dustCommand?: string): Promise<CreateIdeaTransitionTaskResult>;
48
+ export declare function createRefineIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string, openQuestionResponses?: OpenQuestionResponse[], dustCommand?: string): Promise<CreateIdeaTransitionTaskResult>;
49
49
  export declare function decomposeIdea(fileSystem: FileSystem, dustPath: string, options: DecomposeIdeaOptions, dustCommand?: string): Promise<CreateIdeaTransitionTaskResult>;
50
50
  export declare function createShelveIdeaTask(fileSystem: FileSystem, dustPath: string, ideaSlug: string, description?: string, _dustCommand?: string): Promise<CreateIdeaTransitionTaskResult>;
51
51
  export declare function createIdeaTask(fileSystem: FileSystem, dustPath: string, options: {
package/dist/artifacts.js CHANGED
@@ -460,14 +460,17 @@ async function createIdeaTransitionTask(fileSystem, dustPath, workflowType, pref
460
460
  await fileSystem.writeFile(filePath, content);
461
461
  return { filePath };
462
462
  }
463
- async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description, dustCommand) {
463
+ async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description, openQuestionResponses, dustCommand) {
464
464
  const cmd = dustCommand ?? "dust";
465
465
  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.`, [
466
466
  "Idea is thoroughly researched with relevant codebase context",
467
467
  "Open questions are added for any ambiguous or underspecified aspects",
468
468
  "Open questions follow the required heading format and focus on high-value decisions",
469
469
  "Idea file is updated with findings"
470
- ], "Refines Idea", { description });
470
+ ], "Refines Idea", {
471
+ description,
472
+ resolvedQuestions: openQuestionResponses
473
+ });
471
474
  }
472
475
  async function decomposeIdea(fileSystem, dustPath, options, dustCommand) {
473
476
  const cmd = dustCommand ?? "dust";
@@ -632,7 +635,7 @@ function buildArtifactsRepository(fileSystem, dustPath) {
632
635
  return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")).sort();
633
636
  },
634
637
  async createRefineIdeaTask(options) {
635
- return createRefineIdeaTask(fileSystem, dustPath, options.ideaSlug, options.description, options.dustCommand);
638
+ return createRefineIdeaTask(fileSystem, dustPath, options.ideaSlug, options.description, options.openQuestionResponses, options.dustCommand);
636
639
  },
637
640
  async createDecomposeIdeaTask(options) {
638
641
  return decomposeIdea(fileSystem, dustPath, options, options.dustCommand);
package/dist/dust.js CHANGED
@@ -500,7 +500,7 @@ async function loadSettings(cwd, fileSystem) {
500
500
  }
501
501
 
502
502
  // lib/version.ts
503
- var DUST_VERSION = "0.1.92";
503
+ var DUST_VERSION = "0.1.93";
504
504
 
505
505
  // lib/session.ts
506
506
  var DUST_UNATTENDED = "DUST_UNATTENDED";
@@ -2563,6 +2563,25 @@ function selectAgentCapabilities(input) {
2563
2563
  }
2564
2564
  return agents;
2565
2565
  }
2566
+ async function fetchCodexModelsFromApi(apiKey) {
2567
+ try {
2568
+ const response = await fetch("https://api.openai.com/v1/models", {
2569
+ headers: { Authorization: `Bearer ${apiKey}` }
2570
+ });
2571
+ if (!response.ok) {
2572
+ log2(`OpenAI models API returned ${response.status}`);
2573
+ return [];
2574
+ }
2575
+ const body = await response.json();
2576
+ if (!body.data || !Array.isArray(body.data)) {
2577
+ return [];
2578
+ }
2579
+ return body.data.map((m) => m.id).filter((id) => id.includes("codex")).sort();
2580
+ } catch (error) {
2581
+ log2(`OpenAI models API fetch failed: ${error instanceof Error ? error.message : String(error)}`);
2582
+ return [];
2583
+ }
2584
+ }
2566
2585
  async function discoverAgentCapabilities(dependencies) {
2567
2586
  const [claudeVersionProbe, codexVersionProbe] = await Promise.all([
2568
2587
  probeCommand(dependencies.spawn, "claude", ["--version"]),
@@ -2570,10 +2589,18 @@ async function discoverAgentCapabilities(dependencies) {
2570
2589
  ]);
2571
2590
  let codexModelsProbe = null;
2572
2591
  if (codexVersionProbe.success) {
2573
- codexModelsProbe = await probeCommand(dependencies.spawn, "codex", [
2574
- "models",
2575
- "--json"
2576
- ]);
2592
+ const getEnv = dependencies.getEnv ?? ((name) => process.env[name]);
2593
+ const apiKey = getEnv("OPENAI_API_KEY");
2594
+ if (apiKey) {
2595
+ const fetcher = dependencies.fetchCodexModelsFromApi ?? fetchCodexModelsFromApi;
2596
+ const models = await fetcher(apiKey);
2597
+ if (models.length > 0) {
2598
+ codexModelsProbe = {
2599
+ success: true,
2600
+ stdout: JSON.stringify(models)
2601
+ };
2602
+ }
2603
+ }
2577
2604
  }
2578
2605
  return {
2579
2606
  type: "agent-capabilities",
@@ -7840,7 +7867,12 @@ function renderHierarchy(nodes, output, prefix = "") {
7840
7867
  }
7841
7868
  }
7842
7869
  async function list(dependencies) {
7843
- const { arguments: commandArguments, context, fileSystem } = dependencies;
7870
+ const {
7871
+ arguments: commandArguments,
7872
+ context,
7873
+ fileSystem,
7874
+ settings
7875
+ } = dependencies;
7844
7876
  const dustPath = `${context.cwd}/.dust`;
7845
7877
  const colors = getColors();
7846
7878
  if (!fileSystem.exists(dustPath)) {
@@ -7855,6 +7887,7 @@ async function list(dependencies) {
7855
7887
  return { exitCode: 1 };
7856
7888
  }
7857
7889
  const specificTypeRequested = commandArguments.length > 0;
7890
+ const showTaskCreationHint = specificTypeRequested && typesToList.length === 1 && typesToList[0] === "tasks";
7858
7891
  const workflowTasks = typesToList.includes("ideas") && fileSystem.exists(dustPath) ? await findAllWorkflowTasks(fileSystem, dustPath) : null;
7859
7892
  for (const type of typesToList) {
7860
7893
  const dirPath = `${dustPath}/${type}`;
@@ -7939,6 +7972,11 @@ async function list(dependencies) {
7939
7972
  });
7940
7973
  }
7941
7974
  }
7975
+ if (showTaskCreationHint) {
7976
+ context.stdout("➕ Add a New Task");
7977
+ context.stdout("");
7978
+ context.stdout(`Run \`${settings.dustCommand} new task\``);
7979
+ }
7942
7980
  return { exitCode: 0 };
7943
7981
  }
7944
7982
 
@@ -8141,7 +8179,7 @@ function newTaskInstructions(vars) {
8141
8179
  steps.push(" - The goal is a task description with minimal ambiguity at implementation time");
8142
8180
  steps.push("4. Create a new markdown file in `.dust/tasks/` with a descriptive kebab-case name (e.g., `add-user-authentication.md`)");
8143
8181
  steps.push("5. Add a title as the first line using an H1 heading (e.g., `# Add user authentication`)");
8144
- steps.push('6. Write a comprehensive description starting with an imperative opening sentence (e.g., "Add caching to the API layer." not "This task adds caching."). Include technical details and references to relevant files.');
8182
+ steps.push('6. Write a comprehensive description starting with an imperative opening sentence (e.g., "Add caching to the API layer." not "This task adds caching."). The opening sentence must be 150 characters or fewer. Include technical details and references to relevant files.');
8145
8183
  steps.push("7. Add a `## Principles` section with links to relevant principles this task supports (e.g., `- [Principle Name](../principles/principle-name.md)`)");
8146
8184
  steps.push("8. Add a `## Blocked By` section listing any tasks that must complete first, or `(none)` if there are no blockers");
8147
8185
  steps.push("9. Add a `## Definition of Done` section with a checklist of completion criteria using `- [ ]` for each item");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joshski/dust",
3
- "version": "0.1.92",
3
+ "version": "0.1.93",
4
4
  "description": "Flow state for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {