@joshski/dust 0.1.85 → 0.1.86

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.
@@ -8,6 +8,7 @@ import type { AgentSessionEvent, 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';
11
+ import { type RunnerDependencies as CodexRunnerDependencies, run as codexRun } from '../codex/run';
11
12
  import type { SendEventFn } from './events';
12
13
  import { type LogBuffer } from './log-buffer';
13
14
  import type { RepositoryDependencies, RepositoryState } from './repository';
@@ -53,10 +54,20 @@ export interface LoopState {
53
54
  * Create an OutputSink that buffers stdout and logs complete lines.
54
55
  */
55
56
  export declare function createBufferStdoutSink(loopState: LoopState, logBuffer: LogBuffer): OutputSink;
57
+ /**
58
+ * Create a factory function that produces OutputSinks for agent runners.
59
+ * This factory captures loopState and logBuffer, returning a function
60
+ * that can be passed to RunnerDependencies.createStdoutSink.
61
+ */
62
+ export declare function createStdoutSinkFactory(loopState: LoopState, logBuffer: LogBuffer): () => OutputSink;
56
63
  /**
57
64
  * Create a run function that redirects Claude output to a log buffer.
58
65
  */
59
66
  export declare function createBufferRun(run: RepositoryDependencies['run'], bufferSinkDeps: RunnerDependencies): typeof claudeRun;
67
+ /**
68
+ * Create a run function that redirects Codex output to a log buffer.
69
+ */
70
+ export declare function createCodexBufferRun(run: typeof codexRun, codexBufferSinkDeps: CodexRunnerDependencies): typeof claudeRun;
60
71
  /** No-op postEvent for LoopDependencies. */
61
72
  export declare function noOpPostEvent(): Promise<void>;
62
73
  /**
@@ -41,4 +41,40 @@ export declare function buildDockerImage(config: DockerConfig, dependencies: Doc
41
41
  * Check if a Dockerfile exists at .dust/Dockerfile in the repository.
42
42
  */
43
43
  export declare function hasDockerfile(repoPath: string, dependencies: DockerDependencies): boolean;
44
+ type DockerPrepareEvent = {
45
+ type: 'loop.docker_detected';
46
+ imageTag: string;
47
+ } | {
48
+ type: 'loop.docker_building';
49
+ imageTag: string;
50
+ } | {
51
+ type: 'loop.docker_built';
52
+ imageTag: string;
53
+ } | {
54
+ type: 'loop.docker_error';
55
+ error: string;
56
+ };
57
+ interface DockerSpawnConfig {
58
+ imageTag: string;
59
+ repoPath: string;
60
+ homeDir: string;
61
+ hasGitconfig: boolean;
62
+ }
63
+ type PrepareDockerConfigResult = {
64
+ config: DockerSpawnConfig;
65
+ } | {
66
+ error: string;
67
+ } | Record<string, never>;
68
+ /**
69
+ * Prepare Docker configuration for agent execution.
70
+ *
71
+ * Checks for a .dust/Dockerfile, verifies Docker availability, builds the image,
72
+ * and returns the spawn configuration. Emits events throughout the process.
73
+ *
74
+ * Returns:
75
+ * - `{ config: DockerSpawnConfig }` on success
76
+ * - `{ error: string }` on failure (Docker not available or build failed)
77
+ * - `{}` if no Dockerfile exists
78
+ */
79
+ export declare function prepareDockerConfig(repoPath: string, dependencies: DockerDependencies, onEvent: (event: DockerPrepareEvent) => void): Promise<PrepareDockerConfigResult>;
44
80
  export {};
package/dist/dust.js CHANGED
@@ -319,7 +319,7 @@ async function loadSettings(cwd, fileSystem) {
319
319
  }
320
320
 
321
321
  // lib/version.ts
322
- var DUST_VERSION = "0.1.85";
322
+ var DUST_VERSION = "0.1.86";
323
323
 
324
324
  // lib/session.ts
325
325
  var DUST_UNATTENDED = "DUST_UNATTENDED";
@@ -1740,7 +1740,7 @@ async function defaultExchangeCode(code, fetchFn = fetch) {
1740
1740
  return body.token;
1741
1741
  }
1742
1742
  async function authenticate(authDeps) {
1743
- const exchange = authDeps.exchangeCode ?? defaultExchangeCode;
1743
+ const exchange = authDeps.exchangeCode ?? ((code) => defaultExchangeCode(code, authDeps.fetch));
1744
1744
  return new Promise((resolve, reject) => {
1745
1745
  let timer = null;
1746
1746
  let serverHandle = null;
@@ -2807,7 +2807,6 @@ async function removeRepository(path, spawn, context) {
2807
2807
  // lib/bucket/repository-loop.ts
2808
2808
  import { existsSync as fsExistsSync } from "node:fs";
2809
2809
  import os2 from "node:os";
2810
- import path3 from "node:path";
2811
2810
 
2812
2811
  // lib/agent-events.ts
2813
2812
  function rawEventToAgentEvent(rawEvent, provider) {
@@ -2856,7 +2855,6 @@ function formatAgentEvent(event) {
2856
2855
  import { spawn as nodeSpawn3 } from "node:child_process";
2857
2856
  import { existsSync } from "node:fs";
2858
2857
  import os from "node:os";
2859
- import path2 from "node:path";
2860
2858
 
2861
2859
  // lib/docker/docker-agent.ts
2862
2860
  import path from "node:path";
@@ -2914,6 +2912,36 @@ function hasDockerfile(repoPath, dependencies) {
2914
2912
  const dockerfilePath = path.join(repoPath, ".dust", "Dockerfile");
2915
2913
  return dependencies.existsSync(dockerfilePath);
2916
2914
  }
2915
+ async function prepareDockerConfig(repoPath, dependencies, onEvent) {
2916
+ log(`checking for .dust/Dockerfile in ${repoPath}`);
2917
+ if (!hasDockerfile(repoPath, dependencies)) {
2918
+ log("no .dust/Dockerfile found, running without Docker");
2919
+ return {};
2920
+ }
2921
+ const imageTag = generateImageTag(repoPath);
2922
+ log(`Dockerfile found, image tag: ${imageTag}`);
2923
+ onEvent({ type: "loop.docker_detected", imageTag });
2924
+ if (!await isDockerAvailable(dependencies)) {
2925
+ const error = "Docker not available. Install Docker or remove .dust/Dockerfile to run without Docker.";
2926
+ return { error };
2927
+ }
2928
+ onEvent({ type: "loop.docker_building", imageTag });
2929
+ const buildResult = await buildDockerImage({ repoPath, imageTag }, dependencies);
2930
+ if (!buildResult.success) {
2931
+ onEvent({ type: "loop.docker_error", error: buildResult.error });
2932
+ return { error: buildResult.error };
2933
+ }
2934
+ onEvent({ type: "loop.docker_built", imageTag });
2935
+ const homeDir = dependencies.homedir();
2936
+ const config = {
2937
+ imageTag,
2938
+ repoPath,
2939
+ homeDir,
2940
+ hasGitconfig: dependencies.existsSync(path.join(homeDir, ".gitconfig"))
2941
+ };
2942
+ log(`Docker config ready: ${JSON.stringify(config)}`);
2943
+ return { config };
2944
+ }
2917
2945
 
2918
2946
  // lib/artifacts/workflow-tasks.ts
2919
2947
  var IDEA_TRANSITION_PREFIXES = [
@@ -3440,36 +3468,17 @@ async function loopClaude(dependencies, loopDependencies = createDefaultDependen
3440
3468
  homedir: loopDependencies.dockerDeps?.homedir ?? os.homedir,
3441
3469
  existsSync: loopDependencies.dockerDeps?.existsSync ?? existsSync
3442
3470
  };
3443
- log2(`checking for .dust/Dockerfile in ${context.cwd}`);
3444
- if (hasDockerfile(context.cwd, dockerDeps)) {
3445
- const imageTag = generateImageTag(context.cwd);
3446
- log2(`Dockerfile found, image tag: ${imageTag}`);
3447
- onLoopEvent({ type: "loop.docker_detected", imageTag });
3448
- if (!await isDockerAvailable(dockerDeps)) {
3449
- context.stderr("Docker not available. Install Docker or remove .dust/Dockerfile to run without Docker.");
3450
- return { exitCode: 1 };
3451
- }
3452
- onLoopEvent({ type: "loop.docker_building", imageTag });
3453
- const buildResult = await buildDockerImage({ repoPath: context.cwd, imageTag }, dockerDeps);
3454
- if (!buildResult.success) {
3455
- onLoopEvent({ type: "loop.docker_error", error: buildResult.error });
3456
- context.stderr(buildResult.error);
3457
- return { exitCode: 1 };
3458
- }
3459
- onLoopEvent({ type: "loop.docker_built", imageTag });
3460
- const homeDir = os.homedir();
3461
- dockerConfig = {
3462
- imageTag,
3463
- repoPath: context.cwd,
3464
- homeDir,
3465
- hasGitconfig: existsSync(path2.join(homeDir, ".gitconfig"))
3466
- };
3471
+ const dockerResult = await prepareDockerConfig(context.cwd, dockerDeps, onLoopEvent);
3472
+ if ("error" in dockerResult) {
3473
+ context.stderr(dockerResult.error);
3474
+ return { exitCode: 1 };
3475
+ }
3476
+ if ("config" in dockerResult) {
3477
+ dockerConfig = dockerResult.config;
3467
3478
  if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
3468
3479
  context.stderr("Docker mode requires CLAUDE_CODE_OAUTH_TOKEN. Run `claude setup-token` and export the token.");
3469
3480
  return { exitCode: 1 };
3470
3481
  }
3471
- } else {
3472
- log2("no .dust/Dockerfile found, running without Docker");
3473
3482
  }
3474
3483
  log2(`starting loop, maxIterations=${maxIterations}, sessionId=${sessionId}`);
3475
3484
  onLoopEvent({ type: "loop.warning" });
@@ -3546,6 +3555,7 @@ async function* spawnCodex(prompt, options = {}, dependencies = defaultDependenc
3546
3555
  });
3547
3556
  proc.on("error", reject);
3548
3557
  });
3558
+ closePromise.catch(() => {});
3549
3559
  const abortHandler = () => {
3550
3560
  if (!proc.killed) {
3551
3561
  proc.kill();
@@ -3698,9 +3708,15 @@ function createBufferStdoutSink(loopState, logBuffer) {
3698
3708
  }
3699
3709
  };
3700
3710
  }
3711
+ function createStdoutSinkFactory(loopState, logBuffer) {
3712
+ return () => createBufferStdoutSink(loopState, logBuffer);
3713
+ }
3701
3714
  function createBufferRun(run3, bufferSinkDeps) {
3702
3715
  return (prompt, options) => run3(prompt, options, bufferSinkDeps);
3703
3716
  }
3717
+ function createCodexBufferRun(run3, codexBufferSinkDeps) {
3718
+ return (prompt, options) => run3(prompt, options, codexBufferSinkDeps);
3719
+ }
3704
3720
  async function noOpPostEvent() {}
3705
3721
  function createLoopEventHandler(logBuffer) {
3706
3722
  return function onLoopEvent(event) {
@@ -3767,31 +3783,6 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
3767
3783
  sequence: 0,
3768
3784
  agentSessionId: undefined
3769
3785
  };
3770
- const isCodex = repoState.repository.agentProvider === "codex";
3771
- const agentType = isCodex ? "codex" : "claude";
3772
- log3(`${repoName}: agentProvider=${repoState.repository.agentProvider ?? "(unset)"}, using ${agentType}`);
3773
- const createStdoutSink2 = () => createBufferStdoutSink(loopState, repoState.logBuffer);
3774
- let bufferRun;
3775
- if (isCodex) {
3776
- const codexBufferSinkDeps = {
3777
- ...defaultRunnerDependencies2,
3778
- createStdoutSink: createStdoutSink2
3779
- };
3780
- bufferRun = (prompt, options) => run2(prompt, options, codexBufferSinkDeps);
3781
- } else {
3782
- const bufferSinkDeps = {
3783
- ...defaultRunnerDependencies,
3784
- createStdoutSink: createStdoutSink2
3785
- };
3786
- bufferRun = createBufferRun(run3, bufferSinkDeps);
3787
- }
3788
- const loopDeps = {
3789
- spawn,
3790
- run: bufferRun,
3791
- sleep,
3792
- postEvent: noOpPostEvent,
3793
- agentType
3794
- };
3795
3786
  const onLoopEvent = createLoopEventHandler(repoState.logBuffer);
3796
3787
  const onAgentEvent = createAgentEventHandler({
3797
3788
  repoState,
@@ -3807,43 +3798,53 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
3807
3798
  homedir: repoDeps.dockerDeps?.homedir ?? os2.homedir,
3808
3799
  existsSync: repoDeps.dockerDeps?.existsSync ?? fsExistsSync
3809
3800
  };
3810
- log3(`checking for .dust/Dockerfile in ${repoState.path}`);
3811
- if (hasDockerfile(repoState.path, dockerDeps)) {
3812
- const imageTag = generateImageTag(repoState.path);
3813
- log3(`Dockerfile found, image tag: ${imageTag}`);
3814
- onLoopEvent({ type: "loop.docker_detected", imageTag });
3815
- if (!await isDockerAvailable(dockerDeps)) {
3816
- log3("Docker not available");
3817
- appendLogLine(repoState.logBuffer, createLogLine("Docker not available. Install Docker or remove .dust/Dockerfile.", "stderr"));
3818
- } else {
3819
- onLoopEvent({ type: "loop.docker_building", imageTag });
3820
- const buildResult = await buildDockerImage({ repoPath: repoState.path, imageTag }, dockerDeps);
3821
- if (!buildResult.success) {
3822
- onLoopEvent({ type: "loop.docker_error", error: buildResult.error });
3823
- log3(`Docker build failed: ${buildResult.error}`);
3824
- } else {
3825
- onLoopEvent({ type: "loop.docker_built", imageTag });
3826
- const homeDir = dockerDeps.homedir();
3827
- dockerConfig = {
3828
- imageTag,
3829
- repoPath: repoState.path,
3830
- homeDir,
3831
- hasGitconfig: dockerDeps.existsSync(path3.join(homeDir, ".gitconfig"))
3832
- };
3833
- log3(`Docker config ready: ${JSON.stringify(dockerConfig)}`);
3834
- if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
3835
- log3("CLAUDE_CODE_OAUTH_TOKEN is not set, cannot run in Docker mode");
3836
- appendLogLine(repoState.logBuffer, createLogLine("Docker mode requires CLAUDE_CODE_OAUTH_TOKEN. Run `claude setup-token` and export the token.", "stderr"));
3837
- return;
3838
- }
3839
- }
3801
+ const dockerResult = await prepareDockerConfig(repoState.path, dockerDeps, onLoopEvent);
3802
+ if ("error" in dockerResult) {
3803
+ log3(`Docker error: ${dockerResult.error}`);
3804
+ appendLogLine(repoState.logBuffer, createLogLine(dockerResult.error, "stderr"));
3805
+ } else if ("config" in dockerResult) {
3806
+ if (!process.env.CLAUDE_CODE_OAUTH_TOKEN) {
3807
+ log3("CLAUDE_CODE_OAUTH_TOKEN is not set, cannot run in Docker mode");
3808
+ appendLogLine(repoState.logBuffer, createLogLine("Docker mode requires CLAUDE_CODE_OAUTH_TOKEN. Run `claude setup-token` and export the token.", "stderr"));
3809
+ return;
3840
3810
  }
3841
- } else {
3842
- log3("no .dust/Dockerfile found, running without Docker");
3811
+ dockerConfig = dockerResult.config;
3843
3812
  }
3844
3813
  log3(`loop started for ${repoName} at ${repoState.path}`);
3845
3814
  while (!repoState.stopRequested) {
3846
3815
  loopState.agentSessionId = crypto.randomUUID();
3816
+ const isCodex = repoState.repository.agentProvider === "codex";
3817
+ const agentType = isCodex ? "codex" : "claude";
3818
+ log3(`${repoName}: agentProvider=${repoState.repository.agentProvider ?? "(unset)"}, using ${agentType}`);
3819
+ const createStdoutSink2 = createStdoutSinkFactory(loopState, repoState.logBuffer);
3820
+ let bufferRun;
3821
+ if (isCodex) {
3822
+ const codexBufferSinkDeps = {
3823
+ ...defaultRunnerDependencies2,
3824
+ spawnCodex: (prompt, options = {}) => {
3825
+ const spawnDeps = {
3826
+ ...defaultDependencies2,
3827
+ spawn
3828
+ };
3829
+ return defaultRunnerDependencies2.spawnCodex(prompt, options, spawnDeps);
3830
+ },
3831
+ createStdoutSink: createStdoutSink2
3832
+ };
3833
+ bufferRun = createCodexBufferRun(run2, codexBufferSinkDeps);
3834
+ } else {
3835
+ const bufferSinkDeps = {
3836
+ ...defaultRunnerDependencies,
3837
+ createStdoutSink: createStdoutSink2
3838
+ };
3839
+ bufferRun = createBufferRun(run3, bufferSinkDeps);
3840
+ }
3841
+ const loopDeps = {
3842
+ spawn,
3843
+ run: bufferRun,
3844
+ sleep,
3845
+ postEvent: noOpPostEvent,
3846
+ agentType
3847
+ };
3847
3848
  const abortController = new AbortController;
3848
3849
  const cancelCurrentIteration = createCancelHandler(abortController);
3849
3850
  repoState.cancelCurrentIteration = cancelCurrentIteration;
@@ -3990,18 +3991,14 @@ async function handleRepositoryList(repositories, manager, repoDeps, context) {
3990
3991
  }
3991
3992
  }
3992
3993
  for (const [name, repo] of incomingRepos) {
3993
- if (!manager.repositories.has(name)) {
3994
+ const existing = manager.repositories.get(name);
3995
+ if (!existing) {
3994
3996
  await addRepository(repo, manager, repoDeps, context);
3995
- } else {
3996
- const existing = manager.repositories.get(name);
3997
- if (!existing)
3998
- continue;
3999
- if (existing.repository.agentProvider !== repo.agentProvider) {
4000
- const from = existing.repository.agentProvider ?? "(unset)";
4001
- const to = repo.agentProvider ?? "(unset)";
4002
- log4(`${name}: agentProvider changed from ${from} to ${to}`);
4003
- existing.repository.agentProvider = repo.agentProvider;
4004
- }
3997
+ } else if (existing.repository.agentProvider !== repo.agentProvider) {
3998
+ const from = existing.repository.agentProvider ?? "(unset)";
3999
+ const to = repo.agentProvider ?? "(unset)";
4000
+ log4(`${name}: agentProvider changed from ${from} to ${to}`);
4001
+ existing.repository.agentProvider = repo.agentProvider;
4005
4002
  }
4006
4003
  }
4007
4004
  for (const name of manager.repositories.keys()) {
@@ -4114,18 +4111,19 @@ function visibleLength(text) {
4114
4111
  function truncateLine(text, maxWidth) {
4115
4112
  if (maxWidth <= 0)
4116
4113
  return "";
4117
- if (visibleLength(text) <= maxWidth)
4114
+ const textLength = visibleLength(text);
4115
+ if (textLength <= maxWidth)
4118
4116
  return text;
4119
4117
  const ansiRegex = /\x1b\[[0-9;]*m/g;
4118
+ const truncateAt = maxWidth - CHARS.ellipsis.length;
4120
4119
  let visibleCount = 0;
4121
4120
  let result = "";
4122
4121
  let lastIndex = 0;
4123
4122
  for (let match = ansiRegex.exec(text);match !== null; match = ansiRegex.exec(text)) {
4124
4123
  const textBefore = text.slice(lastIndex, match.index);
4125
4124
  for (const char of textBefore) {
4126
- if (visibleCount >= maxWidth - CHARS.ellipsis.length) {
4127
- result += CHARS.ellipsis;
4128
- return result + ANSI.RESET;
4125
+ if (visibleCount >= truncateAt) {
4126
+ return result + CHARS.ellipsis + ANSI.RESET;
4129
4127
  }
4130
4128
  result += char;
4131
4129
  visibleCount++;
@@ -4135,14 +4133,13 @@ function truncateLine(text, maxWidth) {
4135
4133
  }
4136
4134
  const remaining = text.slice(lastIndex);
4137
4135
  for (const char of remaining) {
4138
- if (visibleCount >= maxWidth - CHARS.ellipsis.length) {
4139
- result += CHARS.ellipsis;
4140
- return result + ANSI.RESET;
4136
+ if (visibleCount >= truncateAt) {
4137
+ return result + CHARS.ellipsis + ANSI.RESET;
4141
4138
  }
4142
4139
  result += char;
4143
4140
  visibleCount++;
4144
4141
  }
4145
- return result;
4142
+ return result + ANSI.RESET;
4146
4143
  }
4147
4144
  function createTerminalUIState() {
4148
4145
  return {
@@ -4272,7 +4269,7 @@ function getVisibleLogs(state) {
4272
4269
  const buffer2 = state.logBuffers.get(repoName2);
4273
4270
  if (!buffer2)
4274
4271
  continue;
4275
- const color2 = repoColors.get(repoName2) ?? ANSI.FG_WHITE;
4272
+ const color2 = repoColors.get(repoName2);
4276
4273
  const lines = getLogLines(buffer2);
4277
4274
  for (const line of lines) {
4278
4275
  allLogs.push({ ...line, repository: repoName2, color: color2 });
@@ -4414,27 +4411,27 @@ var log5 = createLogger("dust:cli:commands:bucket");
4414
4411
  var DEFAULT_DUSTBUCKET_WS_URL = "wss://dustbucket.com/agent/connect";
4415
4412
  function createAuthFileSystem(dependencies) {
4416
4413
  return {
4417
- exists: (path4) => {
4414
+ exists: (path2) => {
4418
4415
  try {
4419
- dependencies.accessSync(path4);
4416
+ dependencies.accessSync(path2);
4420
4417
  return true;
4421
4418
  } catch {
4422
4419
  return false;
4423
4420
  }
4424
4421
  },
4425
- isDirectory: (path4) => {
4422
+ isDirectory: (path2) => {
4426
4423
  try {
4427
- return dependencies.statSync(path4).isDirectory();
4424
+ return dependencies.statSync(path2).isDirectory();
4428
4425
  } catch {
4429
4426
  return false;
4430
4427
  }
4431
4428
  },
4432
- getFileCreationTime: (path4) => dependencies.statSync(path4).birthtimeMs,
4433
- readFile: (path4) => dependencies.readFile(path4, "utf8"),
4434
- writeFile: (path4, content) => dependencies.writeFile(path4, content, "utf8"),
4435
- mkdir: (path4, options) => dependencies.mkdir(path4, options).then(() => {}),
4436
- readdir: (path4) => dependencies.readdir(path4),
4437
- chmod: (path4, mode) => dependencies.chmod(path4, mode),
4429
+ getFileCreationTime: (path2) => dependencies.statSync(path2).birthtimeMs,
4430
+ readFile: (path2) => dependencies.readFile(path2, "utf8"),
4431
+ writeFile: (path2, content) => dependencies.writeFile(path2, content, "utf8"),
4432
+ mkdir: (path2, options) => dependencies.mkdir(path2, options).then(() => {}),
4433
+ readdir: (path2) => dependencies.readdir(path2),
4434
+ chmod: (path2, mode) => dependencies.chmod(path2, mode),
4438
4435
  rename: (oldPath, newPath) => dependencies.rename(oldPath, newPath)
4439
4436
  };
4440
4437
  }
@@ -4615,6 +4612,20 @@ function syncTUI(state) {
4615
4612
  }
4616
4613
  }
4617
4614
  }
4615
+ function handleRepositoryListSuccess(state, repos, repoDeps, context, useTUI) {
4616
+ syncTUI(state);
4617
+ for (const repoData of repos) {
4618
+ if (repoData.hasTask) {
4619
+ const repoState = state.repositories.get(repoData.name);
4620
+ if (repoState) {
4621
+ signalTaskAvailable(repoState, state, repoDeps, context, useTUI);
4622
+ }
4623
+ }
4624
+ }
4625
+ }
4626
+ function handleRepositoryListError(state, context, useTUI, error) {
4627
+ logMessage(state, context, useTUI, `Failed to handle repository list: ${error.message}`, "stderr");
4628
+ }
4618
4629
  function logMessage(state, context, useTUI, message, stream = "stdout") {
4619
4630
  if (useTUI) {
4620
4631
  const systemBuffer = state.logBuffers.get("system");
@@ -4752,19 +4763,7 @@ function executeEffects(effects, dependencies) {
4752
4763
  const repoDeps = toRepositoryDependencies(bucketDependencies, fileSystem);
4753
4764
  const repoContext = createTUIContext(state, context, useTUI);
4754
4765
  const repos = effect.repositories;
4755
- handleRepositoryList(repos, state, repoDeps, repoContext).then(() => {
4756
- syncTUI(state);
4757
- for (const repoData of repos) {
4758
- if (repoData.hasTask) {
4759
- const repoState = state.repositories.get(repoData.name);
4760
- if (repoState) {
4761
- signalTaskAvailable(repoState, state, repoDeps, context, useTUI);
4762
- }
4763
- }
4764
- }
4765
- }).catch((error) => {
4766
- logMessage(state, context, useTUI, `Failed to handle repository list: ${error.message}`, "stderr");
4767
- });
4766
+ handleRepositoryList(repos, state, repoDeps, repoContext).then(() => handleRepositoryListSuccess(state, repos, repoDeps, context, useTUI)).catch((error) => handleRepositoryListError(state, context, useTUI, error));
4768
4767
  break;
4769
4768
  }
4770
4769
  case "signalTaskAvailable": {
@@ -5065,16 +5064,16 @@ function createDefaultUploadDependencies() {
5065
5064
  getHomeDir: () => homedir2(),
5066
5065
  fileSystem: authFileSystem
5067
5066
  },
5068
- readFileBytes: async (path4) => {
5069
- const buffer = await Bun.file(path4).arrayBuffer();
5067
+ readFileBytes: async (path2) => {
5068
+ const buffer = await Bun.file(path2).arrayBuffer();
5070
5069
  return new Uint8Array(buffer);
5071
5070
  },
5072
- getFileSize: async (path4) => {
5073
- const file = Bun.file(path4);
5071
+ getFileSize: async (path2) => {
5072
+ const file = Bun.file(path2);
5074
5073
  return file.size;
5075
5074
  },
5076
- fileExists: async (path4) => {
5077
- const file = Bun.file(path4);
5075
+ fileExists: async (path2) => {
5076
+ const file = Bun.file(path2);
5078
5077
  return file.exists();
5079
5078
  },
5080
5079
  uploadFile: async (url, token, fileBytes, contentType, fileName) => {
@@ -5869,12 +5868,12 @@ function validateNoCycles(allPrincipleRelationships) {
5869
5868
  }
5870
5869
  for (const rel of allPrincipleRelationships) {
5871
5870
  const visited = new Set;
5872
- const path4 = [];
5871
+ const path2 = [];
5873
5872
  let current = rel.filePath;
5874
5873
  while (current) {
5875
5874
  if (visited.has(current)) {
5876
- const cycleStart = path4.indexOf(current);
5877
- const cyclePath = path4.slice(cycleStart).concat(current);
5875
+ const cycleStart = path2.indexOf(current);
5876
+ const cyclePath = path2.slice(cycleStart).concat(current);
5878
5877
  violations.push({
5879
5878
  file: rel.filePath,
5880
5879
  message: `Cycle detected in principle hierarchy: ${cyclePath.join(" -> ")}`
@@ -5882,7 +5881,7 @@ function validateNoCycles(allPrincipleRelationships) {
5882
5881
  break;
5883
5882
  }
5884
5883
  visited.add(current);
5885
- path4.push(current);
5884
+ path2.push(current);
5886
5885
  const currentRel = relationshipMap.get(current);
5887
5886
  if (currentRel && currentRel.parentPrinciples.length > 0) {
5888
5887
  current = currentRel.parentPrinciples[0];
@@ -6170,14 +6169,12 @@ async function runValidationCheck(dependencies, emitEvent, clock = Date.now) {
6170
6169
  if (result.exitCode === 0) {
6171
6170
  emitEvent?.({ type: "check-passed", name: "lint", durationMs });
6172
6171
  } else {
6173
- const failedEvent = {
6172
+ emitEvent?.({
6174
6173
  type: "check-failed",
6175
6174
  name: "lint",
6176
- durationMs
6177
- };
6178
- if (output)
6179
- failedEvent.output = output;
6180
- emitEvent?.(failedEvent);
6175
+ durationMs,
6176
+ output
6177
+ });
6181
6178
  }
6182
6179
  return {
6183
6180
  name: "lint",
@@ -6602,7 +6599,7 @@ async function list(dependencies) {
6602
6599
  ideas: collectedItems.map((i) => ({
6603
6600
  path: i.path,
6604
6601
  title: i.title,
6605
- status: i.status ?? "draft"
6602
+ status: i.status
6606
6603
  }))
6607
6604
  });
6608
6605
  } else if (type === "principles") {
@@ -6869,8 +6866,8 @@ function parseGitDiffNameStatus(output) {
6869
6866
  const parts = line.split("\t");
6870
6867
  if (parts.length >= 2) {
6871
6868
  const statusChar = parts[0].charAt(0);
6872
- const path4 = parts.length > 2 ? parts[2] : parts[1];
6873
- changes.push({ status: statusChar, path: path4 });
6869
+ const path2 = parts.length > 2 ? parts[2] : parts[1];
6870
+ changes.push({ status: statusChar, path: path2 });
6874
6871
  }
6875
6872
  }
6876
6873
  return changes;
@@ -6931,12 +6928,12 @@ async function getUncommittedFiles(cwd, gitRunner) {
6931
6928
  `).filter((line) => line.length > 0);
6932
6929
  for (const line of lines) {
6933
6930
  if (line.length > 3) {
6934
- const path4 = line.substring(3);
6935
- const arrowIndex = path4.indexOf(" -> ");
6931
+ const path2 = line.substring(3);
6932
+ const arrowIndex = path2.indexOf(" -> ");
6936
6933
  if (arrowIndex !== -1) {
6937
- files.push(path4.substring(arrowIndex + 4));
6934
+ files.push(path2.substring(arrowIndex + 4));
6938
6935
  } else {
6939
- files.push(path4);
6936
+ files.push(path2);
6940
6937
  }
6941
6938
  }
6942
6939
  }
@@ -7087,24 +7084,24 @@ async function main(options) {
7087
7084
  function createFileSystem(primitives) {
7088
7085
  return {
7089
7086
  exists: primitives.existsSync,
7090
- isDirectory: (path4) => {
7087
+ isDirectory: (path2) => {
7091
7088
  try {
7092
- return primitives.statSync(path4).isDirectory();
7089
+ return primitives.statSync(path2).isDirectory();
7093
7090
  } catch {
7094
7091
  return false;
7095
7092
  }
7096
7093
  },
7097
- readFile: (path4) => primitives.readFile(path4, "utf-8"),
7098
- writeFile: (path4, content, options) => primitives.writeFile(path4, content, {
7094
+ readFile: (path2) => primitives.readFile(path2, "utf-8"),
7095
+ writeFile: (path2, content, options) => primitives.writeFile(path2, content, {
7099
7096
  encoding: "utf-8",
7100
7097
  flag: options?.flag
7101
7098
  }),
7102
- mkdir: async (path4, options) => {
7103
- await primitives.mkdir(path4, options);
7099
+ mkdir: async (path2, options) => {
7100
+ await primitives.mkdir(path2, options);
7104
7101
  },
7105
- getFileCreationTime: (path4) => primitives.statSync(path4).birthtimeMs,
7106
- readdir: (path4) => primitives.readdir(path4),
7107
- chmod: (path4, mode) => primitives.chmod(path4, mode),
7102
+ getFileCreationTime: (path2) => primitives.statSync(path2).birthtimeMs,
7103
+ readdir: (path2) => primitives.readdir(path2),
7104
+ chmod: (path2, mode) => primitives.chmod(path2, mode),
7108
7105
  rename: (oldPath, newPath) => primitives.rename(oldPath, newPath)
7109
7106
  };
7110
7107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joshski/dust",
3
- "version": "0.1.85",
3
+ "version": "0.1.86",
4
4
  "description": "Flow state for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {