@joshski/dust 0.1.106 → 0.1.108

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 (67) hide show
  1. package/README.md +2 -3
  2. package/dist/artifacts.js +2 -2
  3. package/dist/audits.js +296 -0
  4. package/dist/bucket/server-messages.d.ts +3 -2
  5. package/dist/core-principles.js +1401 -87
  6. package/dist/dust.js +1955 -260
  7. package/package.json +2 -3
  8. package/.dust/principles/actionable-errors.md +0 -18
  9. package/.dust/principles/agent-agnostic-design.md +0 -21
  10. package/.dust/principles/agent-autonomy.md +0 -19
  11. package/.dust/principles/agent-context-inference.md +0 -19
  12. package/.dust/principles/agent-specific-enhancement.md +0 -23
  13. package/.dust/principles/agentic-flow-state.md +0 -24
  14. package/.dust/principles/atomic-commits.md +0 -15
  15. package/.dust/principles/batteries-included.md +0 -17
  16. package/.dust/principles/boy-scout-rule.md +0 -15
  17. package/.dust/principles/broken-windows.md +0 -17
  18. package/.dust/principles/clarity-over-brevity.md +0 -13
  19. package/.dust/principles/co-located-tests.md +0 -13
  20. package/.dust/principles/comprehensive-assertions.md +0 -50
  21. package/.dust/principles/comprehensive-test-coverage.md +0 -15
  22. package/.dust/principles/consistent-naming.md +0 -13
  23. package/.dust/principles/context-optimised-code.md +0 -15
  24. package/.dust/principles/context-window-efficiency.md +0 -15
  25. package/.dust/principles/cross-platform-compatibility.md +0 -19
  26. package/.dust/principles/debugging-tooling.md +0 -19
  27. package/.dust/principles/decoupled-code.md +0 -16
  28. package/.dust/principles/dependency-injection.md +0 -15
  29. package/.dust/principles/design-for-testability.md +0 -17
  30. package/.dust/principles/development-traceability.md +0 -19
  31. package/.dust/principles/easy-adoption.md +0 -17
  32. package/.dust/principles/environment-independent-tests.md +0 -19
  33. package/.dust/principles/exploratory-tooling.md +0 -19
  34. package/.dust/principles/fast-feedback-loops.md +0 -15
  35. package/.dust/principles/fast-feedback.md +0 -13
  36. package/.dust/principles/functional-core-imperative-shell.md +0 -15
  37. package/.dust/principles/human-ai-collaboration.md +0 -18
  38. package/.dust/principles/ideal-agent-developer-experience.md +0 -24
  39. package/.dust/principles/intuitive-directory-structure.md +0 -13
  40. package/.dust/principles/keep-unit-tests-pure.md +0 -25
  41. package/.dust/principles/lightweight-planning.md +0 -16
  42. package/.dust/principles/lint-everything.md +0 -19
  43. package/.dust/principles/maintainable-codebase.md +0 -21
  44. package/.dust/principles/make-changes-with-confidence.md +0 -23
  45. package/.dust/principles/make-the-change-easy.md +0 -15
  46. package/.dust/principles/minimal-dependencies.md +0 -13
  47. package/.dust/principles/naming-matters.md +0 -14
  48. package/.dust/principles/progressive-disclosure.md +0 -15
  49. package/.dust/principles/readable-test-data.md +0 -48
  50. package/.dust/principles/reasonably-dry.md +0 -13
  51. package/.dust/principles/repository-hygiene.md +0 -14
  52. package/.dust/principles/reproducible-checks.md +0 -13
  53. package/.dust/principles/runtime-agnostic-tests.md +0 -13
  54. package/.dust/principles/self-contained-repository.md +0 -17
  55. package/.dust/principles/self-diagnosing-tests.md +0 -54
  56. package/.dust/principles/slow-feedback-coping.md +0 -15
  57. package/.dust/principles/small-units.md +0 -17
  58. package/.dust/principles/some-big-design-up-front.md +0 -34
  59. package/.dust/principles/stop-the-line.md +0 -13
  60. package/.dust/principles/stubs-over-mocks.md +0 -19
  61. package/.dust/principles/task-first-workflow.md +0 -13
  62. package/.dust/principles/test-isolation.md +0 -19
  63. package/.dust/principles/traceable-decisions.md +0 -13
  64. package/.dust/principles/trunk-based-development.md +0 -19
  65. package/.dust/principles/unit-test-coverage.md +0 -13
  66. package/.dust/principles/unsurprising-ux.md +0 -15
  67. package/.dust/principles/vcs-independence.md +0 -13
package/README.md CHANGED
@@ -9,11 +9,10 @@ Dust provides a CLI that agents use to systematically blaze through your backlog
9
9
  ## Quick Start
10
10
 
11
11
  ```bash
12
- npm install @joshski/dust
13
- npx dust init
12
+ claude "install dust as per https://github.com/joshski/dust"
14
13
  ```
15
14
 
16
- This creates a [.dust](./.dust/facts/dust-directory-structure.md) directory and adds an [instruction](./.dust/facts/agents-md-instruction.md) to your `AGENTS.md` file.
15
+ This works with other agents (codex, cursor, opencode, etc.) too. The agent will install dust and set up the [.dust](./.dust/facts/dust-directory-structure.md) directory with an [instruction](./.dust/facts/agents-md-instruction.md) in your `AGENTS.md` file.
17
16
 
18
17
  ## Adding Tasks
19
18
 
package/dist/artifacts.js CHANGED
@@ -866,10 +866,10 @@ async function createRefineIdeaTask(fileSystem, dustPath, ideaSlug, description,
866
866
  }
867
867
  async function decomposeIdea(fileSystem, dustPath, options, dustCommand) {
868
868
  const cmd = dustCommand ?? "dust";
869
- return createIdeaTransitionTask(fileSystem, dustPath, "decompose", "Decompose Idea: ", options.ideaSlug, (ideaTitle) => `Create one or more well-defined tasks from this idea. Prefer smaller, narrowly scoped tasks that each deliver a thin but complete vertical slice of working software -- a path through the system that can be tested end-to-end -- rather than component-oriented tasks (like "add schema" or "build endpoint") that only work once all tasks are done. Split the idea into multiple tasks if it covers more than one logical change. Run \`${cmd} principles\` to link relevant principles and \`${cmd} facts\` for design decisions that should inform the task. See [${ideaTitle}](../ideas/${options.ideaSlug}.md).`, [
869
+ return createIdeaTransitionTask(fileSystem, dustPath, "decompose", "Decompose Idea: ", options.ideaSlug, (ideaTitle) => `Create one or more well-defined tasks from this idea. Prefer smaller, narrowly scoped tasks that each deliver a thin but complete vertical slice of working software -- a path through the system that can be tested end-to-end -- rather than component-oriented tasks (like "add schema" or "build endpoint") that only work once all tasks are done. Split the idea into multiple tasks if it covers more than one logical change. Run \`${cmd} principles\` to identify relevant principles (both core and local), then inline the FULL content of ALL selected principles in a Guidance section in each new task file (after Principles but before Definition of Done). This ensures implementing agents read the guidance without extra tool calls. Also run \`${cmd} facts\` for design decisions that should inform the task. See [${ideaTitle}](../ideas/${options.ideaSlug}.md).`, [
870
870
  "One or more new tasks are created in .dust/tasks/",
871
871
  "Task's Principles section links to relevant principles from .dust/principles/",
872
- "The original idea is deleted or updated to reflect remaining scope"
872
+ `The original idea (.dust/ideas/${options.ideaSlug}.md) is deleted or updated to reflect remaining scope`
873
873
  ], "Decomposes Idea", {
874
874
  description: options.description,
875
875
  resolvedQuestions: options.openQuestionResponses
package/dist/audits.js CHANGED
@@ -787,6 +787,301 @@ function feedbackLoopSpeed() {
787
787
  - No changes to files outside \`.dust/\`
788
788
  `;
789
789
  }
790
+ function flakyTests() {
791
+ return dedent`
792
+ # Flaky Tests
793
+
794
+ Detect timing-dependent patterns that cause test flakiness. This includes fixed sleep/delay usage, event ordering assumptions, race conditions, missing synchronization, and subprocess timing issues.
795
+
796
+ ${ideasHint}
797
+
798
+ ## Context
799
+
800
+ Test flakiness undermines confidence in CI and slows development. While fixed delays account for nearly 50% of async-related test flakiness, the remaining issues stem from race conditions, event ordering assumptions, and missing synchronization. This audit provides comprehensive detection of async patterns that cause flakiness through semantic analysis of code structure and control flow.
801
+
802
+ ## Scope
803
+
804
+ Focus on detecting these patterns in test files:
805
+
806
+ 1. **Fixed sleep calls** - \`setTimeout()\`, \`sleep()\`, \`delay()\` with hardcoded millisecond values
807
+ 2. **Wait/delay utilities** - Custom wait functions that use fixed timeouts
808
+ 3. **Retry with fixed delays** - Retry loops that sleep a constant amount between attempts
809
+ 4. **Timing comments** - Comments indicating timing assumptions (e.g., "wait 100ms", "give it time to settle")
810
+ 5. **Event ordering assumptions** - Tests assuming synchronous event propagation
811
+ 6. **Race conditions** - Multiple concurrent async operations without proper synchronization
812
+ 7. **Missing synchronization** - Assertions on eventually-consistent state without waiting
813
+ 8. **Subprocess timing issues** - Child process tests with improper async handling
814
+
815
+ ## Analysis Steps
816
+
817
+ ### 1. Identify Test Files
818
+
819
+ Search for test files using common patterns:
820
+ - \`**/*.test.ts\`
821
+ - \`**/*.test.js\`
822
+ - \`**/*.spec.ts\`
823
+ - \`**/*.spec.js\`
824
+ - Framework-specific patterns (e.g., \`__tests__/**\`)
825
+
826
+ ### 2. Search for Fixed Sleep Patterns
827
+
828
+ Search test files for these patterns:
829
+
830
+ **Direct delay calls:**
831
+ - \`setTimeout\`
832
+ - \`sleep\`
833
+ - \`delay\`
834
+ - \`wait\`
835
+ - \`Thread.sleep\`
836
+ - \`time.sleep\`
837
+
838
+ **Timing comments:**
839
+ - "wait for"
840
+ - "sleep"
841
+ - "give it time"
842
+ - "let it settle"
843
+ - References to specific millisecond values in comments near test assertions
844
+
845
+ ### 3. Detect Event Ordering Assumptions
846
+
847
+ Search for tests that assume synchronous event propagation:
848
+
849
+ **Patterns to detect:**
850
+ - \`emitter.emit('event')\` or similar followed immediately by assertions (without await/wait)
851
+ - Event handler registration followed by immediate state checks
852
+ - Tests asserting on event-driven state changes without synchronization
853
+ - Missing promise wrappers around event-driven flows
854
+
855
+ **Example problematic pattern:**
856
+ \`\`\`typescript
857
+ eventEmitter.emit('data-updated')
858
+ expect(component.state).toBe('updated') // Assumes synchronous propagation
859
+ \`\`\`
860
+
861
+ **Suggested alternatives:**
862
+ - Promise-based event waiting: Wrap events in promises
863
+ - Polling utilities: Wait for state to match expected value
864
+ - Framework-specific event handling patterns
865
+
866
+ ### 4. Detect Race Conditions
867
+
868
+ Search for tests with multiple concurrent async operations without proper synchronization:
869
+
870
+ **Patterns to detect:**
871
+ - Multiple promise calls without \`Promise.all()\` or sequential awaits
872
+ - State mutations from different async contexts without locks/ordering
873
+ - \`afterEach()\`/\`afterAll()\` cleanup that may run before async operations complete
874
+ - Shared state between tests without proper reset in setup/teardown
875
+ - Tests where the outcome depends on which operation finishes first
876
+
877
+ **Example problematic patterns:**
878
+ \`\`\`typescript
879
+ // Missing Promise.all()
880
+ doAsync1() // Not awaited
881
+ doAsync2() // Not awaited
882
+ expect(result).toBe(expected) // Which result?
883
+
884
+ // Cleanup race
885
+ afterEach(() => {
886
+ cleanupState() // May run before async operations finish
887
+ })
888
+ \`\`\`
889
+
890
+ **Severity:** Mark as Critical when operations clearly race, Warning for potential races
891
+
892
+ ### 5. Detect Missing Synchronization
893
+
894
+ Search for assertions on eventually-consistent state:
895
+
896
+ **Patterns to detect:**
897
+ - Assertions on state modified by async operations without awaiting
898
+ - Manual polling with \`while\` loops and fixed delays
899
+ - Comments mentioning "eventually", "should become", "will be"
900
+ - Integration test retries or manual delay logic around assertions
901
+ - Database/cache operations followed by immediate reads without guarantees
902
+
903
+ **Example problematic pattern:**
904
+ \`\`\`typescript
905
+ saveToDatabase(data) // Async operation
906
+ const result = readFromDatabase() // Immediate read
907
+ expect(result).toBe(data) // May fail if write not complete
908
+ \`\`\`
909
+
910
+ **Suggest:** Condition-based waiting utilities or framework-provided eventually helpers
911
+
912
+ ### 6. Detect Subprocess/Child Process Timing Issues
913
+
914
+ Search for tests using child processes with improper async handling:
915
+
916
+ **Patterns to detect:**
917
+ - \`spawn()\`, \`exec()\`, \`fork()\` without waiting for completion
918
+ - Assertions on subprocess output without waiting for exit/close events
919
+ - Race conditions between stdout/stderr events and exit events
920
+ - Cleanup that doesn't account for async process termination
921
+ - Reading process output before process completes
922
+
923
+ **Example problematic patterns:**
924
+ \`\`\`typescript
925
+ const proc = spawn('command')
926
+ expect(proc.stdout).toContain('expected') // May not have output yet
927
+
928
+ // Cleanup race
929
+ afterEach(() => {
930
+ proc.kill() // Doesn't wait for process to actually exit
931
+ })
932
+ \`\`\`
933
+
934
+ **Suggest:** Promise-based subprocess wrappers or event-to-promise utilities
935
+
936
+ ### 7. Detect Framework-Agnostic Async Patterns
937
+
938
+ Search for common cross-framework async issues:
939
+
940
+ **Patterns to detect:**
941
+ - Missing awaits after state/DOM updates
942
+ - Hardcoded waits instead of selector/condition-based waiting
943
+ - Improper async wrapper usage (forgetting await, not handling promises)
944
+ - Async test functions without proper await chains
945
+ - \`.then()\` chains without error handling in tests
946
+
947
+ **Focus on patterns that appear across frameworks rather than framework-specific APIs.**
948
+
949
+ ### 8. Identify Available Utilities
950
+
951
+ Before proposing solutions, search the codebase for existing condition-based waiting utilities:
952
+
953
+ **Common utility names:**
954
+ - \`waitFor\`
955
+ - \`waitUntil\`
956
+ - \`waitForCondition\`
957
+ - \`poll\`
958
+ - \`eventually\`
959
+ - \`retryUntil\`
960
+
961
+ **Framework-specific helpers:**
962
+ - Testing Library: \`waitFor\`, \`waitForElementToBeRemoved\`
963
+ - Playwright/Puppeteer: \`waitForSelector\`, \`waitForFunction\`
964
+ - Cypress: \`cy.wait\` with aliases (not fixed delays)
965
+ - WebdriverIO: \`waitUntil\`
966
+
967
+ If utilities exist, adapt recommendations to use them. If not, suggest implementing simple polling helpers.
968
+
969
+ ## Output Format
970
+
971
+ ### Per-File Ideas
972
+
973
+ Create one idea file per test file containing fixed sleep patterns. Each idea should include:
974
+
975
+ **Title format:** "Flaky Test: Fixed Delays in [Component/Feature] Tests"
976
+
977
+ **Structure:**
978
+ \`\`\`markdown
979
+ # Flaky Test: Fixed Delays in [Component/Feature] Tests
980
+
981
+ ## Context
982
+
983
+ [Test file path] contains hardcoded delays that make tests timing-dependent and prone to flakiness.
984
+
985
+ ## Findings
986
+
987
+ ### [Test Suite/Describe Block Name]
988
+
989
+ **Location:** [file:line]
990
+
991
+ **Pattern:**
992
+ \`\`\`[language]
993
+ [code excerpt showing the fixed delay]
994
+ \`\`\`
995
+
996
+ **Issue:** This test waits a fixed duration instead of waiting for a specific condition, making it either unreliable (if too short) or unnecessarily slow (if too long).
997
+
998
+ [Repeat for each finding in the file]
999
+
1000
+ ## Proposed Solution
1001
+
1002
+ Replace fixed delays with condition-based waiting:
1003
+
1004
+ ### Before
1005
+ \`\`\`[language]
1006
+ [current code with setTimeout/sleep]
1007
+ \`\`\`
1008
+
1009
+ ### After
1010
+ \`\`\`[language]
1011
+ [refactored code using waitFor/polling utility]
1012
+ \`\`\`
1013
+
1014
+ [If no utility exists:]
1015
+ Consider implementing a simple polling utility:
1016
+ \`\`\`[language]
1017
+ [example polling helper implementation]
1018
+ \`\`\`
1019
+
1020
+ ## Benefits
1021
+
1022
+ - Tests become more reliable (no race conditions)
1023
+ - Tests run faster (don't wait longer than necessary)
1024
+ - Tests are more explicit about what they're waiting for
1025
+ \`\`\`
1026
+
1027
+ ### Severity Levels
1028
+
1029
+ Use these severity indicators in idea titles:
1030
+
1031
+ - **Critical:** Obvious issues likely to cause flakiness (e.g., "Flaky Test [CRITICAL]: ...")
1032
+ - **Warning:** Suspicious patterns or edge cases (e.g., "Flaky Test [WARNING]: ...")
1033
+ - **Info:** Timing dependencies that may be intentional (e.g., "Flaky Test [INFO]: ...")
1034
+
1035
+ Mark patterns as Critical when:
1036
+ - Direct \`setTimeout\`/\`sleep\` calls with hardcoded durations
1037
+ - Retry logic with fixed delays
1038
+ - Comments explicitly mentioning waiting for time to pass
1039
+ - Obvious race conditions between async operations
1040
+ - Missing awaits on async operations before assertions
1041
+ - Event emission followed immediately by assertions
1042
+
1043
+ Mark patterns as Warning when:
1044
+ - Unclear if the delay is test-related or production code
1045
+ - Complex timing logic that may be intentional
1046
+ - Potential race conditions requiring analysis
1047
+ - Subprocess tests without clear synchronization
1048
+ - Shared state between tests without visible reset
1049
+
1050
+ Mark patterns as Info when:
1051
+ - Borderline cases requiring human judgment
1052
+ - Patterns that might be intentional performance tests
1053
+ - Timing dependencies with unclear context
1054
+
1055
+ ## Applicability
1056
+
1057
+ This audit applies to codebases with:
1058
+ - Automated test suites (unit, integration, or end-to-end tests)
1059
+ - Async operations being tested (API calls, UI updates, event handling)
1060
+
1061
+ If the project has no tests or only synchronous tests, document that finding and skip the detailed analysis.
1062
+
1063
+ ## Blocked By
1064
+
1065
+ (none)
1066
+
1067
+ ## Definition of Done
1068
+
1069
+ - Identified all test files in the codebase using common patterns
1070
+ - Searched test files for fixed sleep patterns (\`setTimeout\`, \`sleep\`, etc.)
1071
+ - Searched for timing-related comments in test files
1072
+ - Detected event ordering assumptions (emit without wait)
1073
+ - Detected race conditions (multiple async operations without synchronization)
1074
+ - Detected missing synchronization (assertions on eventually-consistent state)
1075
+ - Detected subprocess/child process timing issues
1076
+ - Detected framework-agnostic async patterns (missing awaits, hardcoded waits)
1077
+ - Identified available condition-based waiting utilities (existing or framework-provided)
1078
+ - Created idea files for each test file containing async patterns (one idea per test file)
1079
+ - Each idea includes context, findings with line numbers, and actionable solutions
1080
+ - Solutions are adapted to utilities available in the target codebase
1081
+ - Severity levels assigned appropriately (Critical, Warning, or Info)
1082
+ - No changes to files outside \`.dust/\`
1083
+ `;
1084
+ }
790
1085
  function ideasFromPrinciples() {
791
1086
  return dedent`
792
1087
  # Ideas from Principles
@@ -2465,6 +2760,7 @@ var stockAuditFunctions = {
2465
2760
  "error-handling": errorHandling,
2466
2761
  "facts-verification": factsVerification,
2467
2762
  "feedback-loop-speed": feedbackLoopSpeed,
2763
+ "flaky-tests": flakyTests,
2468
2764
  "global-state": globalState,
2469
2765
  "commit-review": commitReview,
2470
2766
  "ideas-from-principles": ideasFromPrinciples,
@@ -34,13 +34,14 @@ export interface ToolDefinitionsMessage {
34
34
  }
35
35
  /**
36
36
  * Sent by client on connect to initiate the handshake.
37
- * Includes version, platform, git remote, and agent capabilities.
37
+ * Includes version, platform, git remote, machine ID, and agent capabilities.
38
38
  */
39
39
  export interface ConnectionInitMessage {
40
40
  type: 'connection-init';
41
41
  dustVersion: string;
42
42
  platform: string;
43
43
  gitRemote?: string;
44
+ machineId?: string;
44
45
  agents: AgentCapability[];
45
46
  }
46
47
  /**
@@ -71,4 +72,4 @@ export declare function parseServerMessage(data: unknown): ServerMessage | null;
71
72
  * Build a ConnectionInitMessage payload.
72
73
  * Pure function - no side effects.
73
74
  */
74
- export declare function buildConnectionInitPayload(dustVersion: string, platform: string, gitRemote: string | undefined, agents: AgentCapability[]): ConnectionInitMessage;
75
+ export declare function buildConnectionInitPayload(dustVersion: string, platform: string, gitRemote: string | undefined, agents: AgentCapability[], machineId?: string): ConnectionInitMessage;