@joshski/dust 0.1.56 → 0.1.58
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 +134 -63
- package/dist/ideas.js +135 -0
- package/dist/logging/index.d.ts +53 -17
- package/dist/logging/sink.d.ts +25 -20
- package/dist/logging.js +98 -54
- package/lib/istanbul/minimal-reporter.cjs +32 -16
- package/package.json +6 -2
package/dist/dust.js
CHANGED
|
@@ -1177,7 +1177,7 @@ function getLogLines(buffer) {
|
|
|
1177
1177
|
}
|
|
1178
1178
|
|
|
1179
1179
|
// lib/bucket/repository.ts
|
|
1180
|
-
import { dirname as
|
|
1180
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
1181
1181
|
|
|
1182
1182
|
// lib/claude/spawn-claude-code.ts
|
|
1183
1183
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
@@ -1595,6 +1595,9 @@ async function run(prompt, options = {}, dependencies = defaultRunnerDependencie
|
|
|
1595
1595
|
await dependencies.streamEvents(events, sink, onRawEvent);
|
|
1596
1596
|
}
|
|
1597
1597
|
|
|
1598
|
+
// lib/logging/index.ts
|
|
1599
|
+
import { join as join5 } from "node:path";
|
|
1600
|
+
|
|
1598
1601
|
// lib/logging/match.ts
|
|
1599
1602
|
function parsePatterns(debug) {
|
|
1600
1603
|
if (!debug)
|
|
@@ -1617,56 +1620,105 @@ function formatLine(name, messages) {
|
|
|
1617
1620
|
|
|
1618
1621
|
// lib/logging/sink.ts
|
|
1619
1622
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
1620
|
-
import {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
ready = true;
|
|
1628
|
-
const dir = join5(process.cwd(), "log", "dust");
|
|
1629
|
-
logPath = join5(dir, `${scope}.log`);
|
|
1630
|
-
try {
|
|
1631
|
-
mkdirSync(dir, { recursive: true });
|
|
1632
|
-
} catch {
|
|
1633
|
-
logPath = undefined;
|
|
1634
|
-
}
|
|
1635
|
-
return logPath;
|
|
1636
|
-
}
|
|
1637
|
-
function setLogScope(name) {
|
|
1638
|
-
scope = name;
|
|
1639
|
-
process.env.DEBUG_LOG_SCOPE = name;
|
|
1640
|
-
logPath = undefined;
|
|
1623
|
+
import { dirname } from "node:path";
|
|
1624
|
+
|
|
1625
|
+
class FileSink {
|
|
1626
|
+
logPath;
|
|
1627
|
+
_appendFileSync;
|
|
1628
|
+
_mkdirSync;
|
|
1629
|
+
resolvedPath;
|
|
1641
1630
|
ready = false;
|
|
1631
|
+
constructor(logPath, _appendFileSync = appendFileSync, _mkdirSync = mkdirSync) {
|
|
1632
|
+
this.logPath = logPath;
|
|
1633
|
+
this._appendFileSync = _appendFileSync;
|
|
1634
|
+
this._mkdirSync = _mkdirSync;
|
|
1635
|
+
}
|
|
1636
|
+
ensureLogFile() {
|
|
1637
|
+
if (this.ready)
|
|
1638
|
+
return this.resolvedPath;
|
|
1639
|
+
this.ready = true;
|
|
1640
|
+
this.resolvedPath = this.logPath;
|
|
1641
|
+
try {
|
|
1642
|
+
this._mkdirSync(dirname(this.logPath), { recursive: true });
|
|
1643
|
+
} catch {
|
|
1644
|
+
this.resolvedPath = undefined;
|
|
1645
|
+
}
|
|
1646
|
+
return this.resolvedPath;
|
|
1647
|
+
}
|
|
1648
|
+
write(line) {
|
|
1649
|
+
const path = this.ensureLogFile();
|
|
1650
|
+
if (!path)
|
|
1651
|
+
return;
|
|
1652
|
+
try {
|
|
1653
|
+
this._appendFileSync(path, line);
|
|
1654
|
+
} catch {}
|
|
1655
|
+
}
|
|
1642
1656
|
}
|
|
1643
|
-
var writeToFile = (line) => {
|
|
1644
|
-
const path = ensureLogFile();
|
|
1645
|
-
if (!path)
|
|
1646
|
-
return;
|
|
1647
|
-
try {
|
|
1648
|
-
appendFileSync(path, line);
|
|
1649
|
-
} catch {}
|
|
1650
|
-
};
|
|
1651
1657
|
|
|
1652
1658
|
// lib/logging/index.ts
|
|
1653
|
-
var
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
}
|
|
1662
|
-
function createLogger(name, write = writeToFile) {
|
|
1663
|
-
return (...messages) => {
|
|
1664
|
-
init();
|
|
1665
|
-
if (!patterns || !matchesAny(name, patterns))
|
|
1659
|
+
var DUST_LOG_FILE = "DUST_LOG_FILE";
|
|
1660
|
+
function createLoggingService() {
|
|
1661
|
+
let patterns = null;
|
|
1662
|
+
let initialized = false;
|
|
1663
|
+
let activeFileSink = null;
|
|
1664
|
+
const fileSinkCache = new Map;
|
|
1665
|
+
function init() {
|
|
1666
|
+
if (initialized)
|
|
1666
1667
|
return;
|
|
1667
|
-
|
|
1668
|
+
initialized = true;
|
|
1669
|
+
const parsed = parsePatterns(process.env.DEBUG);
|
|
1670
|
+
patterns = parsed.length > 0 ? parsed : null;
|
|
1671
|
+
}
|
|
1672
|
+
function getOrCreateFileSink(path) {
|
|
1673
|
+
let sink = fileSinkCache.get(path);
|
|
1674
|
+
if (!sink) {
|
|
1675
|
+
sink = new FileSink(path);
|
|
1676
|
+
fileSinkCache.set(path, sink);
|
|
1677
|
+
}
|
|
1678
|
+
return sink;
|
|
1679
|
+
}
|
|
1680
|
+
return {
|
|
1681
|
+
enableFileLogs(scope, sinkForTesting) {
|
|
1682
|
+
const existing = process.env[DUST_LOG_FILE];
|
|
1683
|
+
const logDir = process.env.DUST_LOG_DIR ?? join5(process.cwd(), "log");
|
|
1684
|
+
const path = existing ?? join5(logDir, `${scope}.log`);
|
|
1685
|
+
if (!existing) {
|
|
1686
|
+
process.env[DUST_LOG_FILE] = path;
|
|
1687
|
+
}
|
|
1688
|
+
activeFileSink = sinkForTesting ?? new FileSink(path);
|
|
1689
|
+
},
|
|
1690
|
+
createLogger(name, options) {
|
|
1691
|
+
let perLoggerSink;
|
|
1692
|
+
if (options?.file === false) {
|
|
1693
|
+
perLoggerSink = null;
|
|
1694
|
+
} else if (typeof options?.file === "string") {
|
|
1695
|
+
perLoggerSink = getOrCreateFileSink(options.file);
|
|
1696
|
+
}
|
|
1697
|
+
return (...messages) => {
|
|
1698
|
+
init();
|
|
1699
|
+
const line = formatLine(name, messages);
|
|
1700
|
+
if (perLoggerSink !== undefined) {
|
|
1701
|
+
if (perLoggerSink !== null) {
|
|
1702
|
+
perLoggerSink.write(line);
|
|
1703
|
+
}
|
|
1704
|
+
} else if (activeFileSink) {
|
|
1705
|
+
activeFileSink.write(line);
|
|
1706
|
+
}
|
|
1707
|
+
if (patterns && matchesAny(name, patterns)) {
|
|
1708
|
+
process.stdout.write(line);
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
},
|
|
1712
|
+
isEnabled(name) {
|
|
1713
|
+
init();
|
|
1714
|
+
return patterns !== null && matchesAny(name, patterns);
|
|
1715
|
+
}
|
|
1668
1716
|
};
|
|
1669
1717
|
}
|
|
1718
|
+
var defaultService = createLoggingService();
|
|
1719
|
+
var enableFileLogs = defaultService.enableFileLogs.bind(defaultService);
|
|
1720
|
+
var createLogger = defaultService.createLogger.bind(defaultService);
|
|
1721
|
+
var isEnabled = defaultService.isEnabled.bind(defaultService);
|
|
1670
1722
|
|
|
1671
1723
|
// lib/bucket/repository-git.ts
|
|
1672
1724
|
import { join as join6 } from "node:path";
|
|
@@ -1742,7 +1794,7 @@ function formatAgentEvent(event) {
|
|
|
1742
1794
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
1743
1795
|
import { readFileSync } from "node:fs";
|
|
1744
1796
|
import os from "node:os";
|
|
1745
|
-
import { dirname, join as join7 } from "node:path";
|
|
1797
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
1746
1798
|
import { fileURLToPath } from "node:url";
|
|
1747
1799
|
|
|
1748
1800
|
// lib/workflow-tasks.ts
|
|
@@ -1887,7 +1939,7 @@ async function next(dependencies) {
|
|
|
1887
1939
|
}
|
|
1888
1940
|
|
|
1889
1941
|
// lib/cli/commands/loop.ts
|
|
1890
|
-
var __dirname2 =
|
|
1942
|
+
var __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
1891
1943
|
function getDustVersion() {
|
|
1892
1944
|
const candidates = [
|
|
1893
1945
|
join7(__dirname2, "../../../package.json"),
|
|
@@ -1970,7 +2022,7 @@ function createWireEventSender(eventsUrl, sessionId, postEvent, onError, getAgen
|
|
|
1970
2022
|
postEvent(eventsUrl, payload).catch(onError);
|
|
1971
2023
|
};
|
|
1972
2024
|
}
|
|
1973
|
-
var log = createLogger("dust
|
|
2025
|
+
var log = createLogger("dust:cli:commands:loop");
|
|
1974
2026
|
var SLEEP_INTERVAL_MS = 30000;
|
|
1975
2027
|
var SLEEP_STEP_MS = 1000;
|
|
1976
2028
|
var DEFAULT_MAX_ITERATIONS = 10;
|
|
@@ -2137,6 +2189,7 @@ function parseMaxIterations(commandArguments) {
|
|
|
2137
2189
|
return parsed;
|
|
2138
2190
|
}
|
|
2139
2191
|
async function loopClaude(dependencies, loopDependencies = createDefaultDependencies()) {
|
|
2192
|
+
enableFileLogs("loop");
|
|
2140
2193
|
const { context, settings } = dependencies;
|
|
2141
2194
|
const { postEvent } = loopDependencies;
|
|
2142
2195
|
const maxIterations = parseMaxIterations(dependencies.arguments);
|
|
@@ -2200,7 +2253,7 @@ async function loopClaude(dependencies, loopDependencies = createDefaultDependen
|
|
|
2200
2253
|
}
|
|
2201
2254
|
|
|
2202
2255
|
// lib/bucket/repository-loop.ts
|
|
2203
|
-
var log2 = createLogger("dust
|
|
2256
|
+
var log2 = createLogger("dust:bucket:repository-loop");
|
|
2204
2257
|
var FALLBACK_TIMEOUT_MS = 300000;
|
|
2205
2258
|
function createNoOpGlobScanner() {
|
|
2206
2259
|
return {
|
|
@@ -2349,7 +2402,7 @@ async function runRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
|
2349
2402
|
}
|
|
2350
2403
|
|
|
2351
2404
|
// lib/bucket/repository.ts
|
|
2352
|
-
var log3 = createLogger("dust
|
|
2405
|
+
var log3 = createLogger("dust:bucket:repository");
|
|
2353
2406
|
function startRepositoryLoop(repoState, repoDeps, sendEvent, sessionId) {
|
|
2354
2407
|
log3(`starting loop for ${repoState.repository.name}`);
|
|
2355
2408
|
repoState.stopRequested = false;
|
|
@@ -2391,7 +2444,7 @@ async function addRepository(repository, manager, repoDeps, context) {
|
|
|
2391
2444
|
}
|
|
2392
2445
|
log3(`adding repository ${repository.name}`);
|
|
2393
2446
|
const repoPath = getRepoPath(repository.name, repoDeps.getReposDir());
|
|
2394
|
-
await repoDeps.fileSystem.mkdir(
|
|
2447
|
+
await repoDeps.fileSystem.mkdir(dirname3(repoPath), { recursive: true });
|
|
2395
2448
|
if (repoDeps.fileSystem.exists(repoPath)) {
|
|
2396
2449
|
await removeRepository(repoPath, repoDeps.spawn, context);
|
|
2397
2450
|
}
|
|
@@ -2884,7 +2937,7 @@ function handleKeyInput(state, key, options) {
|
|
|
2884
2937
|
}
|
|
2885
2938
|
|
|
2886
2939
|
// lib/cli/commands/bucket.ts
|
|
2887
|
-
var log4 = createLogger("dust
|
|
2940
|
+
var log4 = createLogger("dust:cli:commands:bucket");
|
|
2888
2941
|
var DEFAULT_DUSTBUCKET_WS_URL = "wss://dustbucket.com/agent/connect";
|
|
2889
2942
|
var INITIAL_RECONNECT_DELAY_MS = 1000;
|
|
2890
2943
|
var MAX_RECONNECT_DELAY_MS = 30000;
|
|
@@ -3312,6 +3365,7 @@ async function resolveToken(authDeps, context) {
|
|
|
3312
3365
|
}
|
|
3313
3366
|
}
|
|
3314
3367
|
async function bucket(dependencies, bucketDeps = createDefaultBucketDependencies()) {
|
|
3368
|
+
enableFileLogs("bucket");
|
|
3315
3369
|
const { context, fileSystem } = dependencies;
|
|
3316
3370
|
const token = await resolveToken(bucketDeps.auth, context);
|
|
3317
3371
|
if (!token) {
|
|
@@ -3602,7 +3656,7 @@ function validateTitleFilenameMatch(filePath, content) {
|
|
|
3602
3656
|
}
|
|
3603
3657
|
|
|
3604
3658
|
// lib/lint/validators/goal-hierarchy.ts
|
|
3605
|
-
import { dirname as
|
|
3659
|
+
import { dirname as dirname4, resolve } from "node:path";
|
|
3606
3660
|
var REQUIRED_GOAL_HEADINGS = ["## Parent Goal", "## Sub-Goals"];
|
|
3607
3661
|
function validateGoalHierarchySections(filePath, content) {
|
|
3608
3662
|
const violations = [];
|
|
@@ -3619,7 +3673,7 @@ function validateGoalHierarchySections(filePath, content) {
|
|
|
3619
3673
|
function extractGoalRelationships(filePath, content) {
|
|
3620
3674
|
const lines = content.split(`
|
|
3621
3675
|
`);
|
|
3622
|
-
const fileDir =
|
|
3676
|
+
const fileDir = dirname4(filePath);
|
|
3623
3677
|
const parentGoals = [];
|
|
3624
3678
|
const subGoals = [];
|
|
3625
3679
|
let currentSection = null;
|
|
@@ -3828,7 +3882,7 @@ function validateIdeaTransitionTitle(filePath, content, ideasPath, fileSystem) {
|
|
|
3828
3882
|
}
|
|
3829
3883
|
|
|
3830
3884
|
// lib/lint/validators/link-validator.ts
|
|
3831
|
-
import { dirname as
|
|
3885
|
+
import { dirname as dirname5, resolve as resolve2 } from "node:path";
|
|
3832
3886
|
var SEMANTIC_RULES = [
|
|
3833
3887
|
{
|
|
3834
3888
|
section: "## Goals",
|
|
@@ -3845,7 +3899,7 @@ function validateLinks(filePath, content, fileSystem) {
|
|
|
3845
3899
|
const violations = [];
|
|
3846
3900
|
const lines = content.split(`
|
|
3847
3901
|
`);
|
|
3848
|
-
const fileDir =
|
|
3902
|
+
const fileDir = dirname5(filePath);
|
|
3849
3903
|
for (let i = 0;i < lines.length; i++) {
|
|
3850
3904
|
const line = lines[i];
|
|
3851
3905
|
const linkPattern = new RegExp(MARKDOWN_LINK_PATTERN.source, "g");
|
|
@@ -3872,7 +3926,7 @@ function validateSemanticLinks(filePath, content) {
|
|
|
3872
3926
|
const violations = [];
|
|
3873
3927
|
const lines = content.split(`
|
|
3874
3928
|
`);
|
|
3875
|
-
const fileDir =
|
|
3929
|
+
const fileDir = dirname5(filePath);
|
|
3876
3930
|
let currentSection = null;
|
|
3877
3931
|
for (let i = 0;i < lines.length; i++) {
|
|
3878
3932
|
const line = lines[i];
|
|
@@ -3923,7 +3977,7 @@ function validateGoalHierarchyLinks(filePath, content) {
|
|
|
3923
3977
|
const violations = [];
|
|
3924
3978
|
const lines = content.split(`
|
|
3925
3979
|
`);
|
|
3926
|
-
const fileDir =
|
|
3980
|
+
const fileDir = dirname5(filePath);
|
|
3927
3981
|
let currentSection = null;
|
|
3928
3982
|
for (let i = 0;i < lines.length; i++) {
|
|
3929
3983
|
const line = lines[i];
|
|
@@ -4160,8 +4214,26 @@ async function lintMarkdown(dependencies) {
|
|
|
4160
4214
|
}
|
|
4161
4215
|
|
|
4162
4216
|
// lib/cli/commands/check.ts
|
|
4163
|
-
var log5 = createLogger("dust
|
|
4217
|
+
var log5 = createLogger("dust:cli:commands:check");
|
|
4164
4218
|
var DEFAULT_CHECK_TIMEOUT_MS = 13000;
|
|
4219
|
+
var MAX_OUTPUT_LINES = 500;
|
|
4220
|
+
var KEEP_LINES = 250;
|
|
4221
|
+
function truncateOutput(output) {
|
|
4222
|
+
const lines = output.split(`
|
|
4223
|
+
`);
|
|
4224
|
+
if (lines.length <= MAX_OUTPUT_LINES) {
|
|
4225
|
+
return output;
|
|
4226
|
+
}
|
|
4227
|
+
const snippedCount = lines.length - KEEP_LINES * 2;
|
|
4228
|
+
const firstLines = lines.slice(0, KEEP_LINES);
|
|
4229
|
+
const lastLines = lines.slice(-KEEP_LINES);
|
|
4230
|
+
return [
|
|
4231
|
+
...firstLines,
|
|
4232
|
+
`[...snip ${snippedCount} lines...]`,
|
|
4233
|
+
...lastLines
|
|
4234
|
+
].join(`
|
|
4235
|
+
`);
|
|
4236
|
+
}
|
|
4165
4237
|
async function runSingleCheck(check, cwd, runner) {
|
|
4166
4238
|
const timeoutMs = check.timeoutMilliseconds ?? DEFAULT_CHECK_TIMEOUT_MS;
|
|
4167
4239
|
log5(`running check ${check.name}: ${check.command}`);
|
|
@@ -4241,7 +4313,7 @@ function displayResults(results, context) {
|
|
|
4241
4313
|
context.stdout(`Note: This check was killed after ${result.timeoutSeconds}s. To configure a different timeout, set "timeoutMilliseconds" in the check configuration in .dust/config/settings.json`);
|
|
4242
4314
|
}
|
|
4243
4315
|
if (result.output.trim()) {
|
|
4244
|
-
context.stdout(result.output.trimEnd());
|
|
4316
|
+
context.stdout(truncateOutput(result.output).trimEnd());
|
|
4245
4317
|
}
|
|
4246
4318
|
if (result.hints && result.hints.length > 0) {
|
|
4247
4319
|
context.stdout("");
|
|
@@ -4264,7 +4336,7 @@ async function check(dependencies, shellRunner = defaultShellRunner) {
|
|
|
4264
4336
|
settings
|
|
4265
4337
|
} = dependencies;
|
|
4266
4338
|
const serial = commandArguments.includes("--serial");
|
|
4267
|
-
|
|
4339
|
+
enableFileLogs("check");
|
|
4268
4340
|
if (!settings.checks || settings.checks.length === 0) {
|
|
4269
4341
|
context.stderr("Error: No checks configured in .dust/config/settings.json");
|
|
4270
4342
|
context.stderr("");
|
|
@@ -4396,7 +4468,7 @@ function agentsMdContent(dustCommand) {
|
|
|
4396
4468
|
Always immediately run \`${dustCommand} agent\` when you start working in this repository.
|
|
4397
4469
|
`;
|
|
4398
4470
|
}
|
|
4399
|
-
async function
|
|
4471
|
+
async function init(dependencies) {
|
|
4400
4472
|
const { context, fileSystem } = dependencies;
|
|
4401
4473
|
const colors = getColors();
|
|
4402
4474
|
const dustPath = `${context.cwd}/.dust`;
|
|
@@ -5042,7 +5114,7 @@ async function facts(dependencies) {
|
|
|
5042
5114
|
|
|
5043
5115
|
// lib/cli/main.ts
|
|
5044
5116
|
var commandRegistry = {
|
|
5045
|
-
init
|
|
5117
|
+
init,
|
|
5046
5118
|
lint: lintMarkdown,
|
|
5047
5119
|
list,
|
|
5048
5120
|
tasks,
|
|
@@ -5066,7 +5138,6 @@ var commandRegistry = {
|
|
|
5066
5138
|
help
|
|
5067
5139
|
};
|
|
5068
5140
|
var COMMANDS = Object.keys(commandRegistry).filter((cmd) => !cmd.includes(" "));
|
|
5069
|
-
var HELP_TEXT = generateHelpText({ dustCommand: "dust" });
|
|
5070
5141
|
function isHelpRequest(command) {
|
|
5071
5142
|
return !command || command === "help" || command === "--help" || command === "-h";
|
|
5072
5143
|
}
|
package/dist/ideas.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// lib/markdown/markdown-utilities.ts
|
|
2
|
+
function extractTitle(content) {
|
|
3
|
+
const match = content.match(/^#\s+(.+)$/m);
|
|
4
|
+
return match ? match[1].trim() : null;
|
|
5
|
+
}
|
|
6
|
+
function extractOpeningSentence(content) {
|
|
7
|
+
const lines = content.split(`
|
|
8
|
+
`);
|
|
9
|
+
let h1Index = -1;
|
|
10
|
+
for (let i = 0;i < lines.length; i++) {
|
|
11
|
+
if (lines[i].match(/^#\s+.+$/)) {
|
|
12
|
+
h1Index = i;
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (h1Index === -1) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
let paragraphStart = -1;
|
|
20
|
+
for (let i = h1Index + 1;i < lines.length; i++) {
|
|
21
|
+
const line = lines[i].trim();
|
|
22
|
+
if (line !== "") {
|
|
23
|
+
paragraphStart = i;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (paragraphStart === -1) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const firstLine = lines[paragraphStart];
|
|
31
|
+
const trimmedFirstLine = firstLine.trim();
|
|
32
|
+
if (trimmedFirstLine.startsWith("#") || trimmedFirstLine.startsWith("-") || trimmedFirstLine.startsWith("*") || trimmedFirstLine.startsWith("+") || trimmedFirstLine.match(/^\d+\./) || trimmedFirstLine.startsWith("```") || trimmedFirstLine.startsWith(">")) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
let paragraph = "";
|
|
36
|
+
for (let i = paragraphStart;i < lines.length; i++) {
|
|
37
|
+
const line = lines[i].trim();
|
|
38
|
+
if (line === "")
|
|
39
|
+
break;
|
|
40
|
+
if (line.startsWith("#") || line.startsWith("```") || line.startsWith(">")) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
paragraph += (paragraph ? " " : "") + line;
|
|
44
|
+
}
|
|
45
|
+
const sentenceMatch = paragraph.match(/^(.+?[.?!])(?:\s|$)/);
|
|
46
|
+
if (!sentenceMatch) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return sentenceMatch[1];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// lib/ideas.ts
|
|
53
|
+
function parseOpenQuestions(content) {
|
|
54
|
+
const lines = content.split(`
|
|
55
|
+
`);
|
|
56
|
+
const questions = [];
|
|
57
|
+
let inOpenQuestions = false;
|
|
58
|
+
let currentQuestion = null;
|
|
59
|
+
let currentOption = null;
|
|
60
|
+
let descriptionLines = [];
|
|
61
|
+
function flushOption() {
|
|
62
|
+
if (currentOption) {
|
|
63
|
+
currentOption.description = descriptionLines.join(`
|
|
64
|
+
`).trim();
|
|
65
|
+
descriptionLines = [];
|
|
66
|
+
currentOption = null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function flushQuestion() {
|
|
70
|
+
flushOption();
|
|
71
|
+
if (currentQuestion) {
|
|
72
|
+
questions.push(currentQuestion);
|
|
73
|
+
currentQuestion = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
if (line.startsWith("## ")) {
|
|
78
|
+
if (inOpenQuestions) {
|
|
79
|
+
flushQuestion();
|
|
80
|
+
}
|
|
81
|
+
inOpenQuestions = line.trimEnd() === "## Open Questions";
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (!inOpenQuestions)
|
|
85
|
+
continue;
|
|
86
|
+
if (line.startsWith("### ")) {
|
|
87
|
+
flushQuestion();
|
|
88
|
+
currentQuestion = {
|
|
89
|
+
question: line.slice(4).trim(),
|
|
90
|
+
options: []
|
|
91
|
+
};
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (line.startsWith("#### ")) {
|
|
95
|
+
flushOption();
|
|
96
|
+
currentOption = {
|
|
97
|
+
name: line.slice(5).trim(),
|
|
98
|
+
description: ""
|
|
99
|
+
};
|
|
100
|
+
if (currentQuestion) {
|
|
101
|
+
currentQuestion.options.push(currentOption);
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (currentOption) {
|
|
106
|
+
descriptionLines.push(line);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
flushQuestion();
|
|
110
|
+
return questions;
|
|
111
|
+
}
|
|
112
|
+
async function parseIdea(fileSystem, dustPath, slug) {
|
|
113
|
+
const ideaPath = `${dustPath}/ideas/${slug}.md`;
|
|
114
|
+
if (!fileSystem.exists(ideaPath)) {
|
|
115
|
+
throw new Error(`Idea not found: "${slug}" (expected file at ${ideaPath})`);
|
|
116
|
+
}
|
|
117
|
+
const content = await fileSystem.readFile(ideaPath);
|
|
118
|
+
const title = extractTitle(content);
|
|
119
|
+
if (!title) {
|
|
120
|
+
throw new Error(`Idea file has no title: ${ideaPath}`);
|
|
121
|
+
}
|
|
122
|
+
const openingSentence = extractOpeningSentence(content);
|
|
123
|
+
const openQuestions = parseOpenQuestions(content);
|
|
124
|
+
return {
|
|
125
|
+
slug,
|
|
126
|
+
title,
|
|
127
|
+
openingSentence,
|
|
128
|
+
content,
|
|
129
|
+
openQuestions
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
parseOpenQuestions,
|
|
134
|
+
parseIdea
|
|
135
|
+
};
|
package/dist/logging/index.d.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Minimal debug logging framework.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* timestamped lines to `<cwd>/log/dust/<scope>.log`.
|
|
4
|
+
* Two independent output channels:
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* - **File logging** — activated by `enableFileLogs(scope)` at command startup.
|
|
7
|
+
* Writes all logs to `./log/<scope>.log` by default. Two env vars control routing:
|
|
8
|
+
*
|
|
9
|
+
* Routing rules for enableFileLogs(scope):
|
|
10
|
+
* 1. If DUST_LOG_FILE is already set (inherited from a parent process such as
|
|
11
|
+
* `dust check`), use that path — all scopes land in the same file.
|
|
12
|
+
* 2. Otherwise compute the path from DUST_LOG_DIR (if set) or `<cwd>/log`, set
|
|
13
|
+
* DUST_LOG_FILE so child processes inherit the same destination, then write there.
|
|
14
|
+
*
|
|
15
|
+
* - **Stdout logging** — activated by `DEBUG=pattern`. Writes matching logs to
|
|
16
|
+
* stdout. Works in any command, regardless of whether file logging is enabled.
|
|
10
17
|
*
|
|
11
18
|
* DEBUG is a comma-separated list of match expressions. Each expression
|
|
12
19
|
* can contain `*` as a wildcard (matches any sequence of characters).
|
|
@@ -21,24 +28,53 @@
|
|
|
21
28
|
* structure under `lib/`. For example, `lib/bucket/repository-loop.ts` uses
|
|
22
29
|
* the logger name `dust.bucket.repository-loop`.
|
|
23
30
|
*
|
|
31
|
+
* ## Per-logger file routing
|
|
32
|
+
*
|
|
33
|
+
* `createLogger(name, { file })` accepts an optional `file` override:
|
|
34
|
+
* - `file: "path/to/file.log"` — route this logger to a dedicated file instead
|
|
35
|
+
* of the global sink set by `enableFileLogs`. The path is resolved relative to
|
|
36
|
+
* the log directory.
|
|
37
|
+
* - `file: false` — suppress file output for this logger entirely, even if
|
|
38
|
+
* `enableFileLogs` has been called. Stdout behavior (DEBUG matching) is
|
|
39
|
+
* unchanged.
|
|
40
|
+
* - When `file` is omitted, the logger uses the global file sink (if any).
|
|
41
|
+
*
|
|
42
|
+
* Sink selection precedence: per-logger sink → global sink → no file sink.
|
|
43
|
+
* File sinks are cached by path so multiple loggers targeting the same file
|
|
44
|
+
* share one sink instance.
|
|
45
|
+
*
|
|
24
46
|
* No external dependencies.
|
|
25
47
|
*/
|
|
26
|
-
import { type
|
|
27
|
-
export { setLogScope } from './sink';
|
|
48
|
+
import { type LogSink } from './sink';
|
|
28
49
|
export type LogFn = (...messages: unknown[]) => void;
|
|
50
|
+
export interface LoggerOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Per-logger file routing override.
|
|
53
|
+
* - `string` — path to a dedicated log file (e.g. `"./log/custom.log"`)
|
|
54
|
+
* - `false` — suppress file output for this logger
|
|
55
|
+
* - `undefined` — use the global file sink from `enableFileLogs` (default)
|
|
56
|
+
*/
|
|
57
|
+
file?: string | false;
|
|
58
|
+
}
|
|
59
|
+
export interface LoggingService {
|
|
60
|
+
enableFileLogs(scope: string, sinkForTesting?: LogSink): void;
|
|
61
|
+
createLogger(name: string, options?: LoggerOptions): LogFn;
|
|
62
|
+
isEnabled(name: string): boolean;
|
|
63
|
+
}
|
|
29
64
|
/**
|
|
30
|
-
* Create
|
|
31
|
-
*
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
65
|
+
* Create an isolated logging service instance. All mutable state is
|
|
66
|
+
* encapsulated inside the returned object.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createLoggingService(): LoggingService;
|
|
69
|
+
/**
|
|
70
|
+
* Activate file logging for this command. See {@link LoggingService.enableFileLogs}.
|
|
35
71
|
*/
|
|
36
|
-
export declare
|
|
72
|
+
export declare const enableFileLogs: LoggingService['enableFileLogs'];
|
|
37
73
|
/**
|
|
38
|
-
*
|
|
74
|
+
* Create a named logger function. See {@link LoggingService.createLogger}.
|
|
39
75
|
*/
|
|
40
|
-
export declare
|
|
76
|
+
export declare const createLogger: LoggingService['createLogger'];
|
|
41
77
|
/**
|
|
42
|
-
*
|
|
78
|
+
* Check whether a logger name would produce stdout output under the current DEBUG value.
|
|
43
79
|
*/
|
|
44
|
-
export declare
|
|
80
|
+
export declare const isEnabled: LoggingService['isEnabled'];
|
package/dist/logging/sink.d.ts
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File-based log sink — the imperative shell for debug logging.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Writes log lines to an arbitrary file path, creating the directory lazily
|
|
5
|
+
* on first write. The path is determined by the caller (enableFileLogs in
|
|
6
|
+
* index.ts) rather than this class.
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export declare
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
export interface LogSink {
|
|
9
|
+
write(line: string): void;
|
|
10
|
+
}
|
|
11
|
+
type AppendFileSyncFn = (path: string, data: string) => void;
|
|
12
|
+
type MkdirSyncFn = (path: string, options: {
|
|
13
|
+
recursive: boolean;
|
|
14
|
+
}) => void;
|
|
15
|
+
export declare class FileSink implements LogSink {
|
|
16
|
+
private readonly logPath;
|
|
17
|
+
private readonly _appendFileSync;
|
|
18
|
+
private readonly _mkdirSync;
|
|
19
|
+
private resolvedPath;
|
|
20
|
+
private ready;
|
|
21
|
+
constructor(logPath: string, _appendFileSync?: AppendFileSyncFn, _mkdirSync?: MkdirSyncFn);
|
|
22
|
+
private ensureLogFile;
|
|
23
|
+
/**
|
|
24
|
+
* Write a line to the log file.
|
|
25
|
+
* Silently no-ops if the file cannot be opened.
|
|
26
|
+
*/
|
|
27
|
+
write(line: string): void;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
package/dist/logging.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// lib/logging/index.ts
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
1
4
|
// lib/logging/match.ts
|
|
2
5
|
function parsePatterns(debug) {
|
|
3
6
|
if (!debug)
|
|
@@ -20,67 +23,108 @@ function formatLine(name, messages) {
|
|
|
20
23
|
|
|
21
24
|
// lib/logging/sink.ts
|
|
22
25
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ready = true;
|
|
31
|
-
const dir = join(process.cwd(), "log", "dust");
|
|
32
|
-
logPath = join(dir, `${scope}.log`);
|
|
33
|
-
try {
|
|
34
|
-
mkdirSync(dir, { recursive: true });
|
|
35
|
-
} catch {
|
|
36
|
-
logPath = undefined;
|
|
37
|
-
}
|
|
38
|
-
return logPath;
|
|
39
|
-
}
|
|
40
|
-
function setLogScope(name) {
|
|
41
|
-
scope = name;
|
|
42
|
-
process.env.DEBUG_LOG_SCOPE = name;
|
|
43
|
-
logPath = undefined;
|
|
26
|
+
import { dirname } from "node:path";
|
|
27
|
+
|
|
28
|
+
class FileSink {
|
|
29
|
+
logPath;
|
|
30
|
+
_appendFileSync;
|
|
31
|
+
_mkdirSync;
|
|
32
|
+
resolvedPath;
|
|
44
33
|
ready = false;
|
|
34
|
+
constructor(logPath, _appendFileSync = appendFileSync, _mkdirSync = mkdirSync) {
|
|
35
|
+
this.logPath = logPath;
|
|
36
|
+
this._appendFileSync = _appendFileSync;
|
|
37
|
+
this._mkdirSync = _mkdirSync;
|
|
38
|
+
}
|
|
39
|
+
ensureLogFile() {
|
|
40
|
+
if (this.ready)
|
|
41
|
+
return this.resolvedPath;
|
|
42
|
+
this.ready = true;
|
|
43
|
+
this.resolvedPath = this.logPath;
|
|
44
|
+
try {
|
|
45
|
+
this._mkdirSync(dirname(this.logPath), { recursive: true });
|
|
46
|
+
} catch {
|
|
47
|
+
this.resolvedPath = undefined;
|
|
48
|
+
}
|
|
49
|
+
return this.resolvedPath;
|
|
50
|
+
}
|
|
51
|
+
write(line) {
|
|
52
|
+
const path = this.ensureLogFile();
|
|
53
|
+
if (!path)
|
|
54
|
+
return;
|
|
55
|
+
try {
|
|
56
|
+
this._appendFileSync(path, line);
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
45
59
|
}
|
|
46
|
-
var writeToFile = (line) => {
|
|
47
|
-
const path = ensureLogFile();
|
|
48
|
-
if (!path)
|
|
49
|
-
return;
|
|
50
|
-
try {
|
|
51
|
-
appendFileSync(path, line);
|
|
52
|
-
} catch {}
|
|
53
|
-
};
|
|
54
60
|
|
|
55
61
|
// lib/logging/index.ts
|
|
56
|
-
var
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
function createLogger(name, write = writeToFile) {
|
|
66
|
-
return (...messages) => {
|
|
67
|
-
init();
|
|
68
|
-
if (!patterns || !matchesAny(name, patterns))
|
|
62
|
+
var DUST_LOG_FILE = "DUST_LOG_FILE";
|
|
63
|
+
function createLoggingService() {
|
|
64
|
+
let patterns = null;
|
|
65
|
+
let initialized = false;
|
|
66
|
+
let activeFileSink = null;
|
|
67
|
+
const fileSinkCache = new Map;
|
|
68
|
+
function init() {
|
|
69
|
+
if (initialized)
|
|
69
70
|
return;
|
|
70
|
-
|
|
71
|
+
initialized = true;
|
|
72
|
+
const parsed = parsePatterns(process.env.DEBUG);
|
|
73
|
+
patterns = parsed.length > 0 ? parsed : null;
|
|
74
|
+
}
|
|
75
|
+
function getOrCreateFileSink(path) {
|
|
76
|
+
let sink = fileSinkCache.get(path);
|
|
77
|
+
if (!sink) {
|
|
78
|
+
sink = new FileSink(path);
|
|
79
|
+
fileSinkCache.set(path, sink);
|
|
80
|
+
}
|
|
81
|
+
return sink;
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
enableFileLogs(scope, sinkForTesting) {
|
|
85
|
+
const existing = process.env[DUST_LOG_FILE];
|
|
86
|
+
const logDir = process.env.DUST_LOG_DIR ?? join(process.cwd(), "log");
|
|
87
|
+
const path = existing ?? join(logDir, `${scope}.log`);
|
|
88
|
+
if (!existing) {
|
|
89
|
+
process.env[DUST_LOG_FILE] = path;
|
|
90
|
+
}
|
|
91
|
+
activeFileSink = sinkForTesting ?? new FileSink(path);
|
|
92
|
+
},
|
|
93
|
+
createLogger(name, options) {
|
|
94
|
+
let perLoggerSink;
|
|
95
|
+
if (options?.file === false) {
|
|
96
|
+
perLoggerSink = null;
|
|
97
|
+
} else if (typeof options?.file === "string") {
|
|
98
|
+
perLoggerSink = getOrCreateFileSink(options.file);
|
|
99
|
+
}
|
|
100
|
+
return (...messages) => {
|
|
101
|
+
init();
|
|
102
|
+
const line = formatLine(name, messages);
|
|
103
|
+
if (perLoggerSink !== undefined) {
|
|
104
|
+
if (perLoggerSink !== null) {
|
|
105
|
+
perLoggerSink.write(line);
|
|
106
|
+
}
|
|
107
|
+
} else if (activeFileSink) {
|
|
108
|
+
activeFileSink.write(line);
|
|
109
|
+
}
|
|
110
|
+
if (patterns && matchesAny(name, patterns)) {
|
|
111
|
+
process.stdout.write(line);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
isEnabled(name) {
|
|
116
|
+
init();
|
|
117
|
+
return patterns !== null && matchesAny(name, patterns);
|
|
118
|
+
}
|
|
71
119
|
};
|
|
72
120
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
function _reset() {
|
|
78
|
-
initialized = false;
|
|
79
|
-
patterns = null;
|
|
80
|
-
}
|
|
121
|
+
var defaultService = createLoggingService();
|
|
122
|
+
var enableFileLogs = defaultService.enableFileLogs.bind(defaultService);
|
|
123
|
+
var createLogger = defaultService.createLogger.bind(defaultService);
|
|
124
|
+
var isEnabled = defaultService.isEnabled.bind(defaultService);
|
|
81
125
|
export {
|
|
82
|
-
setLogScope,
|
|
83
126
|
isEnabled,
|
|
84
|
-
|
|
85
|
-
|
|
127
|
+
enableFileLogs,
|
|
128
|
+
createLoggingService,
|
|
129
|
+
createLogger
|
|
86
130
|
};
|
|
@@ -21,25 +21,36 @@ function formatMetrics(metrics) {
|
|
|
21
21
|
return parts.join(', ')
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function
|
|
24
|
+
function getGapLines(fileCoverage) {
|
|
25
|
+
const gapLines = new Set()
|
|
26
|
+
|
|
25
27
|
const lineCoverage = fileCoverage.getLineCoverage()
|
|
28
|
+
for (const [lineStr, hits] of Object.entries(lineCoverage)) {
|
|
29
|
+
if (hits === 0) gapLines.add(Number.parseInt(lineStr, 10))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { branchMap, b } = fileCoverage
|
|
33
|
+
for (const [id, branch] of Object.entries(branchMap)) {
|
|
34
|
+
if (b[id].some(hits => hits === 0)) {
|
|
35
|
+
gapLines.add(branch.loc.start.line)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const sorted = [...gapLines].sort((a, b) => a - b)
|
|
26
40
|
const ranges = []
|
|
27
41
|
let rangeStart = null
|
|
28
42
|
let rangeEnd = null
|
|
29
43
|
|
|
30
|
-
for (const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
rangeStart = line
|
|
41
|
-
rangeEnd = line
|
|
42
|
-
}
|
|
44
|
+
for (const line of sorted) {
|
|
45
|
+
if (rangeStart === null) {
|
|
46
|
+
rangeStart = line
|
|
47
|
+
rangeEnd = line
|
|
48
|
+
} else if (line === rangeEnd + 1) {
|
|
49
|
+
rangeEnd = line
|
|
50
|
+
} else {
|
|
51
|
+
ranges.push([rangeStart, rangeEnd])
|
|
52
|
+
rangeStart = line
|
|
53
|
+
rangeEnd = line
|
|
43
54
|
}
|
|
44
55
|
}
|
|
45
56
|
|
|
@@ -68,7 +79,12 @@ class IncompleteCoverageReporter extends ReportBase {
|
|
|
68
79
|
},
|
|
69
80
|
})
|
|
70
81
|
|
|
71
|
-
if (incompleteFiles.length === 0)
|
|
82
|
+
if (incompleteFiles.length === 0) {
|
|
83
|
+
const cw = context.writer.writeFile(null)
|
|
84
|
+
cw.println('✔ 100% coverage!')
|
|
85
|
+
cw.close()
|
|
86
|
+
return
|
|
87
|
+
}
|
|
72
88
|
|
|
73
89
|
const cw = context.writer.writeFile(null)
|
|
74
90
|
const count = incompleteFiles.length
|
|
@@ -78,7 +94,7 @@ class IncompleteCoverageReporter extends ReportBase {
|
|
|
78
94
|
for (const file of incompleteFiles) {
|
|
79
95
|
cw.println('')
|
|
80
96
|
cw.println(`${file.name} (${formatMetrics(file.metrics)})`)
|
|
81
|
-
for (const line of
|
|
97
|
+
for (const line of getGapLines(file.fileCoverage)) {
|
|
82
98
|
cw.println(`- ${line}`)
|
|
83
99
|
}
|
|
84
100
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joshski/dust",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.58",
|
|
4
4
|
"description": "Flow state for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"import": "./dist/agents.js",
|
|
23
23
|
"types": "./dist/agents/detection.d.ts"
|
|
24
24
|
},
|
|
25
|
+
"./ideas": {
|
|
26
|
+
"import": "./dist/ideas.js",
|
|
27
|
+
"types": "./dist/ideas.d.ts"
|
|
28
|
+
},
|
|
25
29
|
"./istanbul/minimal-reporter": "./lib/istanbul/minimal-reporter.cjs"
|
|
26
30
|
},
|
|
27
31
|
"files": [
|
|
@@ -42,7 +46,7 @@
|
|
|
42
46
|
"author": "joshski",
|
|
43
47
|
"license": "MIT",
|
|
44
48
|
"scripts": {
|
|
45
|
-
"build": "bun build lib/cli/run.ts --target node --outfile dist/dust.js && printf '%s\\n%s' '#!/usr/bin/env node' \"$(cat dist/dust.js)\" > dist/dust.js && bun build lib/workflow-tasks.ts --target node --outfile dist/workflow-tasks.js && bun build lib/logging/index.ts --target node --outfile dist/logging.js && bun build lib/agents/detection.ts --target node --outfile dist/agents.js && bunx tsc --project tsconfig.build.json",
|
|
49
|
+
"build": "bun build lib/cli/run.ts --target node --outfile dist/dust.js && printf '%s\\n%s' '#!/usr/bin/env node' \"$(cat dist/dust.js)\" > dist/dust.js && bun build lib/workflow-tasks.ts --target node --outfile dist/workflow-tasks.js && bun build lib/logging/index.ts --target node --outfile dist/logging.js && bun build lib/agents/detection.ts --target node --outfile dist/agents.js && bun build lib/ideas.ts --target node --outfile dist/ideas.js && bunx tsc --project tsconfig.build.json",
|
|
46
50
|
"test": "vitest run",
|
|
47
51
|
"test:coverage": "vitest run --coverage",
|
|
48
52
|
"eval": "bun run ./evals/run.ts"
|