@joshski/dust 0.1.74 → 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.
Files changed (3) hide show
  1. package/dist/audits.js +110 -0
  2. package/dist/dust.js +144 -23
  3. package/package.json +1 -1
package/dist/audits.js CHANGED
@@ -670,6 +670,114 @@ function globalState() {
670
670
  - [ ] Proposed ideas for refactoring global state to explicit dependencies
671
671
  `;
672
672
  }
673
+ function repositoryContext() {
674
+ return dedent`
675
+ # Repository Context
676
+
677
+ Compile or update \`.dust/repository.md\` with a high-level overview of the repository's purpose, capabilities, and design philosophy.
678
+
679
+ ## Purpose
680
+
681
+ The repository context document helps downstream agents quickly understand the project without reading individual files. It describes features, scenarios, and design philosophy rather than implementation details. This enables high-level planning where agents reason about capabilities rather than code structure.
682
+
683
+ ## Scope
684
+
685
+ Review the current state of the codebase and produce a document covering:
686
+
687
+ 1. **What the project is** - A one-sentence summary of its purpose
688
+ 2. **What it does** - The key capabilities and features it provides
689
+ 3. **How it fits into workflows** - How users or other systems interact with it
690
+ 4. **Design philosophy** - The guiding principles behind its architecture
691
+ 5. **Key scenarios** - The main use cases or user journeys it supports
692
+
693
+ Avoid mentioning specific file paths, class names, or implementation details. Write for someone who needs to make high-level suggestions about the project's direction, not someone about to edit a specific file.
694
+
695
+ ## Analysis Steps
696
+
697
+ 1. Read the existing \`.dust/repository.md\` if it exists
698
+ 2. Review README, package.json, and top-level documentation for project purpose
699
+ 3. Scan the codebase to understand features and capabilities
700
+ 4. Review \`.dust/principles/\` for design philosophy
701
+ 5. Review \`.dust/facts/\` for context on current state
702
+ 6. Update \`.dust/repository.md\` with current findings, preserving any sections that are still accurate
703
+
704
+ ## Principles
705
+
706
+ (none)
707
+
708
+ ## Blocked By
709
+
710
+ (none)
711
+
712
+ ## Definition of Done
713
+
714
+ - [ ] \`.dust/repository.md\` exists and is up to date
715
+ - [ ] Document describes what the project does without referencing specific files
716
+ - [ ] Key capabilities and features are listed
717
+ - [ ] Design philosophy or guiding approach is captured
718
+ - [ ] Document is concise enough to fit comfortably in an agent context window
719
+ - [ ] A new agent reading only this document could make sensible high-level suggestions
720
+ `;
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
+ }
673
781
  function ubiquitousLanguage() {
674
782
  return dedent`
675
783
  # Ubiquitous Language
@@ -736,7 +844,9 @@ var stockAuditFunctions = {
736
844
  "ideas-from-principles": ideasFromPrinciples,
737
845
  "performance-review": performanceReview,
738
846
  "refactoring-opportunities": refactoringOpportunities,
847
+ "repository-context": repositoryContext,
739
848
  "security-review": securityReview,
849
+ "slow-tests": slowTests,
740
850
  "stale-ideas": staleIdeas,
741
851
  "test-coverage": testCoverage,
742
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.74";
278
+ var DUST_VERSION = "0.1.76";
279
279
 
280
280
  // lib/session.ts
281
281
  var DUST_UNATTENDED = "DUST_UNATTENDED";
@@ -1217,6 +1217,114 @@ function globalState() {
1217
1217
  - [ ] Proposed ideas for refactoring global state to explicit dependencies
1218
1218
  `;
1219
1219
  }
1220
+ function repositoryContext() {
1221
+ return dedent`
1222
+ # Repository Context
1223
+
1224
+ Compile or update \`.dust/repository.md\` with a high-level overview of the repository's purpose, capabilities, and design philosophy.
1225
+
1226
+ ## Purpose
1227
+
1228
+ The repository context document helps downstream agents quickly understand the project without reading individual files. It describes features, scenarios, and design philosophy rather than implementation details. This enables high-level planning where agents reason about capabilities rather than code structure.
1229
+
1230
+ ## Scope
1231
+
1232
+ Review the current state of the codebase and produce a document covering:
1233
+
1234
+ 1. **What the project is** - A one-sentence summary of its purpose
1235
+ 2. **What it does** - The key capabilities and features it provides
1236
+ 3. **How it fits into workflows** - How users or other systems interact with it
1237
+ 4. **Design philosophy** - The guiding principles behind its architecture
1238
+ 5. **Key scenarios** - The main use cases or user journeys it supports
1239
+
1240
+ Avoid mentioning specific file paths, class names, or implementation details. Write for someone who needs to make high-level suggestions about the project's direction, not someone about to edit a specific file.
1241
+
1242
+ ## Analysis Steps
1243
+
1244
+ 1. Read the existing \`.dust/repository.md\` if it exists
1245
+ 2. Review README, package.json, and top-level documentation for project purpose
1246
+ 3. Scan the codebase to understand features and capabilities
1247
+ 4. Review \`.dust/principles/\` for design philosophy
1248
+ 5. Review \`.dust/facts/\` for context on current state
1249
+ 6. Update \`.dust/repository.md\` with current findings, preserving any sections that are still accurate
1250
+
1251
+ ## Principles
1252
+
1253
+ (none)
1254
+
1255
+ ## Blocked By
1256
+
1257
+ (none)
1258
+
1259
+ ## Definition of Done
1260
+
1261
+ - [ ] \`.dust/repository.md\` exists and is up to date
1262
+ - [ ] Document describes what the project does without referencing specific files
1263
+ - [ ] Key capabilities and features are listed
1264
+ - [ ] Design philosophy or guiding approach is captured
1265
+ - [ ] Document is concise enough to fit comfortably in an agent context window
1266
+ - [ ] A new agent reading only this document could make sensible high-level suggestions
1267
+ `;
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
+ }
1220
1328
  function ubiquitousLanguage() {
1221
1329
  return dedent`
1222
1330
  # Ubiquitous Language
@@ -1283,7 +1391,9 @@ var stockAuditFunctions = {
1283
1391
  "ideas-from-principles": ideasFromPrinciples,
1284
1392
  "performance-review": performanceReview,
1285
1393
  "refactoring-opportunities": refactoringOpportunities,
1394
+ "repository-context": repositoryContext,
1286
1395
  "security-review": securityReview,
1396
+ "slow-tests": slowTests,
1287
1397
  "stale-ideas": staleIdeas,
1288
1398
  "test-coverage": testCoverage,
1289
1399
  "ubiquitous-language": ubiquitousLanguage
@@ -2214,7 +2324,8 @@ function getRepoPath(repoName, reposDir) {
2214
2324
  async function cloneRepository(repository, targetPath, spawn, context) {
2215
2325
  return new Promise((resolve) => {
2216
2326
  const proc = spawn("git", ["clone", repository.gitUrl, targetPath], {
2217
- stdio: ["ignore", "pipe", "pipe"]
2327
+ stdio: ["ignore", "pipe", "pipe"],
2328
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
2218
2329
  });
2219
2330
  let stderr = "";
2220
2331
  proc.stderr?.on("data", (data) => {
@@ -2438,26 +2549,26 @@ function getEnvironmentContext(cwd) {
2438
2549
  function formatLoopEvent(event) {
2439
2550
  switch (event.type) {
2440
2551
  case "loop.warning":
2441
- return "⚠️ WARNING: This command skips all permission checks. Only use in a sandbox environment!";
2552
+ return "WARNING: This command skips all permission checks. Only use in a sandbox environment!";
2442
2553
  case "loop.started": {
2443
2554
  const agent2 = event.agentType ?? "claude";
2444
- return `\uD83D\uDD04 Starting dust loop ${agent2} (max ${event.maxIterations} iterations)...`;
2555
+ return `Starting dust loop ${agent2} (max ${event.maxIterations} iterations)...`;
2445
2556
  }
2446
2557
  case "loop.syncing":
2447
- return "\uD83C\uDF0D Syncing with remote";
2558
+ return "Syncing with remote";
2448
2559
  case "loop.sync_skipped":
2449
2560
  return `Note: git pull skipped (${event.reason})`;
2450
2561
  case "loop.checking_tasks":
2451
2562
  return null;
2452
2563
  case "loop.no_tasks":
2453
- return "\uD83D\uDE34 No tasks available. Sleeping...";
2564
+ return "No tasks available. Sleeping...";
2454
2565
  case "loop.tasks_found":
2455
- return `✨ Found a task. Going to work!
2566
+ return `Found a task. Going to work!
2456
2567
  `;
2457
2568
  case "loop.iteration_complete":
2458
- return `\uD83D\uDCCB Completed iteration ${event.iteration}/${event.maxIterations}`;
2569
+ return `Completed iteration ${event.iteration}/${event.maxIterations}`;
2459
2570
  case "loop.ended":
2460
- return `\uD83C\uDFC1 Reached max iterations (${event.maxIterations}). Exiting.`;
2571
+ return `Reached max iterations (${event.maxIterations}). Exiting.`;
2461
2572
  }
2462
2573
  }
2463
2574
  function createPostEvent(fetchFn) {
@@ -2515,7 +2626,8 @@ async function gitPull(cwd, spawn) {
2515
2626
  return new Promise((resolve) => {
2516
2627
  const proc = spawn("git", ["pull"], {
2517
2628
  cwd,
2518
- stdio: ["ignore", "pipe", "pipe"]
2629
+ stdio: ["ignore", "pipe", "pipe"],
2630
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
2519
2631
  });
2520
2632
  let stderr = "";
2521
2633
  proc.stderr?.on("data", (data) => {
@@ -3065,6 +3177,15 @@ function parseServerMessage(data) {
3065
3177
  }
3066
3178
 
3067
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
+ };
3068
3189
  var ANSI = {
3069
3190
  HIDE_CURSOR: "\x1B[?25l",
3070
3191
  SHOW_CURSOR: "\x1B[?25h",
@@ -3119,8 +3240,8 @@ function truncateLine(text, maxWidth) {
3119
3240
  for (let match = ansiRegex.exec(text);match !== null; match = ansiRegex.exec(text)) {
3120
3241
  const textBefore = text.slice(lastIndex, match.index);
3121
3242
  for (const char of textBefore) {
3122
- if (visibleCount >= maxWidth - 1) {
3123
- result += "…";
3243
+ if (visibleCount >= maxWidth - CHARS.ellipsis.length) {
3244
+ result += CHARS.ellipsis;
3124
3245
  return result + ANSI.RESET;
3125
3246
  }
3126
3247
  result += char;
@@ -3131,8 +3252,8 @@ function truncateLine(text, maxWidth) {
3131
3252
  }
3132
3253
  const remaining = text.slice(lastIndex);
3133
3254
  for (const char of remaining) {
3134
- if (visibleCount >= maxWidth - 1) {
3135
- result += "…";
3255
+ if (visibleCount >= maxWidth - CHARS.ellipsis.length) {
3256
+ result += CHARS.ellipsis;
3136
3257
  return result + ANSI.RESET;
3137
3258
  }
3138
3259
  result += char;
@@ -3232,7 +3353,7 @@ function getTabRowCount(state) {
3232
3353
  return 1;
3233
3354
  const tabWidths = [5];
3234
3355
  for (const name of state.repositories) {
3235
- tabWidths.push(name.length + 4);
3356
+ tabWidths.push(name.length + 2 + CHARS.dot.length + 1);
3236
3357
  }
3237
3358
  let rows = 1;
3238
3359
  let currentRowWidth = 0;
@@ -3302,8 +3423,8 @@ function renderTabs(state) {
3302
3423
  const color = getRepoColor(name, i);
3303
3424
  const agentStatus = state.agentStatuses.get(name) ?? "idle";
3304
3425
  const dotColor = agentStatus === "busy" ? ANSI.FG_GREEN : ANSI.DIM;
3305
- const dot = `${dotColor}●${ANSI.RESET}`;
3306
- const width = name.length + 4;
3426
+ const dot = `${dotColor}${CHARS.dot}${ANSI.RESET}`;
3427
+ const width = name.length + 2 + CHARS.dot.length + 1;
3307
3428
  if (i === state.selectedIndex) {
3308
3429
  tabs.push({
3309
3430
  text: ` ${dot}${color} ${ANSI.INVERSE}${name}${ANSI.RESET} `,
@@ -3328,10 +3449,10 @@ function renderTabs(state) {
3328
3449
  return rows.map((row) => row.map((t) => t.text).join("|"));
3329
3450
  }
3330
3451
  function renderHelpLine() {
3331
- return `${ANSI.DIM}[←→] select [↑↓] scroll [PgUp/PgDn] page [g/G] top/bottom [o] open [q] quit${ANSI.RESET}`;
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}`;
3332
3453
  }
3333
3454
  function renderSeparator(width) {
3334
- return "─".repeat(width);
3455
+ return CHARS.hline.repeat(Math.max(0, width));
3335
3456
  }
3336
3457
  function formatLogLine(line, prefixAlign, maxWidth) {
3337
3458
  let prefix = "";
@@ -3363,7 +3484,7 @@ function formatLogLine(line, prefixAlign, maxWidth) {
3363
3484
  function renderFrame(state) {
3364
3485
  const lines = [];
3365
3486
  const hostLabel = state.connectedHost ? ` ${ANSI.DIM}[connected to ${state.connectedHost}]${ANSI.RESET}` : "";
3366
- lines.push(`${ANSI.BOLD}dust bucket${ANSI.RESET}${hostLabel}`);
3487
+ lines.push(`${ANSI.BOLD}${CHARS.sparkle}dust bucket${ANSI.RESET}${hostLabel}`);
3367
3488
  const tabRows = renderTabs(state);
3368
3489
  for (const tabRow of tabRows) {
3369
3490
  lines.push(tabRow);
@@ -3386,7 +3507,7 @@ function renderFrame(state) {
3386
3507
  lines.push("");
3387
3508
  }
3388
3509
  if (state.scrollOffset > 0) {
3389
- const indicator = `${ANSI.DIM} ${state.scrollOffset} more${ANSI.RESET}`;
3510
+ const indicator = `${ANSI.DIM}${CHARS.scroll_down} ${state.scrollOffset} more${ANSI.RESET}`;
3390
3511
  lines[lines.length - 1] = indicator;
3391
3512
  }
3392
3513
  const output = [];
@@ -3534,8 +3655,8 @@ function defaultSetupResize(onResize) {
3534
3655
  }
3535
3656
  function defaultGetTerminalSize() {
3536
3657
  return {
3537
- width: process.stdout.columns ?? 80,
3538
- height: process.stdout.rows ?? 24
3658
+ width: process.stdout.columns || 80,
3659
+ height: process.stdout.rows || 24
3539
3660
  };
3540
3661
  }
3541
3662
  function defaultWriteStdout(data) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joshski/dust",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "description": "Flow state for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {