@joshski/dust 0.1.62 → 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/artifacts/facts.d.ts +1 -1
- package/dist/artifacts/ideas.d.ts +1 -1
- package/dist/artifacts/index.d.ts +1 -1
- package/dist/artifacts/principles.d.ts +1 -1
- package/dist/artifacts/tasks.d.ts +1 -1
- package/dist/artifacts/workflow-tasks.d.ts +1 -1
- package/dist/audits/index.d.ts +36 -0
- package/dist/audits/stock-audits.d.ts +12 -0
- package/dist/audits.js +459 -0
- package/dist/cli/dedent.d.ts +8 -0
- package/dist/cli/types.d.ts +2 -21
- package/dist/dust.js +370 -142
- package/dist/filesystem/types.d.ts +24 -0
- package/package.json +9 -2
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
|
|
@@ -274,6 +274,9 @@ async function loadSettings(cwd, fileSystem) {
|
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
// lib/version.ts
|
|
278
|
+
var DUST_VERSION = "0.1.64";
|
|
279
|
+
|
|
277
280
|
// lib/cli/dedent.ts
|
|
278
281
|
function dedent(strings, ...values) {
|
|
279
282
|
const result = strings.reduce((acc, part, index) => acc + part + (values[index] ?? ""), "");
|
|
@@ -902,6 +905,16 @@ function loadStockAudits() {
|
|
|
902
905
|
});
|
|
903
906
|
}
|
|
904
907
|
|
|
908
|
+
// lib/audits/index.ts
|
|
909
|
+
function transformAuditContent(content) {
|
|
910
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
911
|
+
if (!titleMatch) {
|
|
912
|
+
return content;
|
|
913
|
+
}
|
|
914
|
+
const originalTitle = titleMatch[1];
|
|
915
|
+
return content.replace(/^#\s+.+$/m, `# Audit: ${originalTitle}`);
|
|
916
|
+
}
|
|
917
|
+
|
|
905
918
|
// lib/cli/colors.ts
|
|
906
919
|
var ANSI_COLORS = {
|
|
907
920
|
reset: "\x1B[0m",
|
|
@@ -936,14 +949,6 @@ function getColors() {
|
|
|
936
949
|
}
|
|
937
950
|
|
|
938
951
|
// lib/cli/commands/audit.ts
|
|
939
|
-
function transformAuditContent(content) {
|
|
940
|
-
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
941
|
-
if (!titleMatch) {
|
|
942
|
-
return content;
|
|
943
|
-
}
|
|
944
|
-
const originalTitle = titleMatch[1];
|
|
945
|
-
return content.replace(/^#\s+.+$/m, `# Audit: ${originalTitle}`);
|
|
946
|
-
}
|
|
947
952
|
async function addAudit(auditName, dependencies) {
|
|
948
953
|
const { context, fileSystem, settings } = dependencies;
|
|
949
954
|
const dustPath = `${context.cwd}/.dust`;
|
|
@@ -1029,12 +1034,10 @@ async function audit(dependencies) {
|
|
|
1029
1034
|
}
|
|
1030
1035
|
|
|
1031
1036
|
// lib/cli/commands/bucket.ts
|
|
1032
|
-
import { spawn as
|
|
1037
|
+
import { spawn as nodeSpawn4 } from "node:child_process";
|
|
1033
1038
|
import { accessSync, statSync } from "node:fs";
|
|
1034
1039
|
import { chmod, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
1035
|
-
import { createServer as httpCreateServer } from "node:http";
|
|
1036
1040
|
import { homedir } from "node:os";
|
|
1037
|
-
import { join as join9 } from "node:path";
|
|
1038
1041
|
|
|
1039
1042
|
// lib/bucket/auth.ts
|
|
1040
1043
|
import { join as join4 } from "node:path";
|
|
@@ -1152,6 +1155,40 @@ async function authenticate(authDeps) {
|
|
|
1152
1155
|
});
|
|
1153
1156
|
}
|
|
1154
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
|
+
|
|
1155
1192
|
// lib/bucket/events.ts
|
|
1156
1193
|
var WS_OPEN = 1;
|
|
1157
1194
|
function formatBucketEvent(event) {
|
|
@@ -1202,14 +1239,20 @@ function getLogLines(buffer) {
|
|
|
1202
1239
|
return buffer.lines;
|
|
1203
1240
|
}
|
|
1204
1241
|
|
|
1242
|
+
// lib/bucket/paths.ts
|
|
1243
|
+
import { join as join5 } from "node:path";
|
|
1244
|
+
function getReposDir(env, homeDir) {
|
|
1245
|
+
return env.DUST_REPOS_DIR || join5(homeDir, ".dust", "repos");
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1205
1248
|
// lib/bucket/repository.ts
|
|
1206
|
-
import { dirname as
|
|
1249
|
+
import { dirname as dirname2 } from "node:path";
|
|
1207
1250
|
|
|
1208
1251
|
// lib/claude/spawn-claude-code.ts
|
|
1209
|
-
import { spawn as
|
|
1252
|
+
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
1210
1253
|
import { createInterface as nodeCreateInterface } from "node:readline";
|
|
1211
1254
|
var defaultDependencies = {
|
|
1212
|
-
spawn:
|
|
1255
|
+
spawn: nodeSpawn2,
|
|
1213
1256
|
createInterface: nodeCreateInterface
|
|
1214
1257
|
};
|
|
1215
1258
|
async function* spawnClaudeCode(prompt, options = {}, dependencies = defaultDependencies) {
|
|
@@ -1622,7 +1665,7 @@ async function run(prompt, options = {}, dependencies = defaultRunnerDependencie
|
|
|
1622
1665
|
}
|
|
1623
1666
|
|
|
1624
1667
|
// lib/logging/index.ts
|
|
1625
|
-
import { join as
|
|
1668
|
+
import { join as join6 } from "node:path";
|
|
1626
1669
|
|
|
1627
1670
|
// lib/logging/match.ts
|
|
1628
1671
|
function parsePatterns(debug) {
|
|
@@ -1706,8 +1749,8 @@ function createLoggingService() {
|
|
|
1706
1749
|
return {
|
|
1707
1750
|
enableFileLogs(scope, sinkForTesting) {
|
|
1708
1751
|
const existing = process.env[DUST_LOG_FILE];
|
|
1709
|
-
const logDir = process.env.DUST_LOG_DIR ??
|
|
1710
|
-
const path = existing ??
|
|
1752
|
+
const logDir = process.env.DUST_LOG_DIR ?? join6(process.cwd(), "log");
|
|
1753
|
+
const path = existing ?? join6(logDir, `${scope}.log`);
|
|
1711
1754
|
if (!existing) {
|
|
1712
1755
|
process.env[DUST_LOG_FILE] = path;
|
|
1713
1756
|
}
|
|
@@ -1747,10 +1790,10 @@ var createLogger = defaultService.createLogger.bind(defaultService);
|
|
|
1747
1790
|
var isEnabled = defaultService.isEnabled.bind(defaultService);
|
|
1748
1791
|
|
|
1749
1792
|
// lib/bucket/repository-git.ts
|
|
1750
|
-
import { join as
|
|
1793
|
+
import { join as join7 } from "node:path";
|
|
1751
1794
|
function getRepoPath(repoName, reposDir) {
|
|
1752
1795
|
const safeName = repoName.replace(/[^a-zA-Z0-9-_/]/g, "-");
|
|
1753
|
-
return
|
|
1796
|
+
return join7(reposDir, safeName);
|
|
1754
1797
|
}
|
|
1755
1798
|
async function cloneRepository(repository, targetPath, spawn, context) {
|
|
1756
1799
|
return new Promise((resolve) => {
|
|
@@ -1817,11 +1860,8 @@ function formatAgentEvent(event) {
|
|
|
1817
1860
|
}
|
|
1818
1861
|
|
|
1819
1862
|
// lib/cli/commands/loop.ts
|
|
1820
|
-
import { spawn as
|
|
1821
|
-
import { readFileSync } from "node:fs";
|
|
1863
|
+
import { spawn as nodeSpawn3 } from "node:child_process";
|
|
1822
1864
|
import os from "node:os";
|
|
1823
|
-
import { dirname as dirname2, join as join7 } from "node:path";
|
|
1824
|
-
import { fileURLToPath } from "node:url";
|
|
1825
1865
|
|
|
1826
1866
|
// lib/artifacts/workflow-tasks.ts
|
|
1827
1867
|
var IDEA_TRANSITION_PREFIXES = [
|
|
@@ -1970,26 +2010,12 @@ async function next(dependencies) {
|
|
|
1970
2010
|
}
|
|
1971
2011
|
|
|
1972
2012
|
// lib/cli/commands/loop.ts
|
|
1973
|
-
var __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
1974
|
-
function getDustVersion() {
|
|
1975
|
-
const candidates = [
|
|
1976
|
-
join7(__dirname2, "../../../package.json"),
|
|
1977
|
-
join7(__dirname2, "../package.json")
|
|
1978
|
-
];
|
|
1979
|
-
for (const candidate of candidates) {
|
|
1980
|
-
try {
|
|
1981
|
-
const packageJson = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
1982
|
-
return packageJson.version ?? "unknown";
|
|
1983
|
-
} catch {}
|
|
1984
|
-
}
|
|
1985
|
-
return "unknown";
|
|
1986
|
-
}
|
|
1987
2013
|
function getEnvironmentContext(cwd) {
|
|
1988
2014
|
return {
|
|
1989
2015
|
machineName: os.hostname(),
|
|
1990
2016
|
cwd,
|
|
1991
2017
|
platform: `${os.platform()} ${os.release()}`,
|
|
1992
|
-
dustVersion:
|
|
2018
|
+
dustVersion: DUST_VERSION,
|
|
1993
2019
|
runtimeVersion: process.version
|
|
1994
2020
|
};
|
|
1995
2021
|
}
|
|
@@ -2018,19 +2044,21 @@ function formatLoopEvent(event) {
|
|
|
2018
2044
|
return `\uD83C\uDFC1 Reached max iterations (${event.maxIterations}). Exiting.`;
|
|
2019
2045
|
}
|
|
2020
2046
|
}
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
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
|
+
};
|
|
2027
2055
|
}
|
|
2028
2056
|
function createDefaultDependencies() {
|
|
2029
2057
|
return {
|
|
2030
|
-
spawn:
|
|
2058
|
+
spawn: nodeSpawn3,
|
|
2031
2059
|
run,
|
|
2032
2060
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
2033
|
-
postEvent:
|
|
2061
|
+
postEvent: createPostEvent(fetch)
|
|
2034
2062
|
};
|
|
2035
2063
|
}
|
|
2036
2064
|
function createWireEventSender(eventsUrl, sessionId, postEvent, onError, getAgentSessionId, repository = "") {
|
|
@@ -2098,7 +2126,20 @@ async function runOneIteration(dependencies, loopDependencies, onLoopEvent, onAg
|
|
|
2098
2126
|
const { context } = dependencies;
|
|
2099
2127
|
const { spawn, run: run2 } = loopDependencies;
|
|
2100
2128
|
const agentName = loopDependencies.agentType === "codex" ? "Codex" : "Claude";
|
|
2101
|
-
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
|
+
}
|
|
2102
2143
|
log("syncing with remote");
|
|
2103
2144
|
onLoopEvent({ type: "loop.syncing" });
|
|
2104
2145
|
const pullResult = await gitPull(context.cwd, spawn);
|
|
@@ -2133,7 +2174,7 @@ Make sure the repository is in a clean state and synced with remote before finis
|
|
|
2133
2174
|
spawnOptions: {
|
|
2134
2175
|
cwd: context.cwd,
|
|
2135
2176
|
dangerouslySkipPermissions: true,
|
|
2136
|
-
env:
|
|
2177
|
+
env: baseEnv,
|
|
2137
2178
|
signal
|
|
2138
2179
|
},
|
|
2139
2180
|
onRawEvent
|
|
@@ -2189,7 +2230,7 @@ ${instructions}`;
|
|
|
2189
2230
|
spawnOptions: {
|
|
2190
2231
|
cwd: context.cwd,
|
|
2191
2232
|
dangerouslySkipPermissions: true,
|
|
2192
|
-
env:
|
|
2233
|
+
env: baseEnv,
|
|
2193
2234
|
signal
|
|
2194
2235
|
},
|
|
2195
2236
|
onRawEvent
|
|
@@ -2199,7 +2240,7 @@ ${instructions}`;
|
|
|
2199
2240
|
return "ran_claude";
|
|
2200
2241
|
} catch (error) {
|
|
2201
2242
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2202
|
-
|
|
2243
|
+
logger(`${agentName} error on task ${task.title ?? task.path}: ${errorMessage}`);
|
|
2203
2244
|
context.stderr(`${agentName} exited with error: ${errorMessage}`);
|
|
2204
2245
|
onAgentEvent?.({
|
|
2205
2246
|
type: "agent-session-ended",
|
|
@@ -2286,6 +2327,45 @@ async function loopClaude(dependencies, loopDependencies = createDefaultDependen
|
|
|
2286
2327
|
// lib/bucket/repository-loop.ts
|
|
2287
2328
|
var log2 = createLogger("dust:bucket:repository-loop");
|
|
2288
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
|
+
}
|
|
2289
2369
|
function createNoOpGlobScanner() {
|
|
2290
2370
|
return {
|
|
2291
2371
|
scan: async function* () {}
|
|
@@ -2295,12 +2375,13 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2295
2375
|
const { spawn, run: run2, fileSystem, sleep } = repoDeps;
|
|
2296
2376
|
const repoName = repoState.repository.name;
|
|
2297
2377
|
const settings = await loadSettings(repoState.path, fileSystem);
|
|
2378
|
+
const logCallbacks = createLogCallbacks(repoState.logBuffer);
|
|
2298
2379
|
const commandDeps = {
|
|
2299
2380
|
arguments: [],
|
|
2300
2381
|
context: {
|
|
2301
2382
|
cwd: repoState.path,
|
|
2302
|
-
stdout: (msg) =>
|
|
2303
|
-
stderr: (msg) =>
|
|
2383
|
+
stdout: (msg) => logCallbacks.stdout(msg),
|
|
2384
|
+
stderr: (msg) => logCallbacks.stderr(msg)
|
|
2304
2385
|
},
|
|
2305
2386
|
fileSystem,
|
|
2306
2387
|
globScanner: createNoOpGlobScanner(),
|
|
@@ -2320,14 +2401,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2320
2401
|
partialLine = lines[lines.length - 1];
|
|
2321
2402
|
},
|
|
2322
2403
|
line: (text) => {
|
|
2323
|
-
|
|
2324
|
-
appendLogLine(repoState.logBuffer, createLogLine(partialLine, "stdout"));
|
|
2325
|
-
partialLine = "";
|
|
2326
|
-
}
|
|
2327
|
-
for (const segment of text.split(`
|
|
2328
|
-
`)) {
|
|
2329
|
-
appendLogLine(repoState.logBuffer, createLogLine(segment, "stdout"));
|
|
2330
|
-
}
|
|
2404
|
+
partialLine = flushAndLogMultiLine(partialLine, text, repoState.logBuffer);
|
|
2331
2405
|
}
|
|
2332
2406
|
})
|
|
2333
2407
|
};
|
|
@@ -2358,17 +2432,13 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2358
2432
|
}
|
|
2359
2433
|
if (sendEvent && sessionId) {
|
|
2360
2434
|
sequence++;
|
|
2361
|
-
|
|
2435
|
+
sendEvent(buildEventMessage({
|
|
2362
2436
|
sequence,
|
|
2363
|
-
timestamp: new Date().toISOString(),
|
|
2364
2437
|
sessionId,
|
|
2365
2438
|
repository: repoName,
|
|
2366
|
-
event
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
msg.agentSessionId = agentSessionId;
|
|
2370
|
-
}
|
|
2371
|
-
sendEvent(msg);
|
|
2439
|
+
event,
|
|
2440
|
+
agentSessionId
|
|
2441
|
+
}));
|
|
2372
2442
|
}
|
|
2373
2443
|
};
|
|
2374
2444
|
const hooksInstalled = await manageGitHooks(commandDeps);
|
|
@@ -2386,6 +2456,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2386
2456
|
result = await runOneIteration(commandDeps, loopDeps, onLoopEvent, onAgentEvent, {
|
|
2387
2457
|
hooksInstalled,
|
|
2388
2458
|
signal: abortController.signal,
|
|
2459
|
+
repositoryId: repoState.repository.id,
|
|
2389
2460
|
onRawEvent: (rawEvent) => {
|
|
2390
2461
|
onAgentEvent(rawEventToAgentEvent(rawEvent));
|
|
2391
2462
|
}
|
|
@@ -2411,13 +2482,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2411
2482
|
log2(`${repoName}: no tasks available, waiting`);
|
|
2412
2483
|
logLine("Waiting for tasks...");
|
|
2413
2484
|
await new Promise((resolve) => {
|
|
2414
|
-
const wakeUpForThisWait = ()
|
|
2415
|
-
if (repoState.wakeUp !== wakeUpForThisWait) {
|
|
2416
|
-
return;
|
|
2417
|
-
}
|
|
2418
|
-
repoState.wakeUp = undefined;
|
|
2419
|
-
resolve();
|
|
2420
|
-
};
|
|
2485
|
+
const wakeUpForThisWait = createWakeUpHandler(repoState, resolve);
|
|
2421
2486
|
repoState.wakeUp = wakeUpForThisWait;
|
|
2422
2487
|
sleep(FALLBACK_TIMEOUT_MS).then(() => {
|
|
2423
2488
|
if (repoState.wakeUp === wakeUpForThisWait) {
|
|
@@ -2463,6 +2528,9 @@ function parseRepository(data) {
|
|
|
2463
2528
|
if (typeof repositoryData.url === "string") {
|
|
2464
2529
|
repo.url = repositoryData.url;
|
|
2465
2530
|
}
|
|
2531
|
+
if (typeof repositoryData.id === "string") {
|
|
2532
|
+
repo.id = repositoryData.id;
|
|
2533
|
+
}
|
|
2466
2534
|
return repo;
|
|
2467
2535
|
}
|
|
2468
2536
|
}
|
|
@@ -2475,7 +2543,7 @@ async function addRepository(repository, manager, repoDeps, context) {
|
|
|
2475
2543
|
}
|
|
2476
2544
|
log3(`adding repository ${repository.name}`);
|
|
2477
2545
|
const repoPath = getRepoPath(repository.name, repoDeps.getReposDir());
|
|
2478
|
-
await repoDeps.fileSystem.mkdir(
|
|
2546
|
+
await repoDeps.fileSystem.mkdir(dirname2(repoPath), { recursive: true });
|
|
2479
2547
|
if (repoDeps.fileSystem.exists(repoPath)) {
|
|
2480
2548
|
await removeRepository(repoPath, repoDeps.spawn, context);
|
|
2481
2549
|
}
|
|
@@ -3026,41 +3094,11 @@ function defaultGetTerminalSize() {
|
|
|
3026
3094
|
function defaultWriteStdout(data) {
|
|
3027
3095
|
process.stdout.write(data);
|
|
3028
3096
|
}
|
|
3029
|
-
function
|
|
3030
|
-
|
|
3031
|
-
const server = httpCreateServer(async (nodeRequest, nodeResponse) => {
|
|
3032
|
-
const url = new URL(nodeRequest.url ?? "/", `http://localhost:${resolvedPort}`);
|
|
3033
|
-
const request = new Request(url.toString(), {
|
|
3034
|
-
method: nodeRequest.method ?? "GET"
|
|
3035
|
-
});
|
|
3036
|
-
const response = handler(request);
|
|
3037
|
-
const body = await response.text();
|
|
3038
|
-
nodeResponse.writeHead(response.status, {
|
|
3039
|
-
"Content-Type": response.headers.get("content-type") ?? "text/plain"
|
|
3040
|
-
});
|
|
3041
|
-
nodeResponse.end(body);
|
|
3042
|
-
});
|
|
3043
|
-
server.listen(0, () => {
|
|
3044
|
-
const addr2 = server.address();
|
|
3045
|
-
if (addr2 && typeof addr2 === "object") {
|
|
3046
|
-
resolvedPort = addr2.port;
|
|
3047
|
-
}
|
|
3048
|
-
});
|
|
3049
|
-
const addr = server.address();
|
|
3050
|
-
if (addr && typeof addr === "object") {
|
|
3051
|
-
resolvedPort = addr.port;
|
|
3052
|
-
}
|
|
3053
|
-
return { port: resolvedPort, stop: () => server.close() };
|
|
3054
|
-
}
|
|
3055
|
-
function defaultOpenBrowser(url) {
|
|
3056
|
-
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
3057
|
-
nodeSpawn3(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
3058
|
-
}
|
|
3059
|
-
function createDefaultBucketDependencies() {
|
|
3060
|
-
const authFileSystem = {
|
|
3097
|
+
function createAuthFileSystem(dependencies) {
|
|
3098
|
+
return {
|
|
3061
3099
|
exists: (path) => {
|
|
3062
3100
|
try {
|
|
3063
|
-
accessSync(path);
|
|
3101
|
+
dependencies.accessSync(path);
|
|
3064
3102
|
return true;
|
|
3065
3103
|
} catch {
|
|
3066
3104
|
return false;
|
|
@@ -3068,21 +3106,33 @@ function createDefaultBucketDependencies() {
|
|
|
3068
3106
|
},
|
|
3069
3107
|
isDirectory: (path) => {
|
|
3070
3108
|
try {
|
|
3071
|
-
return statSync(path).isDirectory();
|
|
3109
|
+
return dependencies.statSync(path).isDirectory();
|
|
3072
3110
|
} catch {
|
|
3073
3111
|
return false;
|
|
3074
3112
|
}
|
|
3075
3113
|
},
|
|
3076
|
-
getFileCreationTime: (path) => statSync(path).birthtimeMs,
|
|
3077
|
-
readFile: (path) => readFile(path, "utf8"),
|
|
3078
|
-
writeFile: (path, content) => writeFile(path, content, "utf8"),
|
|
3079
|
-
mkdir: (path, options) => mkdir(path, options).then(() => {}),
|
|
3080
|
-
readdir: (path) => readdir(path),
|
|
3081
|
-
chmod: (path, mode) => chmod(path, mode),
|
|
3082
|
-
rename: (oldPath, newPath) =>
|
|
3114
|
+
getFileCreationTime: (path) => dependencies.statSync(path).birthtimeMs,
|
|
3115
|
+
readFile: (path) => dependencies.readFile(path, "utf8"),
|
|
3116
|
+
writeFile: (path, content) => dependencies.writeFile(path, content, "utf8"),
|
|
3117
|
+
mkdir: (path, options) => dependencies.mkdir(path, options).then(() => {}),
|
|
3118
|
+
readdir: (path) => dependencies.readdir(path),
|
|
3119
|
+
chmod: (path, mode) => dependencies.chmod(path, mode),
|
|
3120
|
+
rename: (oldPath, newPath) => dependencies.rename(oldPath, newPath)
|
|
3083
3121
|
};
|
|
3122
|
+
}
|
|
3123
|
+
function createDefaultBucketDependencies() {
|
|
3124
|
+
const authFileSystem = createAuthFileSystem({
|
|
3125
|
+
accessSync,
|
|
3126
|
+
statSync,
|
|
3127
|
+
readFile,
|
|
3128
|
+
writeFile,
|
|
3129
|
+
mkdir,
|
|
3130
|
+
readdir,
|
|
3131
|
+
chmod,
|
|
3132
|
+
rename: (oldPath, newPath) => import("node:fs/promises").then((mod) => mod.rename(oldPath, newPath))
|
|
3133
|
+
});
|
|
3084
3134
|
return {
|
|
3085
|
-
spawn:
|
|
3135
|
+
spawn: nodeSpawn4,
|
|
3086
3136
|
createWebSocket: defaultCreateWebSocket,
|
|
3087
3137
|
setupKeypress: defaultSetupKeypress,
|
|
3088
3138
|
setupSignals: defaultSetupSignals,
|
|
@@ -3091,10 +3141,10 @@ function createDefaultBucketDependencies() {
|
|
|
3091
3141
|
writeStdout: defaultWriteStdout,
|
|
3092
3142
|
isTTY: process.stdout.isTTY ?? false,
|
|
3093
3143
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
3094
|
-
getReposDir: () => process.env
|
|
3144
|
+
getReposDir: () => getReposDir(process.env, homedir()),
|
|
3095
3145
|
auth: {
|
|
3096
|
-
createServer:
|
|
3097
|
-
openBrowser
|
|
3146
|
+
createServer: createLocalServer,
|
|
3147
|
+
openBrowser,
|
|
3098
3148
|
getHomeDir: () => homedir(),
|
|
3099
3149
|
fileSystem: authFileSystem
|
|
3100
3150
|
}
|
|
@@ -3459,6 +3509,176 @@ async function bucket(dependencies, bucketDeps = createDefaultBucketDependencies
|
|
|
3459
3509
|
return { exitCode: 0 };
|
|
3460
3510
|
}
|
|
3461
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
|
+
|
|
3462
3682
|
// lib/cli/process-runner.ts
|
|
3463
3683
|
import { spawn } from "node:child_process";
|
|
3464
3684
|
function createShellRunner(spawnFn) {
|
|
@@ -3517,7 +3737,7 @@ function runBufferedProcess(spawnFn, command, commandArguments, cwd, shell, time
|
|
|
3517
3737
|
}
|
|
3518
3738
|
|
|
3519
3739
|
// lib/cli/commands/lint-markdown.ts
|
|
3520
|
-
import { join as
|
|
3740
|
+
import { join as join8 } from "node:path";
|
|
3521
3741
|
|
|
3522
3742
|
// lib/lint/validators/content-validator.ts
|
|
3523
3743
|
var REQUIRED_HEADINGS = [
|
|
@@ -3807,7 +4027,7 @@ function validateIdeaTransitionTitle(filePath, content, ideasPath, fileSystem) {
|
|
|
3807
4027
|
}
|
|
3808
4028
|
|
|
3809
4029
|
// lib/lint/validators/link-validator.ts
|
|
3810
|
-
import { dirname as
|
|
4030
|
+
import { dirname as dirname3, resolve } from "node:path";
|
|
3811
4031
|
var SEMANTIC_RULES = [
|
|
3812
4032
|
{
|
|
3813
4033
|
section: "## Principles",
|
|
@@ -3824,7 +4044,7 @@ function validateLinks(filePath, content, fileSystem) {
|
|
|
3824
4044
|
const violations = [];
|
|
3825
4045
|
const lines = content.split(`
|
|
3826
4046
|
`);
|
|
3827
|
-
const fileDir =
|
|
4047
|
+
const fileDir = dirname3(filePath);
|
|
3828
4048
|
for (let i = 0;i < lines.length; i++) {
|
|
3829
4049
|
const line = lines[i];
|
|
3830
4050
|
const linkPattern = new RegExp(MARKDOWN_LINK_PATTERN.source, "g");
|
|
@@ -3851,7 +4071,7 @@ function validateSemanticLinks(filePath, content) {
|
|
|
3851
4071
|
const violations = [];
|
|
3852
4072
|
const lines = content.split(`
|
|
3853
4073
|
`);
|
|
3854
|
-
const fileDir =
|
|
4074
|
+
const fileDir = dirname3(filePath);
|
|
3855
4075
|
let currentSection = null;
|
|
3856
4076
|
for (let i = 0;i < lines.length; i++) {
|
|
3857
4077
|
const line = lines[i];
|
|
@@ -3902,7 +4122,7 @@ function validatePrincipleHierarchyLinks(filePath, content) {
|
|
|
3902
4122
|
const violations = [];
|
|
3903
4123
|
const lines = content.split(`
|
|
3904
4124
|
`);
|
|
3905
|
-
const fileDir =
|
|
4125
|
+
const fileDir = dirname3(filePath);
|
|
3906
4126
|
let currentSection = null;
|
|
3907
4127
|
for (let i = 0;i < lines.length; i++) {
|
|
3908
4128
|
const line = lines[i];
|
|
@@ -3951,7 +4171,7 @@ function validatePrincipleHierarchyLinks(filePath, content) {
|
|
|
3951
4171
|
}
|
|
3952
4172
|
|
|
3953
4173
|
// lib/lint/validators/principle-hierarchy.ts
|
|
3954
|
-
import { dirname as
|
|
4174
|
+
import { dirname as dirname4, resolve as resolve2 } from "node:path";
|
|
3955
4175
|
var REQUIRED_PRINCIPLE_HEADINGS = ["## Parent Principle", "## Sub-Principles"];
|
|
3956
4176
|
function validatePrincipleHierarchySections(filePath, content) {
|
|
3957
4177
|
const violations = [];
|
|
@@ -3968,7 +4188,7 @@ function validatePrincipleHierarchySections(filePath, content) {
|
|
|
3968
4188
|
function extractPrincipleRelationships(filePath, content) {
|
|
3969
4189
|
const lines = content.split(`
|
|
3970
4190
|
`);
|
|
3971
|
-
const fileDir =
|
|
4191
|
+
const fileDir = dirname4(filePath);
|
|
3972
4192
|
const parentPrinciples = [];
|
|
3973
4193
|
const subPrinciples = [];
|
|
3974
4194
|
let currentSection = null;
|
|
@@ -4089,7 +4309,7 @@ async function lintMarkdown(dependencies) {
|
|
|
4089
4309
|
const violations = [];
|
|
4090
4310
|
context.stdout("Validating directory structure...");
|
|
4091
4311
|
violations.push(...await validateDirectoryStructure(dustPath, fileSystem, dependencies.settings.extraDirectories));
|
|
4092
|
-
const settingsPath =
|
|
4312
|
+
const settingsPath = join8(dustPath, "config", "settings.json");
|
|
4093
4313
|
if (fileSystem.exists(settingsPath)) {
|
|
4094
4314
|
context.stdout("Validating settings.json...");
|
|
4095
4315
|
try {
|
|
@@ -4419,7 +4639,7 @@ async function check(dependencies, shellRunner = defaultShellRunner) {
|
|
|
4419
4639
|
function generateHelpText(settings) {
|
|
4420
4640
|
const bin = settings.dustCommand;
|
|
4421
4641
|
return dedent`
|
|
4422
|
-
|
|
4642
|
+
✨ dust - Flow state for AI coding agents.
|
|
4423
4643
|
|
|
4424
4644
|
Usage: ${bin} <command> [options]
|
|
4425
4645
|
|
|
@@ -4705,10 +4925,10 @@ async function list(dependencies) {
|
|
|
4705
4925
|
}
|
|
4706
4926
|
|
|
4707
4927
|
// lib/codex/spawn-codex.ts
|
|
4708
|
-
import { spawn as
|
|
4928
|
+
import { spawn as nodeSpawn5 } from "node:child_process";
|
|
4709
4929
|
import { createInterface as nodeCreateInterface2 } from "node:readline";
|
|
4710
4930
|
var defaultDependencies2 = {
|
|
4711
|
-
spawn:
|
|
4931
|
+
spawn: nodeSpawn5,
|
|
4712
4932
|
createInterface: nodeCreateInterface2
|
|
4713
4933
|
};
|
|
4714
4934
|
async function* spawnCodex(prompt, options = {}, dependencies = defaultDependencies2) {
|
|
@@ -5227,6 +5447,7 @@ var commandRegistry = {
|
|
|
5227
5447
|
agent,
|
|
5228
5448
|
audit,
|
|
5229
5449
|
bucket,
|
|
5450
|
+
"bucket asset upload": bucketAssetUpload,
|
|
5230
5451
|
focus,
|
|
5231
5452
|
"new task": newTask,
|
|
5232
5453
|
"new principle": newPrinciple,
|
|
@@ -5243,6 +5464,9 @@ var COMMANDS = Object.keys(commandRegistry).filter((cmd) => !cmd.includes(" "));
|
|
|
5243
5464
|
function isHelpRequest(command) {
|
|
5244
5465
|
return !command || command === "help" || command === "--help" || command === "-h";
|
|
5245
5466
|
}
|
|
5467
|
+
function isVersionRequest(command) {
|
|
5468
|
+
return command === "--version" || command === "-v";
|
|
5469
|
+
}
|
|
5246
5470
|
function isValidCommand(command) {
|
|
5247
5471
|
return command in commandRegistry;
|
|
5248
5472
|
}
|
|
@@ -5262,6 +5486,10 @@ async function main(options) {
|
|
|
5262
5486
|
const { commandArguments, context, fileSystem, glob, directoryFileSorter } = options;
|
|
5263
5487
|
const settings = await loadSettings(context.cwd, fileSystem);
|
|
5264
5488
|
const helpText = generateHelpText(settings);
|
|
5489
|
+
if (isVersionRequest(commandArguments[0])) {
|
|
5490
|
+
context.stdout(DUST_VERSION);
|
|
5491
|
+
return { exitCode: 0 };
|
|
5492
|
+
}
|
|
5265
5493
|
if (isHelpRequest(commandArguments[0])) {
|
|
5266
5494
|
context.stdout(helpText);
|
|
5267
5495
|
return { exitCode: 0 };
|
|
@@ -5308,10 +5536,10 @@ function createFileSystem(primitives) {
|
|
|
5308
5536
|
rename: (oldPath, newPath) => primitives.rename(oldPath, newPath)
|
|
5309
5537
|
};
|
|
5310
5538
|
}
|
|
5311
|
-
function createGlobScanner(
|
|
5539
|
+
function createGlobScanner(readdir3) {
|
|
5312
5540
|
return {
|
|
5313
5541
|
scan: async function* (dir) {
|
|
5314
|
-
for (const entry of await
|
|
5542
|
+
for (const entry of await readdir3(dir, { recursive: true })) {
|
|
5315
5543
|
if (entry.endsWith(".md"))
|
|
5316
5544
|
yield entry;
|
|
5317
5545
|
}
|
|
@@ -5338,7 +5566,7 @@ async function wireEntry(fsPrimitives, processPrimitives, consolePrimitives) {
|
|
|
5338
5566
|
}
|
|
5339
5567
|
|
|
5340
5568
|
// lib/cli/run.ts
|
|
5341
|
-
await wireEntry({ existsSync, statSync:
|
|
5569
|
+
await wireEntry({ existsSync, statSync: statSync3, readFile: readFile3, writeFile: writeFile3, mkdir: mkdir3, readdir: readdir3, chmod: chmod3, rename }, {
|
|
5342
5570
|
argv: process.argv,
|
|
5343
5571
|
cwd: () => process.cwd(),
|
|
5344
5572
|
exit: (code) => {
|
|
@@ -5350,4 +5578,4 @@ await wireEntry({ existsSync, statSync: statSync2, readFile: readFile2, writeFil
|
|
|
5350
5578
|
process.stdout.write(message);
|
|
5351
5579
|
},
|
|
5352
5580
|
error: console.error
|
|
5353
|
-
});
|
|
5581
|
+
});
|