@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.
- package/dist/bucket/repository-loop.d.ts +11 -0
- package/dist/docker/docker-agent.d.ts +36 -0
- package/dist/dust.js +159 -162
- package/package.json +1 -1
|
@@ -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.
|
|
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
|
-
|
|
3444
|
-
if (
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
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
|
-
|
|
3811
|
-
if (
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
if (!
|
|
3816
|
-
log3("
|
|
3817
|
-
appendLogLine(repoState.logBuffer, createLogLine("Docker
|
|
3818
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3994
|
+
const existing = manager.repositories.get(name);
|
|
3995
|
+
if (!existing) {
|
|
3994
3996
|
await addRepository(repo, manager, repoDeps, context);
|
|
3995
|
-
} else {
|
|
3996
|
-
const
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
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
|
-
|
|
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 >=
|
|
4127
|
-
result
|
|
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 >=
|
|
4139
|
-
result
|
|
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)
|
|
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: (
|
|
4414
|
+
exists: (path2) => {
|
|
4418
4415
|
try {
|
|
4419
|
-
dependencies.accessSync(
|
|
4416
|
+
dependencies.accessSync(path2);
|
|
4420
4417
|
return true;
|
|
4421
4418
|
} catch {
|
|
4422
4419
|
return false;
|
|
4423
4420
|
}
|
|
4424
4421
|
},
|
|
4425
|
-
isDirectory: (
|
|
4422
|
+
isDirectory: (path2) => {
|
|
4426
4423
|
try {
|
|
4427
|
-
return dependencies.statSync(
|
|
4424
|
+
return dependencies.statSync(path2).isDirectory();
|
|
4428
4425
|
} catch {
|
|
4429
4426
|
return false;
|
|
4430
4427
|
}
|
|
4431
4428
|
},
|
|
4432
|
-
getFileCreationTime: (
|
|
4433
|
-
readFile: (
|
|
4434
|
-
writeFile: (
|
|
4435
|
-
mkdir: (
|
|
4436
|
-
readdir: (
|
|
4437
|
-
chmod: (
|
|
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 (
|
|
5069
|
-
const buffer = await Bun.file(
|
|
5067
|
+
readFileBytes: async (path2) => {
|
|
5068
|
+
const buffer = await Bun.file(path2).arrayBuffer();
|
|
5070
5069
|
return new Uint8Array(buffer);
|
|
5071
5070
|
},
|
|
5072
|
-
getFileSize: async (
|
|
5073
|
-
const file = Bun.file(
|
|
5071
|
+
getFileSize: async (path2) => {
|
|
5072
|
+
const file = Bun.file(path2);
|
|
5074
5073
|
return file.size;
|
|
5075
5074
|
},
|
|
5076
|
-
fileExists: async (
|
|
5077
|
-
const file = Bun.file(
|
|
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
|
|
5871
|
+
const path2 = [];
|
|
5873
5872
|
let current = rel.filePath;
|
|
5874
5873
|
while (current) {
|
|
5875
5874
|
if (visited.has(current)) {
|
|
5876
|
-
const cycleStart =
|
|
5877
|
-
const cyclePath =
|
|
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
|
-
|
|
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
|
-
|
|
6172
|
+
emitEvent?.({
|
|
6174
6173
|
type: "check-failed",
|
|
6175
6174
|
name: "lint",
|
|
6176
|
-
durationMs
|
|
6177
|
-
|
|
6178
|
-
|
|
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
|
|
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
|
|
6873
|
-
changes.push({ status: statusChar, path:
|
|
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
|
|
6935
|
-
const arrowIndex =
|
|
6931
|
+
const path2 = line.substring(3);
|
|
6932
|
+
const arrowIndex = path2.indexOf(" -> ");
|
|
6936
6933
|
if (arrowIndex !== -1) {
|
|
6937
|
-
files.push(
|
|
6934
|
+
files.push(path2.substring(arrowIndex + 4));
|
|
6938
6935
|
} else {
|
|
6939
|
-
files.push(
|
|
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: (
|
|
7087
|
+
isDirectory: (path2) => {
|
|
7091
7088
|
try {
|
|
7092
|
-
return primitives.statSync(
|
|
7089
|
+
return primitives.statSync(path2).isDirectory();
|
|
7093
7090
|
} catch {
|
|
7094
7091
|
return false;
|
|
7095
7092
|
}
|
|
7096
7093
|
},
|
|
7097
|
-
readFile: (
|
|
7098
|
-
writeFile: (
|
|
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 (
|
|
7103
|
-
await primitives.mkdir(
|
|
7099
|
+
mkdir: async (path2, options) => {
|
|
7100
|
+
await primitives.mkdir(path2, options);
|
|
7104
7101
|
},
|
|
7105
|
-
getFileCreationTime: (
|
|
7106
|
-
readdir: (
|
|
7107
|
-
chmod: (
|
|
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
|
}
|