@joshski/dust 0.1.63 → 0.1.64
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/dust.js +302 -86
- package/package.json +1 -1
package/dist/dust.js
CHANGED
|
@@ -3,14 +3,14 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// lib/cli/run.ts
|
|
6
|
-
import { existsSync, statSync as
|
|
6
|
+
import { existsSync, statSync as statSync3 } from "node:fs";
|
|
7
7
|
import {
|
|
8
|
-
chmod as
|
|
9
|
-
mkdir as
|
|
10
|
-
readdir as
|
|
11
|
-
readFile as
|
|
8
|
+
chmod as chmod3,
|
|
9
|
+
mkdir as mkdir3,
|
|
10
|
+
readdir as readdir3,
|
|
11
|
+
readFile as readFile3,
|
|
12
12
|
rename,
|
|
13
|
-
writeFile as
|
|
13
|
+
writeFile as writeFile3
|
|
14
14
|
} from "node:fs/promises";
|
|
15
15
|
|
|
16
16
|
// lib/git/file-sorter.ts
|
|
@@ -275,7 +275,7 @@ async function loadSettings(cwd, fileSystem) {
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
// lib/version.ts
|
|
278
|
-
var DUST_VERSION = "0.1.
|
|
278
|
+
var DUST_VERSION = "0.1.64";
|
|
279
279
|
|
|
280
280
|
// lib/cli/dedent.ts
|
|
281
281
|
function dedent(strings, ...values) {
|
|
@@ -1034,10 +1034,9 @@ async function audit(dependencies) {
|
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
1036
1036
|
// lib/cli/commands/bucket.ts
|
|
1037
|
-
import { spawn as
|
|
1037
|
+
import { spawn as nodeSpawn4 } from "node:child_process";
|
|
1038
1038
|
import { accessSync, statSync } from "node:fs";
|
|
1039
1039
|
import { chmod, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
1040
|
-
import { createServer as httpCreateServer } from "node:http";
|
|
1041
1040
|
import { homedir } from "node:os";
|
|
1042
1041
|
|
|
1043
1042
|
// lib/bucket/auth.ts
|
|
@@ -1156,6 +1155,40 @@ async function authenticate(authDeps) {
|
|
|
1156
1155
|
});
|
|
1157
1156
|
}
|
|
1158
1157
|
|
|
1158
|
+
// lib/bucket/auth-server.ts
|
|
1159
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
1160
|
+
import { createServer as httpCreateServer } from "node:http";
|
|
1161
|
+
function createLocalServer(handler) {
|
|
1162
|
+
let resolvedPort = 0;
|
|
1163
|
+
const server = httpCreateServer(async (nodeRequest, nodeResponse) => {
|
|
1164
|
+
const url = new URL(nodeRequest.url ?? "/", `http://localhost:${resolvedPort}`);
|
|
1165
|
+
const request = new Request(url.toString(), {
|
|
1166
|
+
method: nodeRequest.method ?? "GET"
|
|
1167
|
+
});
|
|
1168
|
+
const response = handler(request);
|
|
1169
|
+
const body = await response.text();
|
|
1170
|
+
nodeResponse.writeHead(response.status, {
|
|
1171
|
+
"Content-Type": response.headers.get("content-type") ?? "text/plain"
|
|
1172
|
+
});
|
|
1173
|
+
nodeResponse.end(body);
|
|
1174
|
+
});
|
|
1175
|
+
server.listen(0, () => {
|
|
1176
|
+
const addr2 = server.address();
|
|
1177
|
+
if (addr2 && typeof addr2 === "object") {
|
|
1178
|
+
resolvedPort = addr2.port;
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
const addr = server.address();
|
|
1182
|
+
if (addr && typeof addr === "object") {
|
|
1183
|
+
resolvedPort = addr.port;
|
|
1184
|
+
}
|
|
1185
|
+
return { port: resolvedPort, stop: () => server.close() };
|
|
1186
|
+
}
|
|
1187
|
+
function openBrowser(url) {
|
|
1188
|
+
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
1189
|
+
nodeSpawn(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1159
1192
|
// lib/bucket/events.ts
|
|
1160
1193
|
var WS_OPEN = 1;
|
|
1161
1194
|
function formatBucketEvent(event) {
|
|
@@ -1216,10 +1249,10 @@ function getReposDir(env, homeDir) {
|
|
|
1216
1249
|
import { dirname as dirname2 } from "node:path";
|
|
1217
1250
|
|
|
1218
1251
|
// lib/claude/spawn-claude-code.ts
|
|
1219
|
-
import { spawn as
|
|
1252
|
+
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
1220
1253
|
import { createInterface as nodeCreateInterface } from "node:readline";
|
|
1221
1254
|
var defaultDependencies = {
|
|
1222
|
-
spawn:
|
|
1255
|
+
spawn: nodeSpawn2,
|
|
1223
1256
|
createInterface: nodeCreateInterface
|
|
1224
1257
|
};
|
|
1225
1258
|
async function* spawnClaudeCode(prompt, options = {}, dependencies = defaultDependencies) {
|
|
@@ -1827,7 +1860,7 @@ function formatAgentEvent(event) {
|
|
|
1827
1860
|
}
|
|
1828
1861
|
|
|
1829
1862
|
// lib/cli/commands/loop.ts
|
|
1830
|
-
import { spawn as
|
|
1863
|
+
import { spawn as nodeSpawn3 } from "node:child_process";
|
|
1831
1864
|
import os from "node:os";
|
|
1832
1865
|
|
|
1833
1866
|
// lib/artifacts/workflow-tasks.ts
|
|
@@ -2011,19 +2044,21 @@ function formatLoopEvent(event) {
|
|
|
2011
2044
|
return `\uD83C\uDFC1 Reached max iterations (${event.maxIterations}). Exiting.`;
|
|
2012
2045
|
}
|
|
2013
2046
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2047
|
+
function createPostEvent(fetchFn) {
|
|
2048
|
+
return async (url, payload) => {
|
|
2049
|
+
await fetchFn(url, {
|
|
2050
|
+
method: "POST",
|
|
2051
|
+
headers: { "Content-Type": "application/json" },
|
|
2052
|
+
body: JSON.stringify(payload)
|
|
2053
|
+
});
|
|
2054
|
+
};
|
|
2020
2055
|
}
|
|
2021
2056
|
function createDefaultDependencies() {
|
|
2022
2057
|
return {
|
|
2023
|
-
spawn:
|
|
2058
|
+
spawn: nodeSpawn3,
|
|
2024
2059
|
run,
|
|
2025
2060
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
2026
|
-
postEvent:
|
|
2061
|
+
postEvent: createPostEvent(fetch)
|
|
2027
2062
|
};
|
|
2028
2063
|
}
|
|
2029
2064
|
function createWireEventSender(eventsUrl, sessionId, postEvent, onError, getAgentSessionId, repository = "") {
|
|
@@ -2091,7 +2126,20 @@ async function runOneIteration(dependencies, loopDependencies, onLoopEvent, onAg
|
|
|
2091
2126
|
const { context } = dependencies;
|
|
2092
2127
|
const { spawn, run: run2 } = loopDependencies;
|
|
2093
2128
|
const agentName = loopDependencies.agentType === "codex" ? "Codex" : "Claude";
|
|
2094
|
-
const {
|
|
2129
|
+
const {
|
|
2130
|
+
onRawEvent,
|
|
2131
|
+
hooksInstalled = false,
|
|
2132
|
+
signal,
|
|
2133
|
+
logger = log,
|
|
2134
|
+
repositoryId
|
|
2135
|
+
} = options;
|
|
2136
|
+
const baseEnv = {
|
|
2137
|
+
DUST_UNATTENDED: "1",
|
|
2138
|
+
DUST_SKIP_AGENT: "1"
|
|
2139
|
+
};
|
|
2140
|
+
if (repositoryId) {
|
|
2141
|
+
baseEnv.DUST_REPOSITORY_ID = repositoryId;
|
|
2142
|
+
}
|
|
2095
2143
|
log("syncing with remote");
|
|
2096
2144
|
onLoopEvent({ type: "loop.syncing" });
|
|
2097
2145
|
const pullResult = await gitPull(context.cwd, spawn);
|
|
@@ -2126,7 +2174,7 @@ Make sure the repository is in a clean state and synced with remote before finis
|
|
|
2126
2174
|
spawnOptions: {
|
|
2127
2175
|
cwd: context.cwd,
|
|
2128
2176
|
dangerouslySkipPermissions: true,
|
|
2129
|
-
env:
|
|
2177
|
+
env: baseEnv,
|
|
2130
2178
|
signal
|
|
2131
2179
|
},
|
|
2132
2180
|
onRawEvent
|
|
@@ -2182,7 +2230,7 @@ ${instructions}`;
|
|
|
2182
2230
|
spawnOptions: {
|
|
2183
2231
|
cwd: context.cwd,
|
|
2184
2232
|
dangerouslySkipPermissions: true,
|
|
2185
|
-
env:
|
|
2233
|
+
env: baseEnv,
|
|
2186
2234
|
signal
|
|
2187
2235
|
},
|
|
2188
2236
|
onRawEvent
|
|
@@ -2279,6 +2327,45 @@ async function loopClaude(dependencies, loopDependencies = createDefaultDependen
|
|
|
2279
2327
|
// lib/bucket/repository-loop.ts
|
|
2280
2328
|
var log2 = createLogger("dust:bucket:repository-loop");
|
|
2281
2329
|
var FALLBACK_TIMEOUT_MS = 300000;
|
|
2330
|
+
function createLogCallbacks(logBuffer) {
|
|
2331
|
+
return {
|
|
2332
|
+
stdout: (msg) => appendLogLine(logBuffer, createLogLine(msg, "stdout")),
|
|
2333
|
+
stderr: (msg) => appendLogLine(logBuffer, createLogLine(msg, "stderr"))
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
function flushAndLogMultiLine(partialLine, text, logBuffer) {
|
|
2337
|
+
if (partialLine) {
|
|
2338
|
+
appendLogLine(logBuffer, createLogLine(partialLine, "stdout"));
|
|
2339
|
+
}
|
|
2340
|
+
for (const segment of text.split(`
|
|
2341
|
+
`)) {
|
|
2342
|
+
appendLogLine(logBuffer, createLogLine(segment, "stdout"));
|
|
2343
|
+
}
|
|
2344
|
+
return "";
|
|
2345
|
+
}
|
|
2346
|
+
function buildEventMessage(parameters) {
|
|
2347
|
+
const msg = {
|
|
2348
|
+
sequence: parameters.sequence,
|
|
2349
|
+
timestamp: new Date().toISOString(),
|
|
2350
|
+
sessionId: parameters.sessionId,
|
|
2351
|
+
repository: parameters.repository,
|
|
2352
|
+
event: parameters.event
|
|
2353
|
+
};
|
|
2354
|
+
if (parameters.agentSessionId) {
|
|
2355
|
+
msg.agentSessionId = parameters.agentSessionId;
|
|
2356
|
+
}
|
|
2357
|
+
return msg;
|
|
2358
|
+
}
|
|
2359
|
+
function createWakeUpHandler(repoState, resolve) {
|
|
2360
|
+
const handler = () => {
|
|
2361
|
+
if (repoState.wakeUp !== handler) {
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
repoState.wakeUp = undefined;
|
|
2365
|
+
resolve();
|
|
2366
|
+
};
|
|
2367
|
+
return handler;
|
|
2368
|
+
}
|
|
2282
2369
|
function createNoOpGlobScanner() {
|
|
2283
2370
|
return {
|
|
2284
2371
|
scan: async function* () {}
|
|
@@ -2288,12 +2375,13 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2288
2375
|
const { spawn, run: run2, fileSystem, sleep } = repoDeps;
|
|
2289
2376
|
const repoName = repoState.repository.name;
|
|
2290
2377
|
const settings = await loadSettings(repoState.path, fileSystem);
|
|
2378
|
+
const logCallbacks = createLogCallbacks(repoState.logBuffer);
|
|
2291
2379
|
const commandDeps = {
|
|
2292
2380
|
arguments: [],
|
|
2293
2381
|
context: {
|
|
2294
2382
|
cwd: repoState.path,
|
|
2295
|
-
stdout: (msg) =>
|
|
2296
|
-
stderr: (msg) =>
|
|
2383
|
+
stdout: (msg) => logCallbacks.stdout(msg),
|
|
2384
|
+
stderr: (msg) => logCallbacks.stderr(msg)
|
|
2297
2385
|
},
|
|
2298
2386
|
fileSystem,
|
|
2299
2387
|
globScanner: createNoOpGlobScanner(),
|
|
@@ -2313,14 +2401,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2313
2401
|
partialLine = lines[lines.length - 1];
|
|
2314
2402
|
},
|
|
2315
2403
|
line: (text) => {
|
|
2316
|
-
|
|
2317
|
-
appendLogLine(repoState.logBuffer, createLogLine(partialLine, "stdout"));
|
|
2318
|
-
partialLine = "";
|
|
2319
|
-
}
|
|
2320
|
-
for (const segment of text.split(`
|
|
2321
|
-
`)) {
|
|
2322
|
-
appendLogLine(repoState.logBuffer, createLogLine(segment, "stdout"));
|
|
2323
|
-
}
|
|
2404
|
+
partialLine = flushAndLogMultiLine(partialLine, text, repoState.logBuffer);
|
|
2324
2405
|
}
|
|
2325
2406
|
})
|
|
2326
2407
|
};
|
|
@@ -2351,17 +2432,13 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2351
2432
|
}
|
|
2352
2433
|
if (sendEvent && sessionId) {
|
|
2353
2434
|
sequence++;
|
|
2354
|
-
|
|
2435
|
+
sendEvent(buildEventMessage({
|
|
2355
2436
|
sequence,
|
|
2356
|
-
timestamp: new Date().toISOString(),
|
|
2357
2437
|
sessionId,
|
|
2358
2438
|
repository: repoName,
|
|
2359
|
-
event
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
msg.agentSessionId = agentSessionId;
|
|
2363
|
-
}
|
|
2364
|
-
sendEvent(msg);
|
|
2439
|
+
event,
|
|
2440
|
+
agentSessionId
|
|
2441
|
+
}));
|
|
2365
2442
|
}
|
|
2366
2443
|
};
|
|
2367
2444
|
const hooksInstalled = await manageGitHooks(commandDeps);
|
|
@@ -2379,6 +2456,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2379
2456
|
result = await runOneIteration(commandDeps, loopDeps, onLoopEvent, onAgentEvent, {
|
|
2380
2457
|
hooksInstalled,
|
|
2381
2458
|
signal: abortController.signal,
|
|
2459
|
+
repositoryId: repoState.repository.id,
|
|
2382
2460
|
onRawEvent: (rawEvent) => {
|
|
2383
2461
|
onAgentEvent(rawEventToAgentEvent(rawEvent));
|
|
2384
2462
|
}
|
|
@@ -2404,13 +2482,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2404
2482
|
log2(`${repoName}: no tasks available, waiting`);
|
|
2405
2483
|
logLine("Waiting for tasks...");
|
|
2406
2484
|
await new Promise((resolve) => {
|
|
2407
|
-
const wakeUpForThisWait = ()
|
|
2408
|
-
if (repoState.wakeUp !== wakeUpForThisWait) {
|
|
2409
|
-
return;
|
|
2410
|
-
}
|
|
2411
|
-
repoState.wakeUp = undefined;
|
|
2412
|
-
resolve();
|
|
2413
|
-
};
|
|
2485
|
+
const wakeUpForThisWait = createWakeUpHandler(repoState, resolve);
|
|
2414
2486
|
repoState.wakeUp = wakeUpForThisWait;
|
|
2415
2487
|
sleep(FALLBACK_TIMEOUT_MS).then(() => {
|
|
2416
2488
|
if (repoState.wakeUp === wakeUpForThisWait) {
|
|
@@ -2456,6 +2528,9 @@ function parseRepository(data) {
|
|
|
2456
2528
|
if (typeof repositoryData.url === "string") {
|
|
2457
2529
|
repo.url = repositoryData.url;
|
|
2458
2530
|
}
|
|
2531
|
+
if (typeof repositoryData.id === "string") {
|
|
2532
|
+
repo.id = repositoryData.id;
|
|
2533
|
+
}
|
|
2459
2534
|
return repo;
|
|
2460
2535
|
}
|
|
2461
2536
|
}
|
|
@@ -3019,36 +3094,6 @@ function defaultGetTerminalSize() {
|
|
|
3019
3094
|
function defaultWriteStdout(data) {
|
|
3020
3095
|
process.stdout.write(data);
|
|
3021
3096
|
}
|
|
3022
|
-
function defaultCreateServer(handler) {
|
|
3023
|
-
let resolvedPort = 0;
|
|
3024
|
-
const server = httpCreateServer(async (nodeRequest, nodeResponse) => {
|
|
3025
|
-
const url = new URL(nodeRequest.url ?? "/", `http://localhost:${resolvedPort}`);
|
|
3026
|
-
const request = new Request(url.toString(), {
|
|
3027
|
-
method: nodeRequest.method ?? "GET"
|
|
3028
|
-
});
|
|
3029
|
-
const response = handler(request);
|
|
3030
|
-
const body = await response.text();
|
|
3031
|
-
nodeResponse.writeHead(response.status, {
|
|
3032
|
-
"Content-Type": response.headers.get("content-type") ?? "text/plain"
|
|
3033
|
-
});
|
|
3034
|
-
nodeResponse.end(body);
|
|
3035
|
-
});
|
|
3036
|
-
server.listen(0, () => {
|
|
3037
|
-
const addr2 = server.address();
|
|
3038
|
-
if (addr2 && typeof addr2 === "object") {
|
|
3039
|
-
resolvedPort = addr2.port;
|
|
3040
|
-
}
|
|
3041
|
-
});
|
|
3042
|
-
const addr = server.address();
|
|
3043
|
-
if (addr && typeof addr === "object") {
|
|
3044
|
-
resolvedPort = addr.port;
|
|
3045
|
-
}
|
|
3046
|
-
return { port: resolvedPort, stop: () => server.close() };
|
|
3047
|
-
}
|
|
3048
|
-
function defaultOpenBrowser(url) {
|
|
3049
|
-
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
3050
|
-
nodeSpawn3(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
3051
|
-
}
|
|
3052
3097
|
function createAuthFileSystem(dependencies) {
|
|
3053
3098
|
return {
|
|
3054
3099
|
exists: (path) => {
|
|
@@ -3087,7 +3132,7 @@ function createDefaultBucketDependencies() {
|
|
|
3087
3132
|
rename: (oldPath, newPath) => import("node:fs/promises").then((mod) => mod.rename(oldPath, newPath))
|
|
3088
3133
|
});
|
|
3089
3134
|
return {
|
|
3090
|
-
spawn:
|
|
3135
|
+
spawn: nodeSpawn4,
|
|
3091
3136
|
createWebSocket: defaultCreateWebSocket,
|
|
3092
3137
|
setupKeypress: defaultSetupKeypress,
|
|
3093
3138
|
setupSignals: defaultSetupSignals,
|
|
@@ -3098,8 +3143,8 @@ function createDefaultBucketDependencies() {
|
|
|
3098
3143
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
3099
3144
|
getReposDir: () => getReposDir(process.env, homedir()),
|
|
3100
3145
|
auth: {
|
|
3101
|
-
createServer:
|
|
3102
|
-
openBrowser
|
|
3146
|
+
createServer: createLocalServer,
|
|
3147
|
+
openBrowser,
|
|
3103
3148
|
getHomeDir: () => homedir(),
|
|
3104
3149
|
fileSystem: authFileSystem
|
|
3105
3150
|
}
|
|
@@ -3464,6 +3509,176 @@ async function bucket(dependencies, bucketDeps = createDefaultBucketDependencies
|
|
|
3464
3509
|
return { exitCode: 0 };
|
|
3465
3510
|
}
|
|
3466
3511
|
|
|
3512
|
+
// lib/cli/commands/bucket-asset-upload.ts
|
|
3513
|
+
import { accessSync as accessSync2, statSync as statSync2 } from "node:fs";
|
|
3514
|
+
import { chmod as chmod2, mkdir as mkdir2, readdir as readdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3515
|
+
import { homedir as homedir2 } from "node:os";
|
|
3516
|
+
import { extname } from "node:path";
|
|
3517
|
+
var MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
3518
|
+
var ALLOWED_EXTENSIONS = new Set([
|
|
3519
|
+
".png",
|
|
3520
|
+
".jpg",
|
|
3521
|
+
".jpeg",
|
|
3522
|
+
".gif",
|
|
3523
|
+
".webp",
|
|
3524
|
+
".svg",
|
|
3525
|
+
".pdf",
|
|
3526
|
+
".txt",
|
|
3527
|
+
".json",
|
|
3528
|
+
".csv",
|
|
3529
|
+
".md",
|
|
3530
|
+
".html",
|
|
3531
|
+
".xml"
|
|
3532
|
+
]);
|
|
3533
|
+
var MIME_TYPES = {
|
|
3534
|
+
".png": "image/png",
|
|
3535
|
+
".jpg": "image/jpeg",
|
|
3536
|
+
".jpeg": "image/jpeg",
|
|
3537
|
+
".gif": "image/gif",
|
|
3538
|
+
".webp": "image/webp",
|
|
3539
|
+
".svg": "image/svg+xml",
|
|
3540
|
+
".pdf": "application/pdf",
|
|
3541
|
+
".txt": "text/plain",
|
|
3542
|
+
".json": "application/json",
|
|
3543
|
+
".csv": "text/csv",
|
|
3544
|
+
".md": "text/markdown",
|
|
3545
|
+
".html": "text/html",
|
|
3546
|
+
".xml": "application/xml"
|
|
3547
|
+
};
|
|
3548
|
+
function createDefaultUploadDependencies() {
|
|
3549
|
+
const authFileSystemDeps = {
|
|
3550
|
+
accessSync: accessSync2,
|
|
3551
|
+
statSync: statSync2,
|
|
3552
|
+
readFile: readFile2,
|
|
3553
|
+
writeFile: writeFile2,
|
|
3554
|
+
mkdir: mkdir2,
|
|
3555
|
+
readdir: readdir2,
|
|
3556
|
+
chmod: chmod2,
|
|
3557
|
+
rename: (oldPath, newPath) => import("node:fs/promises").then((mod) => mod.rename(oldPath, newPath))
|
|
3558
|
+
};
|
|
3559
|
+
const authFileSystem = createAuthFileSystem(authFileSystemDeps);
|
|
3560
|
+
return {
|
|
3561
|
+
auth: {
|
|
3562
|
+
createServer: createLocalServer,
|
|
3563
|
+
openBrowser,
|
|
3564
|
+
getHomeDir: () => homedir2(),
|
|
3565
|
+
fileSystem: authFileSystem
|
|
3566
|
+
},
|
|
3567
|
+
readFileBytes: async (path) => {
|
|
3568
|
+
const buffer = await Bun.file(path).arrayBuffer();
|
|
3569
|
+
return new Uint8Array(buffer);
|
|
3570
|
+
},
|
|
3571
|
+
getFileSize: async (path) => {
|
|
3572
|
+
const file = Bun.file(path);
|
|
3573
|
+
return file.size;
|
|
3574
|
+
},
|
|
3575
|
+
fileExists: async (path) => {
|
|
3576
|
+
const file = Bun.file(path);
|
|
3577
|
+
return file.exists();
|
|
3578
|
+
},
|
|
3579
|
+
uploadFile: async (url, token, fileBytes, contentType) => {
|
|
3580
|
+
const response = await fetch(url, {
|
|
3581
|
+
method: "POST",
|
|
3582
|
+
headers: {
|
|
3583
|
+
Authorization: `Bearer ${token}`,
|
|
3584
|
+
"Content-Type": contentType
|
|
3585
|
+
},
|
|
3586
|
+
body: new Blob([fileBytes])
|
|
3587
|
+
});
|
|
3588
|
+
if (!response.ok) {
|
|
3589
|
+
const text = await response.text();
|
|
3590
|
+
throw new Error(`Upload failed (${response.status}): ${text || response.statusText}`);
|
|
3591
|
+
}
|
|
3592
|
+
const body = await response.json();
|
|
3593
|
+
if (typeof body.url !== "string") {
|
|
3594
|
+
throw new Error("Server response missing URL");
|
|
3595
|
+
}
|
|
3596
|
+
return { url: body.url };
|
|
3597
|
+
}
|
|
3598
|
+
};
|
|
3599
|
+
}
|
|
3600
|
+
async function resolveToken2(authDeps, context) {
|
|
3601
|
+
const envToken = process.env.DUST_BUCKET_TOKEN;
|
|
3602
|
+
if (envToken) {
|
|
3603
|
+
return envToken;
|
|
3604
|
+
}
|
|
3605
|
+
const stored = await loadStoredToken(authDeps.fileSystem, authDeps.getHomeDir());
|
|
3606
|
+
if (stored) {
|
|
3607
|
+
return stored;
|
|
3608
|
+
}
|
|
3609
|
+
context.stdout("Opening browser to authenticate with dustbucket...");
|
|
3610
|
+
try {
|
|
3611
|
+
const token = await authenticate(authDeps);
|
|
3612
|
+
await storeToken(authDeps.fileSystem, authDeps.getHomeDir(), token);
|
|
3613
|
+
context.stdout("Authenticated successfully");
|
|
3614
|
+
return token;
|
|
3615
|
+
} catch (error) {
|
|
3616
|
+
context.stderr(`Authentication failed: ${error.message}`);
|
|
3617
|
+
return null;
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
function getContentType(filePath) {
|
|
3621
|
+
const ext = extname(filePath).toLowerCase();
|
|
3622
|
+
return MIME_TYPES[ext] || "application/octet-stream";
|
|
3623
|
+
}
|
|
3624
|
+
function isAllowedExtension(filePath) {
|
|
3625
|
+
const ext = extname(filePath).toLowerCase();
|
|
3626
|
+
return ALLOWED_EXTENSIONS.has(ext);
|
|
3627
|
+
}
|
|
3628
|
+
function formatFileSize(bytes) {
|
|
3629
|
+
if (bytes < 1024)
|
|
3630
|
+
return `${bytes} bytes`;
|
|
3631
|
+
if (bytes < 1048576)
|
|
3632
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
3633
|
+
return `${(bytes / 1048576).toFixed(1)} MB`;
|
|
3634
|
+
}
|
|
3635
|
+
async function bucketAssetUpload(dependencies, uploadDeps = createDefaultUploadDependencies(), env = process.env) {
|
|
3636
|
+
const { context } = dependencies;
|
|
3637
|
+
const filePath = dependencies.arguments[0];
|
|
3638
|
+
if (!filePath) {
|
|
3639
|
+
context.stderr("Usage: dust bucket asset upload <file-path>");
|
|
3640
|
+
return { exitCode: 1 };
|
|
3641
|
+
}
|
|
3642
|
+
const repositoryId = env.DUST_REPOSITORY_ID;
|
|
3643
|
+
if (!repositoryId) {
|
|
3644
|
+
context.stderr("Error: DUST_REPOSITORY_ID environment variable is not set.");
|
|
3645
|
+
context.stderr("This command must be run within a repository context (via `dust bucket`).");
|
|
3646
|
+
return { exitCode: 1 };
|
|
3647
|
+
}
|
|
3648
|
+
const exists = await uploadDeps.fileExists(filePath);
|
|
3649
|
+
if (!exists) {
|
|
3650
|
+
context.stderr(`File not found: ${filePath}`);
|
|
3651
|
+
return { exitCode: 1 };
|
|
3652
|
+
}
|
|
3653
|
+
if (!isAllowedExtension(filePath)) {
|
|
3654
|
+
const ext = extname(filePath).toLowerCase() || "(no extension)";
|
|
3655
|
+
const allowed = Array.from(ALLOWED_EXTENSIONS).join(", ");
|
|
3656
|
+
context.stderr(`Unsupported file type: ${ext}`);
|
|
3657
|
+
context.stderr(`Allowed types: ${allowed}`);
|
|
3658
|
+
return { exitCode: 1 };
|
|
3659
|
+
}
|
|
3660
|
+
const fileSize = await uploadDeps.getFileSize(filePath);
|
|
3661
|
+
if (fileSize > MAX_FILE_SIZE_BYTES) {
|
|
3662
|
+
context.stderr(`File too large: ${formatFileSize(fileSize)} (max ${formatFileSize(MAX_FILE_SIZE_BYTES)})`);
|
|
3663
|
+
return { exitCode: 1 };
|
|
3664
|
+
}
|
|
3665
|
+
const token = await resolveToken2(uploadDeps.auth, context);
|
|
3666
|
+
if (!token) {
|
|
3667
|
+
return { exitCode: 1 };
|
|
3668
|
+
}
|
|
3669
|
+
const fileBytes = await uploadDeps.readFileBytes(filePath);
|
|
3670
|
+
const contentType = getContentType(filePath);
|
|
3671
|
+
const uploadUrl = `${getDustbucketHost()}/api/assets?repositoryId=${encodeURIComponent(repositoryId)}`;
|
|
3672
|
+
try {
|
|
3673
|
+
const result = await uploadDeps.uploadFile(uploadUrl, token, fileBytes, contentType);
|
|
3674
|
+
context.stdout(result.url);
|
|
3675
|
+
return { exitCode: 0 };
|
|
3676
|
+
} catch (error) {
|
|
3677
|
+
context.stderr(`Upload failed: ${error.message}`);
|
|
3678
|
+
return { exitCode: 1 };
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3467
3682
|
// lib/cli/process-runner.ts
|
|
3468
3683
|
import { spawn } from "node:child_process";
|
|
3469
3684
|
function createShellRunner(spawnFn) {
|
|
@@ -4710,10 +4925,10 @@ async function list(dependencies) {
|
|
|
4710
4925
|
}
|
|
4711
4926
|
|
|
4712
4927
|
// lib/codex/spawn-codex.ts
|
|
4713
|
-
import { spawn as
|
|
4928
|
+
import { spawn as nodeSpawn5 } from "node:child_process";
|
|
4714
4929
|
import { createInterface as nodeCreateInterface2 } from "node:readline";
|
|
4715
4930
|
var defaultDependencies2 = {
|
|
4716
|
-
spawn:
|
|
4931
|
+
spawn: nodeSpawn5,
|
|
4717
4932
|
createInterface: nodeCreateInterface2
|
|
4718
4933
|
};
|
|
4719
4934
|
async function* spawnCodex(prompt, options = {}, dependencies = defaultDependencies2) {
|
|
@@ -5232,6 +5447,7 @@ var commandRegistry = {
|
|
|
5232
5447
|
agent,
|
|
5233
5448
|
audit,
|
|
5234
5449
|
bucket,
|
|
5450
|
+
"bucket asset upload": bucketAssetUpload,
|
|
5235
5451
|
focus,
|
|
5236
5452
|
"new task": newTask,
|
|
5237
5453
|
"new principle": newPrinciple,
|
|
@@ -5320,10 +5536,10 @@ function createFileSystem(primitives) {
|
|
|
5320
5536
|
rename: (oldPath, newPath) => primitives.rename(oldPath, newPath)
|
|
5321
5537
|
};
|
|
5322
5538
|
}
|
|
5323
|
-
function createGlobScanner(
|
|
5539
|
+
function createGlobScanner(readdir3) {
|
|
5324
5540
|
return {
|
|
5325
5541
|
scan: async function* (dir) {
|
|
5326
|
-
for (const entry of await
|
|
5542
|
+
for (const entry of await readdir3(dir, { recursive: true })) {
|
|
5327
5543
|
if (entry.endsWith(".md"))
|
|
5328
5544
|
yield entry;
|
|
5329
5545
|
}
|
|
@@ -5350,7 +5566,7 @@ async function wireEntry(fsPrimitives, processPrimitives, consolePrimitives) {
|
|
|
5350
5566
|
}
|
|
5351
5567
|
|
|
5352
5568
|
// lib/cli/run.ts
|
|
5353
|
-
await wireEntry({ existsSync, statSync:
|
|
5569
|
+
await wireEntry({ existsSync, statSync: statSync3, readFile: readFile3, writeFile: writeFile3, mkdir: mkdir3, readdir: readdir3, chmod: chmod3, rename }, {
|
|
5354
5570
|
argv: process.argv,
|
|
5355
5571
|
cwd: () => process.cwd(),
|
|
5356
5572
|
exit: (code) => {
|