@joshski/dust 0.1.75 → 0.1.76
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/audits.js +60 -0
- package/dist/dust.js +94 -23
- package/package.json +1 -1
package/dist/audits.js
CHANGED
|
@@ -719,6 +719,65 @@ function repositoryContext() {
|
|
|
719
719
|
- [ ] A new agent reading only this document could make sensible high-level suggestions
|
|
720
720
|
`;
|
|
721
721
|
}
|
|
722
|
+
function slowTests() {
|
|
723
|
+
return dedent`
|
|
724
|
+
# Slow Tests
|
|
725
|
+
|
|
726
|
+
Identify slow-running tests that impact feedback loop speed.
|
|
727
|
+
|
|
728
|
+
${ideasHint}
|
|
729
|
+
|
|
730
|
+
## Scope
|
|
731
|
+
|
|
732
|
+
Focus on these areas:
|
|
733
|
+
|
|
734
|
+
1. **Test execution times** - Identify tests that exceed a reasonable duration threshold (e.g., 100ms for unit tests, 1s for integration tests)
|
|
735
|
+
2. **I/O-bound tests** - Tests that perform actual file system, network, or database operations
|
|
736
|
+
3. **Sleep/delay usage** - Tests using \`setTimeout\`, \`sleep\`, or similar timing functions
|
|
737
|
+
4. **Missing mocks** - Tests that make real HTTP requests or database calls instead of using stubs
|
|
738
|
+
5. **Setup overhead** - Expensive \`beforeEach\`/\`beforeAll\` setup that could be optimized or shared
|
|
739
|
+
6. **Serial test execution** - Tests that could run in parallel but are forced to run serially
|
|
740
|
+
|
|
741
|
+
## Analysis Steps
|
|
742
|
+
|
|
743
|
+
1. Run the test suite with timing output: \`npm test -- --reporter=verbose\` or equivalent
|
|
744
|
+
2. Identify tests taking longer than the threshold (100ms+ for unit, 1s+ for integration)
|
|
745
|
+
3. Search for \`setTimeout\`, \`sleep\`, \`delay\`, and similar timing patterns in test files
|
|
746
|
+
4. Look for real I/O: \`fetch\`, \`axios\`, database clients, file system operations without mocks
|
|
747
|
+
5. Review \`beforeEach\`/\`beforeAll\` blocks for expensive operations
|
|
748
|
+
6. Check test configuration for parallelization settings
|
|
749
|
+
|
|
750
|
+
## Output
|
|
751
|
+
|
|
752
|
+
For each slow test identified, provide:
|
|
753
|
+
- **Test name** - The describe/it block name
|
|
754
|
+
- **File path** - Location of the test
|
|
755
|
+
- **Duration** - How long the test takes (if measurable)
|
|
756
|
+
- **Cause** - Why the test is slow (I/O, sleep, setup, etc.)
|
|
757
|
+
- **Suggestion** - Specific optimization (mock the API, use fake timers, share setup, etc.)
|
|
758
|
+
|
|
759
|
+
## Principles
|
|
760
|
+
|
|
761
|
+
- [Fast Feedback Loops](../principles/fast-feedback-loops.md) - Tests should run quickly for tight iteration cycles
|
|
762
|
+
- [Fast Feedback](../principles/fast-feedback.md) - Slow tests discourage frequent validation
|
|
763
|
+
- [Keep Unit Tests Pure](../principles/keep-unit-tests-pure.md) - Pure tests are faster and more reliable
|
|
764
|
+
- [Stubs Over Mocks](../principles/stubs-over-mocks.md) - Use stubs to avoid slow real dependencies
|
|
765
|
+
|
|
766
|
+
## Blocked By
|
|
767
|
+
|
|
768
|
+
(none)
|
|
769
|
+
|
|
770
|
+
## Definition of Done
|
|
771
|
+
|
|
772
|
+
- [ ] Ran test suite with timing information
|
|
773
|
+
- [ ] Listed tests exceeding duration thresholds (100ms unit, 1s integration)
|
|
774
|
+
- [ ] Identified tests using sleep/setTimeout/delay patterns
|
|
775
|
+
- [ ] Found tests with unmocked I/O (network, database, file system)
|
|
776
|
+
- [ ] Reviewed beforeEach/beforeAll for optimization opportunities
|
|
777
|
+
- [ ] Checked test parallelization configuration
|
|
778
|
+
- [ ] Proposed ideas for optimizing the slowest tests
|
|
779
|
+
`;
|
|
780
|
+
}
|
|
722
781
|
function ubiquitousLanguage() {
|
|
723
782
|
return dedent`
|
|
724
783
|
# Ubiquitous Language
|
|
@@ -787,6 +846,7 @@ var stockAuditFunctions = {
|
|
|
787
846
|
"refactoring-opportunities": refactoringOpportunities,
|
|
788
847
|
"repository-context": repositoryContext,
|
|
789
848
|
"security-review": securityReview,
|
|
849
|
+
"slow-tests": slowTests,
|
|
790
850
|
"stale-ideas": staleIdeas,
|
|
791
851
|
"test-coverage": testCoverage,
|
|
792
852
|
"ubiquitous-language": ubiquitousLanguage
|
package/dist/dust.js
CHANGED
|
@@ -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.76";
|
|
279
279
|
|
|
280
280
|
// lib/session.ts
|
|
281
281
|
var DUST_UNATTENDED = "DUST_UNATTENDED";
|
|
@@ -1266,6 +1266,65 @@ function repositoryContext() {
|
|
|
1266
1266
|
- [ ] A new agent reading only this document could make sensible high-level suggestions
|
|
1267
1267
|
`;
|
|
1268
1268
|
}
|
|
1269
|
+
function slowTests() {
|
|
1270
|
+
return dedent`
|
|
1271
|
+
# Slow Tests
|
|
1272
|
+
|
|
1273
|
+
Identify slow-running tests that impact feedback loop speed.
|
|
1274
|
+
|
|
1275
|
+
${ideasHint}
|
|
1276
|
+
|
|
1277
|
+
## Scope
|
|
1278
|
+
|
|
1279
|
+
Focus on these areas:
|
|
1280
|
+
|
|
1281
|
+
1. **Test execution times** - Identify tests that exceed a reasonable duration threshold (e.g., 100ms for unit tests, 1s for integration tests)
|
|
1282
|
+
2. **I/O-bound tests** - Tests that perform actual file system, network, or database operations
|
|
1283
|
+
3. **Sleep/delay usage** - Tests using \`setTimeout\`, \`sleep\`, or similar timing functions
|
|
1284
|
+
4. **Missing mocks** - Tests that make real HTTP requests or database calls instead of using stubs
|
|
1285
|
+
5. **Setup overhead** - Expensive \`beforeEach\`/\`beforeAll\` setup that could be optimized or shared
|
|
1286
|
+
6. **Serial test execution** - Tests that could run in parallel but are forced to run serially
|
|
1287
|
+
|
|
1288
|
+
## Analysis Steps
|
|
1289
|
+
|
|
1290
|
+
1. Run the test suite with timing output: \`npm test -- --reporter=verbose\` or equivalent
|
|
1291
|
+
2. Identify tests taking longer than the threshold (100ms+ for unit, 1s+ for integration)
|
|
1292
|
+
3. Search for \`setTimeout\`, \`sleep\`, \`delay\`, and similar timing patterns in test files
|
|
1293
|
+
4. Look for real I/O: \`fetch\`, \`axios\`, database clients, file system operations without mocks
|
|
1294
|
+
5. Review \`beforeEach\`/\`beforeAll\` blocks for expensive operations
|
|
1295
|
+
6. Check test configuration for parallelization settings
|
|
1296
|
+
|
|
1297
|
+
## Output
|
|
1298
|
+
|
|
1299
|
+
For each slow test identified, provide:
|
|
1300
|
+
- **Test name** - The describe/it block name
|
|
1301
|
+
- **File path** - Location of the test
|
|
1302
|
+
- **Duration** - How long the test takes (if measurable)
|
|
1303
|
+
- **Cause** - Why the test is slow (I/O, sleep, setup, etc.)
|
|
1304
|
+
- **Suggestion** - Specific optimization (mock the API, use fake timers, share setup, etc.)
|
|
1305
|
+
|
|
1306
|
+
## Principles
|
|
1307
|
+
|
|
1308
|
+
- [Fast Feedback Loops](../principles/fast-feedback-loops.md) - Tests should run quickly for tight iteration cycles
|
|
1309
|
+
- [Fast Feedback](../principles/fast-feedback.md) - Slow tests discourage frequent validation
|
|
1310
|
+
- [Keep Unit Tests Pure](../principles/keep-unit-tests-pure.md) - Pure tests are faster and more reliable
|
|
1311
|
+
- [Stubs Over Mocks](../principles/stubs-over-mocks.md) - Use stubs to avoid slow real dependencies
|
|
1312
|
+
|
|
1313
|
+
## Blocked By
|
|
1314
|
+
|
|
1315
|
+
(none)
|
|
1316
|
+
|
|
1317
|
+
## Definition of Done
|
|
1318
|
+
|
|
1319
|
+
- [ ] Ran test suite with timing information
|
|
1320
|
+
- [ ] Listed tests exceeding duration thresholds (100ms unit, 1s integration)
|
|
1321
|
+
- [ ] Identified tests using sleep/setTimeout/delay patterns
|
|
1322
|
+
- [ ] Found tests with unmocked I/O (network, database, file system)
|
|
1323
|
+
- [ ] Reviewed beforeEach/beforeAll for optimization opportunities
|
|
1324
|
+
- [ ] Checked test parallelization configuration
|
|
1325
|
+
- [ ] Proposed ideas for optimizing the slowest tests
|
|
1326
|
+
`;
|
|
1327
|
+
}
|
|
1269
1328
|
function ubiquitousLanguage() {
|
|
1270
1329
|
return dedent`
|
|
1271
1330
|
# Ubiquitous Language
|
|
@@ -1334,6 +1393,7 @@ var stockAuditFunctions = {
|
|
|
1334
1393
|
"refactoring-opportunities": refactoringOpportunities,
|
|
1335
1394
|
"repository-context": repositoryContext,
|
|
1336
1395
|
"security-review": securityReview,
|
|
1396
|
+
"slow-tests": slowTests,
|
|
1337
1397
|
"stale-ideas": staleIdeas,
|
|
1338
1398
|
"test-coverage": testCoverage,
|
|
1339
1399
|
"ubiquitous-language": ubiquitousLanguage
|
|
@@ -2264,7 +2324,8 @@ function getRepoPath(repoName, reposDir) {
|
|
|
2264
2324
|
async function cloneRepository(repository, targetPath, spawn, context) {
|
|
2265
2325
|
return new Promise((resolve) => {
|
|
2266
2326
|
const proc = spawn("git", ["clone", repository.gitUrl, targetPath], {
|
|
2267
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
2327
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2328
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
2268
2329
|
});
|
|
2269
2330
|
let stderr = "";
|
|
2270
2331
|
proc.stderr?.on("data", (data) => {
|
|
@@ -2488,26 +2549,26 @@ function getEnvironmentContext(cwd) {
|
|
|
2488
2549
|
function formatLoopEvent(event) {
|
|
2489
2550
|
switch (event.type) {
|
|
2490
2551
|
case "loop.warning":
|
|
2491
|
-
return "
|
|
2552
|
+
return "WARNING: This command skips all permission checks. Only use in a sandbox environment!";
|
|
2492
2553
|
case "loop.started": {
|
|
2493
2554
|
const agent2 = event.agentType ?? "claude";
|
|
2494
|
-
return
|
|
2555
|
+
return `Starting dust loop ${agent2} (max ${event.maxIterations} iterations)...`;
|
|
2495
2556
|
}
|
|
2496
2557
|
case "loop.syncing":
|
|
2497
|
-
return "
|
|
2558
|
+
return "Syncing with remote";
|
|
2498
2559
|
case "loop.sync_skipped":
|
|
2499
2560
|
return `Note: git pull skipped (${event.reason})`;
|
|
2500
2561
|
case "loop.checking_tasks":
|
|
2501
2562
|
return null;
|
|
2502
2563
|
case "loop.no_tasks":
|
|
2503
|
-
return "
|
|
2564
|
+
return "No tasks available. Sleeping...";
|
|
2504
2565
|
case "loop.tasks_found":
|
|
2505
|
-
return
|
|
2566
|
+
return `Found a task. Going to work!
|
|
2506
2567
|
`;
|
|
2507
2568
|
case "loop.iteration_complete":
|
|
2508
|
-
return
|
|
2569
|
+
return `Completed iteration ${event.iteration}/${event.maxIterations}`;
|
|
2509
2570
|
case "loop.ended":
|
|
2510
|
-
return
|
|
2571
|
+
return `Reached max iterations (${event.maxIterations}). Exiting.`;
|
|
2511
2572
|
}
|
|
2512
2573
|
}
|
|
2513
2574
|
function createPostEvent(fetchFn) {
|
|
@@ -2565,7 +2626,8 @@ async function gitPull(cwd, spawn) {
|
|
|
2565
2626
|
return new Promise((resolve) => {
|
|
2566
2627
|
const proc = spawn("git", ["pull"], {
|
|
2567
2628
|
cwd,
|
|
2568
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
2629
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2630
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
2569
2631
|
});
|
|
2570
2632
|
let stderr = "";
|
|
2571
2633
|
proc.stderr?.on("data", (data) => {
|
|
@@ -3115,6 +3177,15 @@ function parseServerMessage(data) {
|
|
|
3115
3177
|
}
|
|
3116
3178
|
|
|
3117
3179
|
// lib/bucket/terminal-ui.ts
|
|
3180
|
+
var CHARS = {
|
|
3181
|
+
dot: "*",
|
|
3182
|
+
sparkle: "",
|
|
3183
|
+
ellipsis: "...",
|
|
3184
|
+
hline: "-",
|
|
3185
|
+
arrows_lr: "<->",
|
|
3186
|
+
arrows_ud: "up/dn",
|
|
3187
|
+
scroll_down: "v"
|
|
3188
|
+
};
|
|
3118
3189
|
var ANSI = {
|
|
3119
3190
|
HIDE_CURSOR: "\x1B[?25l",
|
|
3120
3191
|
SHOW_CURSOR: "\x1B[?25h",
|
|
@@ -3169,8 +3240,8 @@ function truncateLine(text, maxWidth) {
|
|
|
3169
3240
|
for (let match = ansiRegex.exec(text);match !== null; match = ansiRegex.exec(text)) {
|
|
3170
3241
|
const textBefore = text.slice(lastIndex, match.index);
|
|
3171
3242
|
for (const char of textBefore) {
|
|
3172
|
-
if (visibleCount >= maxWidth -
|
|
3173
|
-
result +=
|
|
3243
|
+
if (visibleCount >= maxWidth - CHARS.ellipsis.length) {
|
|
3244
|
+
result += CHARS.ellipsis;
|
|
3174
3245
|
return result + ANSI.RESET;
|
|
3175
3246
|
}
|
|
3176
3247
|
result += char;
|
|
@@ -3181,8 +3252,8 @@ function truncateLine(text, maxWidth) {
|
|
|
3181
3252
|
}
|
|
3182
3253
|
const remaining = text.slice(lastIndex);
|
|
3183
3254
|
for (const char of remaining) {
|
|
3184
|
-
if (visibleCount >= maxWidth -
|
|
3185
|
-
result +=
|
|
3255
|
+
if (visibleCount >= maxWidth - CHARS.ellipsis.length) {
|
|
3256
|
+
result += CHARS.ellipsis;
|
|
3186
3257
|
return result + ANSI.RESET;
|
|
3187
3258
|
}
|
|
3188
3259
|
result += char;
|
|
@@ -3282,7 +3353,7 @@ function getTabRowCount(state) {
|
|
|
3282
3353
|
return 1;
|
|
3283
3354
|
const tabWidths = [5];
|
|
3284
3355
|
for (const name of state.repositories) {
|
|
3285
|
-
tabWidths.push(name.length +
|
|
3356
|
+
tabWidths.push(name.length + 2 + CHARS.dot.length + 1);
|
|
3286
3357
|
}
|
|
3287
3358
|
let rows = 1;
|
|
3288
3359
|
let currentRowWidth = 0;
|
|
@@ -3352,8 +3423,8 @@ function renderTabs(state) {
|
|
|
3352
3423
|
const color = getRepoColor(name, i);
|
|
3353
3424
|
const agentStatus = state.agentStatuses.get(name) ?? "idle";
|
|
3354
3425
|
const dotColor = agentStatus === "busy" ? ANSI.FG_GREEN : ANSI.DIM;
|
|
3355
|
-
const dot = `${dotColor}
|
|
3356
|
-
const width = name.length +
|
|
3426
|
+
const dot = `${dotColor}${CHARS.dot}${ANSI.RESET}`;
|
|
3427
|
+
const width = name.length + 2 + CHARS.dot.length + 1;
|
|
3357
3428
|
if (i === state.selectedIndex) {
|
|
3358
3429
|
tabs.push({
|
|
3359
3430
|
text: ` ${dot}${color} ${ANSI.INVERSE}${name}${ANSI.RESET} `,
|
|
@@ -3378,10 +3449,10 @@ function renderTabs(state) {
|
|
|
3378
3449
|
return rows.map((row) => row.map((t) => t.text).join("|"));
|
|
3379
3450
|
}
|
|
3380
3451
|
function renderHelpLine() {
|
|
3381
|
-
return `${ANSI.DIM}[
|
|
3452
|
+
return `${ANSI.DIM}[${CHARS.arrows_lr}] select [${CHARS.arrows_ud}] scroll [PgUp/PgDn] page [g/G] top/bottom [o] open [q] quit${ANSI.RESET}`;
|
|
3382
3453
|
}
|
|
3383
3454
|
function renderSeparator(width) {
|
|
3384
|
-
return
|
|
3455
|
+
return CHARS.hline.repeat(Math.max(0, width));
|
|
3385
3456
|
}
|
|
3386
3457
|
function formatLogLine(line, prefixAlign, maxWidth) {
|
|
3387
3458
|
let prefix = "";
|
|
@@ -3413,7 +3484,7 @@ function formatLogLine(line, prefixAlign, maxWidth) {
|
|
|
3413
3484
|
function renderFrame(state) {
|
|
3414
3485
|
const lines = [];
|
|
3415
3486
|
const hostLabel = state.connectedHost ? ` ${ANSI.DIM}[connected to ${state.connectedHost}]${ANSI.RESET}` : "";
|
|
3416
|
-
lines.push(`${ANSI.BOLD}
|
|
3487
|
+
lines.push(`${ANSI.BOLD}${CHARS.sparkle}dust bucket${ANSI.RESET}${hostLabel}`);
|
|
3417
3488
|
const tabRows = renderTabs(state);
|
|
3418
3489
|
for (const tabRow of tabRows) {
|
|
3419
3490
|
lines.push(tabRow);
|
|
@@ -3436,7 +3507,7 @@ function renderFrame(state) {
|
|
|
3436
3507
|
lines.push("");
|
|
3437
3508
|
}
|
|
3438
3509
|
if (state.scrollOffset > 0) {
|
|
3439
|
-
const indicator = `${ANSI.DIM}
|
|
3510
|
+
const indicator = `${ANSI.DIM}${CHARS.scroll_down} ${state.scrollOffset} more${ANSI.RESET}`;
|
|
3440
3511
|
lines[lines.length - 1] = indicator;
|
|
3441
3512
|
}
|
|
3442
3513
|
const output = [];
|
|
@@ -3584,8 +3655,8 @@ function defaultSetupResize(onResize) {
|
|
|
3584
3655
|
}
|
|
3585
3656
|
function defaultGetTerminalSize() {
|
|
3586
3657
|
return {
|
|
3587
|
-
width: process.stdout.columns
|
|
3588
|
-
height: process.stdout.rows
|
|
3658
|
+
width: process.stdout.columns || 80,
|
|
3659
|
+
height: process.stdout.rows || 24
|
|
3589
3660
|
};
|
|
3590
3661
|
}
|
|
3591
3662
|
function defaultWriteStdout(data) {
|