prjct-cli 0.19.0 → 0.20.1

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 (230) hide show
  1. package/CHANGELOG.md +66 -6
  2. package/CLAUDE.md +56 -15
  3. package/README.md +5 -6
  4. package/bin/prjct +59 -42
  5. package/bin/prjct.ts +60 -0
  6. package/core/__tests__/agentic/memory-system.test.ts +18 -3
  7. package/core/__tests__/agentic/plan-mode.test.ts +55 -26
  8. package/core/__tests__/agentic/prompt-builder.test.ts +6 -6
  9. package/core/__tests__/utils/project-commands.test.ts +72 -0
  10. package/core/agentic/agent-router.ts +3 -12
  11. package/core/agentic/command-executor.ts +372 -3
  12. package/core/agentic/context-builder.ts +7 -27
  13. package/core/agentic/ground-truth.ts +604 -5
  14. package/core/agentic/index.ts +180 -0
  15. package/core/agentic/loop-detector.ts +418 -4
  16. package/core/agentic/memory-system.ts +857 -3
  17. package/core/agentic/plan-mode.ts +491 -4
  18. package/core/agentic/prompt-builder.ts +44 -65
  19. package/core/agentic/services.ts +13 -5
  20. package/core/agentic/skill-loader.ts +112 -0
  21. package/core/agentic/smart-context.ts +37 -122
  22. package/core/agentic/template-loader.ts +79 -122
  23. package/core/agentic/tool-registry.ts +5 -11
  24. package/core/agents/index.ts +1 -1
  25. package/core/agents/performance.ts +4 -2
  26. package/core/bus/bus.ts +262 -0
  27. package/core/bus/index.ts +3 -313
  28. package/core/commands/analysis.ts +5 -5
  29. package/core/commands/analytics.ts +11 -11
  30. package/core/commands/base.ts +33 -209
  31. package/core/commands/cleanup.ts +148 -0
  32. package/core/commands/command-data.ts +346 -0
  33. package/core/commands/commands.ts +216 -0
  34. package/core/commands/design.ts +83 -0
  35. package/core/commands/index.ts +13 -207
  36. package/core/commands/maintenance.ts +52 -473
  37. package/core/commands/planning.ts +3 -3
  38. package/core/commands/register.ts +104 -0
  39. package/core/commands/registry.ts +441 -0
  40. package/core/commands/setup.ts +25 -9
  41. package/core/commands/shipping.ts +48 -11
  42. package/core/commands/snapshots.ts +299 -0
  43. package/core/commands/workflow.ts +2 -2
  44. package/core/constants/index.ts +254 -4
  45. package/core/domain/agent-loader.ts +5 -6
  46. package/core/domain/task-stack.ts +555 -4
  47. package/core/errors.ts +127 -1
  48. package/core/events/events.ts +87 -0
  49. package/core/events/index.ts +4 -138
  50. package/core/index.ts +15 -23
  51. package/core/infrastructure/agent-detector.ts +126 -201
  52. package/core/infrastructure/author-detector.ts +99 -171
  53. package/core/infrastructure/command-installer.ts +476 -4
  54. package/core/infrastructure/config-manager.ts +41 -37
  55. package/core/infrastructure/path-manager.ts +59 -9
  56. package/core/infrastructure/permission-manager.ts +286 -0
  57. package/core/outcomes/analyzer.ts +7 -41
  58. package/core/outcomes/index.ts +1 -1
  59. package/core/outcomes/recorder.ts +1 -1
  60. package/core/{plugins → plugin/builtin}/webhook.ts +6 -22
  61. package/core/plugin/loader.ts +5 -5
  62. package/core/plugin/registry.ts +2 -2
  63. package/core/schemas/ideas.ts +85 -54
  64. package/core/schemas/index.ts +14 -33
  65. package/core/schemas/permissions.ts +177 -0
  66. package/core/schemas/project.ts +39 -12
  67. package/core/schemas/roadmap.ts +94 -59
  68. package/core/schemas/schemas.ts +39 -0
  69. package/core/schemas/shipped.ts +87 -60
  70. package/core/schemas/state.ts +110 -70
  71. package/core/server/index.ts +21 -0
  72. package/core/server/routes.ts +165 -0
  73. package/core/server/server.ts +136 -0
  74. package/core/server/sse.ts +135 -0
  75. package/core/services/agent-service.ts +170 -0
  76. package/core/services/breakdown-service.ts +126 -0
  77. package/core/services/index.ts +21 -0
  78. package/core/services/memory-service.ts +108 -0
  79. package/core/services/project-service.ts +146 -0
  80. package/core/services/skill-service.ts +253 -0
  81. package/core/session/compaction.ts +257 -0
  82. package/core/session/index.ts +20 -8
  83. package/core/{infrastructure/session-manager/migration.ts → session/log-migration.ts} +9 -9
  84. package/core/{infrastructure/session-manager/session-manager.ts → session/session-log-manager.ts} +27 -26
  85. package/core/session/{session-manager.ts → task-session-manager.ts} +7 -4
  86. package/core/session/utils.ts +1 -1
  87. package/core/storage/ideas-storage.ts +10 -26
  88. package/core/storage/index.ts +14 -162
  89. package/core/storage/queue-storage.ts +13 -11
  90. package/core/storage/shipped-storage.ts +4 -17
  91. package/core/storage/state-storage.ts +35 -43
  92. package/core/storage/storage-manager.ts +42 -52
  93. package/core/storage/storage.ts +160 -0
  94. package/core/sync/auth-config.ts +1 -8
  95. package/core/sync/index.ts +17 -10
  96. package/core/sync/oauth-handler.ts +1 -6
  97. package/core/sync/sync-client.ts +6 -34
  98. package/core/sync/sync-manager.ts +11 -40
  99. package/core/types/agentic.ts +577 -0
  100. package/core/types/agents.ts +145 -0
  101. package/core/types/bus.ts +82 -0
  102. package/core/types/commands.ts +366 -0
  103. package/core/types/config.ts +66 -0
  104. package/core/types/core.ts +96 -0
  105. package/core/types/domain.ts +71 -0
  106. package/core/types/events.ts +42 -0
  107. package/core/types/fs.ts +56 -0
  108. package/core/types/index.ts +387 -500
  109. package/core/types/infrastructure.ts +196 -0
  110. package/core/{agentic/memory-system/types.ts → types/memory.ts} +33 -8
  111. package/core/{outcomes/types.ts → types/outcomes.ts} +53 -8
  112. package/core/types/plugin.ts +25 -0
  113. package/core/types/server.ts +54 -0
  114. package/core/types/services.ts +65 -0
  115. package/core/types/session.ts +135 -0
  116. package/core/types/storage.ts +148 -0
  117. package/core/types/sync.ts +121 -0
  118. package/core/types/task.ts +72 -0
  119. package/core/types/template.ts +24 -0
  120. package/core/types/utils.ts +90 -0
  121. package/core/utils/cache.ts +195 -0
  122. package/core/utils/collection-filters.ts +245 -0
  123. package/core/utils/date-helper.ts +1 -5
  124. package/core/utils/file-helper.ts +20 -10
  125. package/core/utils/jsonl-helper.ts +5 -8
  126. package/core/utils/markdown-builder.ts +277 -0
  127. package/core/utils/project-commands.ts +132 -0
  128. package/core/utils/runtime.ts +119 -0
  129. package/dist/bin/prjct.mjs +12568 -0
  130. package/package.json +13 -8
  131. package/scripts/build.js +106 -0
  132. package/scripts/postinstall.js +50 -8
  133. package/templates/agentic/agents/uxui.md +210 -0
  134. package/templates/agentic/subagent-generation.md +1 -1
  135. package/templates/commands/bug.md +219 -41
  136. package/templates/commands/feature.md +368 -80
  137. package/templates/commands/serve.md +118 -0
  138. package/templates/commands/ship.md +152 -14
  139. package/templates/commands/skill.md +110 -0
  140. package/templates/commands/sync.md +63 -4
  141. package/templates/commands/test.md +40 -188
  142. package/templates/mcp-config.json +0 -36
  143. package/templates/permissions/default.jsonc +60 -0
  144. package/templates/permissions/permissive.jsonc +49 -0
  145. package/templates/permissions/strict.jsonc +62 -0
  146. package/templates/skills/code-review.md +47 -0
  147. package/templates/skills/debug.md +61 -0
  148. package/templates/skills/refactor.md +47 -0
  149. package/templates/subagents/domain/devops.md +1 -1
  150. package/templates/subagents/domain/testing.md +6 -10
  151. package/templates/subagents/workflow/prjct-shipper.md +16 -7
  152. package/templates/tools/bash.txt +22 -0
  153. package/templates/tools/edit.txt +18 -0
  154. package/templates/tools/glob.txt +19 -0
  155. package/templates/tools/grep.txt +21 -0
  156. package/templates/tools/read.txt +14 -0
  157. package/templates/tools/task.txt +20 -0
  158. package/templates/tools/webfetch.txt +16 -0
  159. package/templates/tools/websearch.txt +18 -0
  160. package/templates/tools/write.txt +17 -0
  161. package/core/agentic/command-executor/command-executor.ts +0 -312
  162. package/core/agentic/command-executor/index.ts +0 -16
  163. package/core/agentic/command-executor/status-signal.ts +0 -38
  164. package/core/agentic/command-executor/types.ts +0 -79
  165. package/core/agentic/ground-truth/index.ts +0 -76
  166. package/core/agentic/ground-truth/types.ts +0 -33
  167. package/core/agentic/ground-truth/utils.ts +0 -48
  168. package/core/agentic/ground-truth/verifiers/analyze.ts +0 -54
  169. package/core/agentic/ground-truth/verifiers/done.ts +0 -75
  170. package/core/agentic/ground-truth/verifiers/feature.ts +0 -70
  171. package/core/agentic/ground-truth/verifiers/index.ts +0 -37
  172. package/core/agentic/ground-truth/verifiers/init.ts +0 -52
  173. package/core/agentic/ground-truth/verifiers/now.ts +0 -57
  174. package/core/agentic/ground-truth/verifiers/ship.ts +0 -85
  175. package/core/agentic/ground-truth/verifiers/spec.ts +0 -45
  176. package/core/agentic/ground-truth/verifiers/sync.ts +0 -47
  177. package/core/agentic/ground-truth/verifiers.ts +0 -6
  178. package/core/agentic/loop-detector/error-analysis.ts +0 -97
  179. package/core/agentic/loop-detector/hallucination.ts +0 -71
  180. package/core/agentic/loop-detector/index.ts +0 -41
  181. package/core/agentic/loop-detector/loop-detector.ts +0 -222
  182. package/core/agentic/loop-detector/types.ts +0 -66
  183. package/core/agentic/memory-system/history.ts +0 -53
  184. package/core/agentic/memory-system/index.ts +0 -192
  185. package/core/agentic/memory-system/patterns.ts +0 -156
  186. package/core/agentic/memory-system/semantic-memories.ts +0 -278
  187. package/core/agentic/memory-system/session.ts +0 -21
  188. package/core/agentic/plan-mode/approval.ts +0 -57
  189. package/core/agentic/plan-mode/constants.ts +0 -44
  190. package/core/agentic/plan-mode/index.ts +0 -28
  191. package/core/agentic/plan-mode/plan-mode.ts +0 -407
  192. package/core/agentic/plan-mode/types.ts +0 -193
  193. package/core/agents/types.ts +0 -126
  194. package/core/command-registry/categories.ts +0 -23
  195. package/core/command-registry/commands.ts +0 -15
  196. package/core/command-registry/core-commands.ts +0 -344
  197. package/core/command-registry/index.ts +0 -158
  198. package/core/command-registry/optional-commands.ts +0 -163
  199. package/core/command-registry/setup-commands.ts +0 -83
  200. package/core/command-registry/types.ts +0 -59
  201. package/core/command-registry.ts +0 -9
  202. package/core/commands/types.ts +0 -185
  203. package/core/commands.ts +0 -11
  204. package/core/constants/formats.ts +0 -187
  205. package/core/context-sync.ts +0 -18
  206. package/core/data/index.ts +0 -27
  207. package/core/data/md-base-manager.ts +0 -203
  208. package/core/data/md-ideas-manager.ts +0 -155
  209. package/core/data/md-queue-manager.ts +0 -180
  210. package/core/data/md-shipped-manager.ts +0 -90
  211. package/core/data/md-state-manager.ts +0 -137
  212. package/core/domain/task-stack/index.ts +0 -19
  213. package/core/domain/task-stack/parser.ts +0 -86
  214. package/core/domain/task-stack/storage.ts +0 -123
  215. package/core/domain/task-stack/task-stack.ts +0 -340
  216. package/core/domain/task-stack/types.ts +0 -51
  217. package/core/infrastructure/command-installer/command-installer.ts +0 -327
  218. package/core/infrastructure/command-installer/global-config.ts +0 -136
  219. package/core/infrastructure/command-installer/index.ts +0 -25
  220. package/core/infrastructure/command-installer/types.ts +0 -41
  221. package/core/infrastructure/session-manager/index.ts +0 -23
  222. package/core/infrastructure/session-manager/types.ts +0 -45
  223. package/core/infrastructure/session-manager.ts +0 -8
  224. package/core/serializers/ideas-serializer.ts +0 -187
  225. package/core/serializers/index.ts +0 -36
  226. package/core/serializers/queue-serializer.ts +0 -210
  227. package/core/serializers/shipped-serializer.ts +0 -108
  228. package/core/serializers/state-serializer.ts +0 -136
  229. package/core/session/types.ts +0 -29
  230. /package/core/infrastructure/{agents/claude-agent.ts → claude-agent.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,65 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.20.1] - 2025-12-26
4
+
5
+ ### Refactor: Type Consolidation
6
+
7
+ Centralized ALL types in `core/types/` following DRY principles.
8
+
9
+ **Changes:**
10
+ - Moved types from `domain/task-stack.ts` → `types/domain.ts`
11
+ - Moved types from `sync/*.ts` → `types/sync.ts`
12
+ - Moved types from `storage/*.ts` → `types/storage.ts`
13
+ - Moved types from `server/*.ts` → `types/server.ts`
14
+ - Moved types from `utils/*.ts` → `types/utils.ts`
15
+ - Added `types/plugin.ts` for webhook types
16
+ - Updated all barrel exports to re-export from `core/types`
17
+ - Renamed types to canonical names (TaskEntry → TaskStackEntry, etc.)
18
+
19
+ **Stats:** 41 files changed, 606 insertions, 819 deletions (net -213 lines)
20
+
21
+ ## [0.20.0] - 2025-12-21
22
+
23
+ ### Feature: UX/UI Design Agent Integration
24
+
25
+ Auto-generated UX/UI specialist agent for all frontend projects (web + mobile).
26
+
27
+ **Priority: UX > UI** - Experience is more important than visuals.
28
+
29
+ #### New Agent: `templates/agentic/agents/uxui.md`
30
+ - **Part 1: UX Principles** - User analysis, clarity, feedback, reduced friction, error handling, accessibility (a11y)
31
+ - **Part 2: UI Guidelines** - Aesthetic directions, typography trends (avoiding "AI slop"), color framework, purposeful animation
32
+ - **Part 3: Quality Checklists** - Mandatory UX/UI gates before shipping
33
+
34
+ #### Frontend Detection in `/p:sync`
35
+ Auto-generates uxui.md when ANY frontend tech is detected:
36
+
37
+ | Platform | Technologies |
38
+ |----------|-------------|
39
+ | Web | React, Vue, Svelte, Angular, Next.js, Nuxt |
40
+ | Mobile | React Native, Expo, Flutter, SwiftUI, Jetpack Compose |
41
+
42
+ #### Enhanced `/p:feature` Phase 4
43
+ For frontend features, now includes:
44
+ 1. **UX Analysis** - Who, problem, happy path, edge cases
45
+ 2. **UX Requirements Checklist** - 6 mandatory accessibility/usability checks
46
+ 3. **Aesthetic Direction Selection** - Minimal, Bold, Soft, Brutalist
47
+ 4. **UI Guidelines Application** - Typography, color, animation, layout
48
+
49
+ #### Anti-patterns Avoided ("AI Slop")
50
+ - Generic fonts: Inter, Roboto, Arial, Space Grotesk
51
+ - Purple/blue gradients on white
52
+ - Centered layouts without personality
53
+ - Unstyled component libraries
54
+
55
+ **Files Added:**
56
+ - `templates/agentic/agents/uxui.md` - Complete UX/UI specialist agent
57
+
58
+ **Files Modified:**
59
+ - `templates/commands/sync.md` - Frontend detection + uxui.md generation
60
+ - `templates/commands/feature.md` - Phase 4.0 UX/UI analysis
61
+ - `templates/commands/ship.md` - Pre-flight checks + confidence scoring
62
+
3
63
  ## [0.19.0] - 2025-12-21
4
64
 
5
65
  ### Breaking: Web Package Removed
@@ -1337,7 +1397,7 @@ The 3-tier help system solves the core user frustration: **users know WHAT they
1337
1397
  - **Comprehensive Testing Documentation** - Complete testing guide and setup documentation
1338
1398
  - **TESTING.md** - Full testing guide with:
1339
1399
  - Quick start commands for running tests
1340
- - Vitest workspace architecture (core + website)
1400
+ - Bun-based testing setup (core)
1341
1401
  - Detailed configuration for both Node.js and React environments
1342
1402
  - Testing best practices and examples
1343
1403
  - CI/CD integration documentation
@@ -1360,7 +1420,7 @@ The 3-tier help system solves the core user frustration: **users know WHAT they
1360
1420
 
1361
1421
  ### Technical Details
1362
1422
 
1363
- - **Testing Stack**: Vitest with workspace configuration for dual environments
1423
+ - **Testing Stack**: Bun test for unit tests
1364
1424
  - **Core Tests** (Node.js): 179 tests for agentic system, commands, and utilities
1365
1425
  - **Website Tests** (React): 104 tests with Testing Library for components
1366
1426
  - **CI/CD**: GitHub Actions workflow with parallel test execution
@@ -2265,7 +2325,7 @@ The 3-tier help system solves the core user frustration: **users know WHAT they
2265
2325
 
2266
2326
  - **Interactive Workflow System** - Intelligent agent workflows with user-guided capability installation
2267
2327
  - **Adaptive Workflows**: Workflows detect missing capabilities and prompt user for decisions
2268
- - **Smart Recommendations**: Stack-aware tool suggestions (React → Vitest, Vue → Vitest, Angular → Jest)
2328
+ - **Smart Recommendations**: Stack-aware tool suggestions (React → Bun test, Vue → Bun test, Angular → Jest)
2269
2329
  - **Installation Tracking**: Every tool installation becomes a visible, tracked workflow task
2270
2330
  - **Interactive Prompts**: Never auto-skips steps - always asks user (install/skip/continue/pause)
2271
2331
  - **Capability Detection**: Automatically detects design systems, test frameworks, and documentation tools
@@ -2296,11 +2356,11 @@ The 3-tier help system solves the core user frustration: **users know WHAT they
2296
2356
 
2297
2357
  - **Stack Detection**: Identifies React/Vue/Angular, TypeScript, bundler (Vite/Webpack/esbuild)
2298
2358
  - **Tool Recommendations**:
2299
- - React + TS → Vitest + Testing Library
2300
- - Vue → Vitest + @vue/test-utils
2359
+ - React + TS → Bun test + Testing Library
2360
+ - Vue → Bun test + @vue/test-utils
2301
2361
  - Angular → Jest + @types/jest
2302
2362
  - **Auto-Configuration**:
2303
- - Creates config files (vitest.config.js, jest.config.js, jsdoc.json)
2363
+ - Creates config files for the selected tooling (e.g., jest.config.js, jsdoc.json)
2304
2364
  - Updates package.json scripts
2305
2365
  - Verifies installation success
2306
2366
  - **Duration Tracking**: Installation tasks show completion time (e.g., "1.2 min")
package/CLAUDE.md CHANGED
@@ -32,32 +32,55 @@ bun -e "console.log(crypto.randomUUID())" 2>/dev/null || node -e "console.log(re
32
32
  Designed for [Claude](https://www.anthropic.com/claude)
33
33
  ```
34
34
 
35
- ## Architecture: Write-Through
35
+ ## Architecture: Write-Through Pattern
36
36
 
37
37
  ```
38
38
  User Action → Storage (JSON) → Context (MD) → Sync Events
39
39
  ```
40
40
 
41
+ ### Layer System (10 layers)
42
+
41
43
  | Layer | Path | Purpose |
42
44
  |-------|------|---------|
43
- | Storage | `storage/*.json` | Source of truth |
44
- | Context | `context/*.md` | Claude-readable (generated) |
45
- | Sync | `sync/pending.json` | Backend events |
46
- | Memory | `memory/events.jsonl` | Audit trail |
45
+ | **Storage** | `storage/*.json` | Source of truth (state, queue, shipped) |
46
+ | **Context** | `context/*.md` | Claude-readable generated files |
47
+ | **Core** | `core/` | Current task data |
48
+ | **Progress** | `progress/` | Historical progress tracking |
49
+ | **Planning** | `planning/` | Ideas, roadmap, specs, tasks |
50
+ | **Analysis** | `analysis/` | Repo analysis, tech stack |
51
+ | **Memory** | `memory/` | Events, patterns, semantic memories |
52
+ | **Agents** | `agents/` | Domain specialists (auto-generated) |
53
+ | **Sessions** | `sessions/YYYY/MM/DD/` | Daily session logs |
54
+ | **Sync** | `sync/` | Backend sync events |
47
55
 
48
56
  ### File Structure
49
57
  ```
50
58
  ~/.prjct-cli/projects/{projectId}/
59
+ ├── project.json # Project config (authors, version)
51
60
  ├── storage/
52
61
  │ ├── state.json # Current task (source of truth)
53
- │ ├── shipped.json # Shipped features
54
- │ └── queue.json # Task queue
62
+ │ ├── queue.json # Priority queue
63
+ │ └── shipped.json # Shipped features
55
64
  ├── context/
56
65
  │ ├── now.md # Generated from state.json
66
+ │ ├── next.md # Generated from queue.json
57
67
  │ └── shipped.md # Generated from shipped.json
58
- ├── sync/pending.json # Backend events
59
- ├── memory/events.jsonl # Audit trail
60
- └── agents/ # Domain specialists
68
+ ├── core/ # Current task context
69
+ ├── progress/ # Historical metrics
70
+ ├── planning/
71
+ │ ├── ideas.json # Captured ideas
72
+ │ ├── roadmap.json # Feature roadmap
73
+ │ └── tasks/ # Task breakdowns
74
+ ├── analysis/
75
+ │ └── repo-analysis.json # Tech stack, patterns
76
+ ├── memory/
77
+ │ ├── events.jsonl # Audit trail
78
+ │ └── context.jsonl # Semantic memories
79
+ ├── agents/ # Auto-generated domain specialists
80
+ ├── sessions/ # Daily session logs (YYYY/MM/DD/)
81
+ └── sync/
82
+ ├── pending.json # Events pending sync
83
+ └── last-sync.json # Last sync timestamp
61
84
  ```
62
85
 
63
86
  ## Core Workflow
@@ -68,15 +91,33 @@ User Action → Storage (JSON) → Context (MD) → Sync Events
68
91
 
69
92
  ## Commands
70
93
 
94
+ ### Core Commands (14)
71
95
  | Command | Purpose |
72
96
  |---------|---------|
73
- | `/p:sync` | Analyze repo, generate agents |
97
+ | `/p:init` | Initialize project with deep analysis |
98
+ | `/p:idea` | Transform ideas into architectures |
99
+ | `/p:feature` | Add feature with value analysis |
100
+ | `/p:spec` | Create detailed specifications |
74
101
  | `/p:now [task]` | Start/show current task |
102
+ | `/p:pause` | Pause active task |
103
+ | `/p:resume` | Resume paused task |
104
+ | `/p:next` | Show priority queue |
75
105
  | `/p:done` | Complete current task |
76
- | `/p:ship [feature]` | Ship with quality checks |
77
- | `/p:feature` | Add to roadmap |
78
- | `/p:idea` | Quick idea capture |
79
- | `/p:recap` | Project overview |
106
+ | `/p:ship` | Ship with quality checks |
107
+ | `/p:bug` | Report bug with auto-priority |
108
+ | `/p:dash` | Unified dashboard |
109
+ | `/p:sync` | Analyze repo, generate agents |
110
+ | `/p:suggest` | Context-aware recommendations |
111
+
112
+ ### Optional Commands
113
+ | Command | Purpose |
114
+ |---------|---------|
115
+ | `/p:design` | System architecture design |
116
+ | `/p:cleanup` | Clean temp files |
117
+ | `/p:analyze` | Deep repo analysis |
118
+ | `/p:undo` / `/p:redo` | Snapshot management |
119
+ | `/p:git` | Smart git operations |
120
+ | `/p:test` | Run tests with auto-fix |
80
121
 
81
122
  ## Natural Language Trigger
82
123
 
package/README.md CHANGED
@@ -425,25 +425,24 @@ prjct recap # Show progress
425
425
 
426
426
  ## 🧪 Testing
427
427
 
428
- prjct-cli uses **Vitest** with comprehensive test coverage for both the CLI core and website.
428
+ prjct-cli uses **Bun** (`bun test`) for unit tests.
429
429
 
430
430
  ### Quick Start
431
431
 
432
432
  ```bash
433
433
  # Run all tests
434
- npm test
434
+ bun test
435
435
 
436
436
  # Run tests in watch mode
437
- npm run test:watch
437
+ bun test --watch
438
438
 
439
439
  # Generate coverage report
440
- npm run test:coverage
440
+ bun test --coverage
441
441
  ```
442
442
 
443
443
  ### Test Suites
444
444
 
445
445
  - **Core CLI** (Node.js) - Agentic system, commands, and utilities
446
- - **Website** (React + TypeScript) - Component tests with Testing Library
447
446
 
448
447
  ### CI/CD
449
448
 
@@ -451,7 +450,7 @@ Tests run automatically on every push and pull request via GitHub Actions.
451
450
 
452
451
  [![Tests](https://github.com/jlopezlira/prjct-cli/actions/workflows/test.yml/badge.svg)](https://github.com/jlopezlira/prjct-cli/actions/workflows/test.yml)
453
452
 
454
- > 📖 **Full testing guide:** See [TESTING.md](TESTING.md) for detailed documentation, configuration, and best practices.
453
+ > 📖 **Full testing guide:** See [docs/TESTING.md](docs/TESTING.md) for detailed documentation, configuration, and best practices.
455
454
 
456
455
  ## ❓ FAQ
457
456
 
package/bin/prjct CHANGED
@@ -1,45 +1,62 @@
1
- #!/usr/bin/env bun
2
-
3
- /**
4
- * prjct CLI entry point
5
- *
6
- * Auto-setup on first use (like Astro, Vite, etc.)
7
- */
8
-
9
- import { VERSION } from '../core/utils/version.ts'
10
- import editorsConfig from '../core/infrastructure/editors-config.ts'
11
-
12
- // Check for special subcommands that bypass normal CLI
13
- const args = process.argv.slice(2)
14
-
15
- if (args[0] === 'dev') {
16
- // Launch prjct dev environment
17
- await import('./dev.js')
18
- process.exitCode = 0
19
- } else if (args[0] === 'web' || args[0] === 'serve') {
20
- // Launch prjct web server
21
- await import('./serve.js')
22
- process.exitCode = 0
23
- } else {
24
- // Ensure setup has run for this version
25
- try {
26
- const lastVersion = await editorsConfig.getLastVersion()
27
-
28
- if (!lastVersion || lastVersion !== VERSION) {
29
- console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
30
- console.log('🔧 One-time setup (v' + VERSION + ')...')
31
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')
32
-
33
- const { default: setup } = await import('../core/infrastructure/setup.ts')
34
- await setup.run()
35
-
36
- console.log('✓ Setup complete!\n')
1
+ #!/bin/sh
2
+
3
+ # prjct CLI - Runtime-agnostic entry point
4
+ #
5
+ # Detects available runtime (bun preferred, node fallback)
6
+ # and executes the appropriate entry point.
7
+ #
8
+ # @version 1.0.0
9
+
10
+ # Get the directory where this script is located
11
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
+ ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
+
14
+ # Check if bun is available
15
+ check_bun() {
16
+ command -v bun >/dev/null 2>&1
17
+ }
18
+
19
+ # Check if node is available
20
+ check_node() {
21
+ command -v node >/dev/null 2>&1
22
+ }
23
+
24
+ # Run with bun (native TypeScript)
25
+ run_with_bun() {
26
+ exec bun "$SCRIPT_DIR/prjct.ts" "$@"
27
+ }
28
+
29
+ # Run with node (compiled JavaScript)
30
+ run_with_node() {
31
+ DIST_BIN="$ROOT_DIR/dist/bin/prjct.mjs"
32
+
33
+ # Check if compiled version exists
34
+ if [ ! -f "$DIST_BIN" ]; then
35
+ echo "Building for Node.js (first run)..."
36
+ node "$ROOT_DIR/scripts/build.js" || {
37
+ echo "Error: Build failed. Please ensure you have write permissions."
38
+ exit 1
37
39
  }
38
- } catch (error) {
39
- console.error('\n⚠️ Setup warning:', (error as Error).message)
40
- console.error('You can run setup manually: prjct setup\n')
41
- }
40
+ fi
42
41
 
43
- // Continue to main CLI logic
44
- await import('../core/index.ts')
42
+ exec node "$DIST_BIN" "$@"
45
43
  }
44
+
45
+ # Main execution
46
+ main() {
47
+ # Prefer bun if available (faster, native TS support)
48
+ if check_bun; then
49
+ run_with_bun "$@"
50
+ elif check_node; then
51
+ run_with_node "$@"
52
+ else
53
+ echo "Error: Neither bun nor node is installed."
54
+ echo ""
55
+ echo "Please install one of:"
56
+ echo " - Bun (recommended): https://bun.sh"
57
+ echo " - Node.js 18+: https://nodejs.org"
58
+ exit 1
59
+ fi
60
+ }
61
+
62
+ main "$@"
package/bin/prjct.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * prjct CLI entry point
3
+ *
4
+ * Auto-setup on first use (like Astro, Vite, etc.)
5
+ * Supports both Bun and Node.js runtimes.
6
+ */
7
+
8
+ import { VERSION } from '../core/utils/version'
9
+ import editorsConfig from '../core/infrastructure/editors-config'
10
+ import { startServer, DEFAULT_PORT } from '../core/server/server'
11
+ import configManager from '../core/infrastructure/config-manager'
12
+
13
+ // Check for special subcommands that bypass normal CLI
14
+ const args = process.argv.slice(2)
15
+
16
+ if (args[0] === 'dev') {
17
+ // Dev mode - placeholder for future development server
18
+ console.log('Dev mode is not yet implemented.')
19
+ console.log('Use "prjct serve" to start the web server.')
20
+ process.exitCode = 0
21
+ } else if (args[0] === 'web' || args[0] === 'serve') {
22
+ // Launch prjct web server
23
+ try {
24
+ const projectPath = process.cwd()
25
+ const projectId = await configManager.getProjectId(projectPath)
26
+
27
+ if (!projectId) {
28
+ console.error('No prjct project found. Run "prjct init" first.')
29
+ process.exitCode = 1
30
+ } else {
31
+ const port = parseInt(args[1]) || DEFAULT_PORT
32
+ await startServer(projectId, projectPath, port)
33
+ }
34
+ } catch (error) {
35
+ console.error('Server error:', (error as Error).message)
36
+ process.exitCode = 1
37
+ }
38
+ } else {
39
+ // Ensure setup has run for this version
40
+ try {
41
+ const lastVersion = await editorsConfig.getLastVersion()
42
+
43
+ if (!lastVersion || lastVersion !== VERSION) {
44
+ console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
45
+ console.log('🔧 One-time setup (v' + VERSION + ')...')
46
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n')
47
+
48
+ const { default: setup } = await import('../core/infrastructure/setup')
49
+ await setup.run()
50
+
51
+ console.log('✓ Setup complete!\n')
52
+ }
53
+ } catch (error) {
54
+ console.error('\n⚠️ Setup warning:', (error as Error).message)
55
+ console.error('You can run setup manually: prjct setup\n')
56
+ }
57
+
58
+ // Continue to main CLI logic
59
+ await import('../core/index')
60
+ }
@@ -3,17 +3,24 @@
3
3
  * P3.3: Semantic Memory Database
4
4
  */
5
5
 
6
- import { describe, it, expect, beforeEach, afterEach } from 'bun:test'
6
+ import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'bun:test'
7
7
  import memorySystem from '../../agentic/memory-system'
8
+ import pathManager from '../../infrastructure/path-manager'
8
9
  import fs from 'fs/promises'
9
10
  import path from 'path'
10
- import os from 'os'
11
11
 
12
12
  let testCounter = 0
13
13
  const getTestProjectId = () => `test-memory-${Date.now()}-${++testCounter}`
14
14
 
15
15
  describe('MemorySystem P3.3', () => {
16
16
  let TEST_PROJECT_ID: string
17
+ const TEST_GLOBAL_BASE_DIR = path.join(process.cwd(), '.tmp', 'prjct-cli-tests')
18
+
19
+ beforeAll(async () => {
20
+ // Reason: In sandboxed test environments we can't write to "~/.prjct-cli".
21
+ pathManager.setGlobalBaseDir(TEST_GLOBAL_BASE_DIR)
22
+ await fs.mkdir(TEST_GLOBAL_BASE_DIR, { recursive: true })
23
+ })
17
24
 
18
25
  beforeEach(() => {
19
26
  TEST_PROJECT_ID = getTestProjectId()
@@ -244,10 +251,18 @@ describe('MemorySystem P3.3', () => {
244
251
 
245
252
  afterEach(async () => {
246
253
  try {
247
- const testPath = path.join(os.homedir(), '.prjct-cli', 'projects', TEST_PROJECT_ID)
254
+ const testPath = pathManager.getGlobalProjectPath(TEST_PROJECT_ID)
248
255
  await fs.rm(testPath, { recursive: true, force: true })
249
256
  } catch {
250
257
  // Ignore cleanup errors
251
258
  }
252
259
  })
260
+
261
+ afterAll(async () => {
262
+ try {
263
+ await fs.rm(TEST_GLOBAL_BASE_DIR, { recursive: true, force: true })
264
+ } catch {
265
+ // Ignore cleanup errors
266
+ }
267
+ })
253
268
  })
@@ -10,6 +10,25 @@ import planMode, {
10
10
  DESTRUCTIVE_COMMANDS,
11
11
  PLANNING_TOOLS
12
12
  } from '../../agentic/plan-mode'
13
+ import type { ProposedPlan, ApprovalContext, ChangedFile } from '../../types'
14
+
15
+ // Helper to create complete ProposedPlan objects
16
+ const createPlan = (overrides: Partial<ProposedPlan> = {}): ProposedPlan => ({
17
+ summary: 'Test summary',
18
+ approach: 'Test approach',
19
+ steps: [],
20
+ affectedFiles: [],
21
+ ...overrides,
22
+ })
23
+
24
+ // Helper to create complete ApprovalContext objects
25
+ const createApprovalContext = (overrides: Partial<ApprovalContext> = {}): ApprovalContext => ({
26
+ changedFiles: [],
27
+ filesToDelete: [],
28
+ operation: 'modify_files',
29
+ warnings: [],
30
+ ...overrides,
31
+ })
13
32
 
14
33
  describe('PlanMode P3.4', () => {
15
34
  const TEST_PROJECT_ID = 'test-plan-mode'
@@ -116,7 +135,7 @@ describe('PlanMode P3.4', () => {
116
135
 
117
136
  it('should return true when pending approval', () => {
118
137
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
119
- planMode.proposePlan(TEST_PROJECT_ID, { summary: 'Test', steps: [] })
138
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan())
120
139
 
121
140
  expect(planMode.isInPlanningMode(TEST_PROJECT_ID)).toBe(true)
122
141
  })
@@ -127,7 +146,7 @@ describe('PlanMode P3.4', () => {
127
146
 
128
147
  it('should return false when plan is executing', () => {
129
148
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
130
- planMode.proposePlan(TEST_PROJECT_ID, { summary: 'Test', steps: [{ description: 'Step 1' }] })
149
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({ steps: [{ description: 'Step 1' }] }))
131
150
  planMode.approvePlan(TEST_PROJECT_ID)
132
151
  planMode.startExecution(TEST_PROJECT_ID)
133
152
 
@@ -138,22 +157,27 @@ describe('PlanMode P3.4', () => {
138
157
  describe('recordGatheredInfo', () => {
139
158
  it('should add info to gatheredInfo array', () => {
140
159
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
141
- planMode.recordGatheredInfo(TEST_PROJECT_ID, { type: 'file', source: 'src/index.js', data: 'content' })
160
+ planMode.recordGatheredInfo(TEST_PROJECT_ID, {
161
+ type: 'file_content',
162
+ source: 'src/index.js',
163
+ data: 'content',
164
+ gatheredAt: new Date().toISOString()
165
+ })
142
166
 
143
167
  const plan = planMode.getActivePlan(TEST_PROJECT_ID)
144
168
  expect(plan!.gatheredInfo.length).toBe(1)
145
- expect(plan!.gatheredInfo[0].type).toBe('file')
169
+ expect(plan!.gatheredInfo[0].type).toBe('file_content')
146
170
  })
147
171
  })
148
172
 
149
173
  describe('proposePlan', () => {
150
174
  it('should set status to pending approval', () => {
151
175
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
152
- planMode.proposePlan(TEST_PROJECT_ID, {
176
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({
153
177
  summary: 'Add dark mode feature',
154
178
  approach: 'CSS variables with theme context',
155
179
  steps: [{ description: 'Create theme context' }, { description: 'Add toggle' }]
156
- })
180
+ }))
157
181
 
158
182
  const plan = planMode.getActivePlan(TEST_PROJECT_ID)
159
183
  expect(plan!.status).toBe(PLAN_STATUS.PENDING_APPROVAL)
@@ -161,11 +185,11 @@ describe('PlanMode P3.4', () => {
161
185
 
162
186
  it('should return formatted plan for display', () => {
163
187
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
164
- const formatted = planMode.proposePlan(TEST_PROJECT_ID, {
188
+ const formatted = planMode.proposePlan(TEST_PROJECT_ID, createPlan({
165
189
  summary: 'Test plan',
166
190
  approach: 'Test approach',
167
191
  steps: [{ description: 'Step 1' }]
168
- })
192
+ }))
169
193
 
170
194
  expect(formatted!.summary).toBe('Test plan')
171
195
  expect(formatted!.approach).toBe('Test approach')
@@ -176,7 +200,7 @@ describe('PlanMode P3.4', () => {
176
200
  describe('approvePlan', () => {
177
201
  it('should change status to approved', () => {
178
202
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
179
- planMode.proposePlan(TEST_PROJECT_ID, { steps: [{ description: 'Step 1' }] })
203
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({ steps: [{ description: 'Step 1' }] }))
180
204
  const result = planMode.approvePlan(TEST_PROJECT_ID)
181
205
 
182
206
  expect(result!.approved).toBe(true)
@@ -186,9 +210,9 @@ describe('PlanMode P3.4', () => {
186
210
 
187
211
  it('should convert proposed steps to executable steps', () => {
188
212
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
189
- planMode.proposePlan(TEST_PROJECT_ID, {
213
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({
190
214
  steps: [{ description: 'Step 1' }, { description: 'Step 2' }]
191
- })
215
+ }))
192
216
  const result = planMode.approvePlan(TEST_PROJECT_ID)
193
217
 
194
218
  expect(result!.steps.length).toBe(2)
@@ -206,7 +230,7 @@ describe('PlanMode P3.4', () => {
206
230
  describe('rejectPlan', () => {
207
231
  it('should mark plan as rejected', () => {
208
232
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
209
- planMode.proposePlan(TEST_PROJECT_ID, { steps: [] })
233
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan())
210
234
  const result = planMode.rejectPlan(TEST_PROJECT_ID, 'Not the right approach')
211
235
 
212
236
  expect(result!.rejected).toBe(true)
@@ -215,7 +239,7 @@ describe('PlanMode P3.4', () => {
215
239
 
216
240
  it('should clear active plan after rejection', () => {
217
241
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
218
- planMode.proposePlan(TEST_PROJECT_ID, { steps: [] })
242
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan())
219
243
  planMode.rejectPlan(TEST_PROJECT_ID)
220
244
 
221
245
  expect(planMode.getActivePlan(TEST_PROJECT_ID)).toBeNull()
@@ -225,12 +249,12 @@ describe('PlanMode P3.4', () => {
225
249
  describe('execution flow', () => {
226
250
  beforeEach(() => {
227
251
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
228
- planMode.proposePlan(TEST_PROJECT_ID, {
252
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({
229
253
  steps: [
230
254
  { description: 'Step 1', tool: 'Write' },
231
255
  { description: 'Step 2', tool: 'Bash' }
232
256
  ]
233
- })
257
+ }))
234
258
  planMode.approvePlan(TEST_PROJECT_ID)
235
259
  })
236
260
 
@@ -263,7 +287,7 @@ describe('PlanMode P3.4', () => {
263
287
  describe('abortPlan', () => {
264
288
  it('should abort and clear active plan', () => {
265
289
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
266
- planMode.proposePlan(TEST_PROJECT_ID, { steps: [{ description: 'Step 1' }] })
290
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({ steps: [{ description: 'Step 1' }] }))
267
291
  planMode.approvePlan(TEST_PROJECT_ID)
268
292
  planMode.startExecution(TEST_PROJECT_ID)
269
293
 
@@ -277,11 +301,15 @@ describe('PlanMode P3.4', () => {
277
301
 
278
302
  describe('generateApprovalPrompt', () => {
279
303
  it('should generate ship approval prompt', () => {
280
- const prompt = planMode.generateApprovalPrompt('ship', {
304
+ const prompt = planMode.generateApprovalPrompt('ship', createApprovalContext({
281
305
  branch: 'feature/dark-mode',
282
- changedFiles: ['a.js', 'b.js'],
283
- commitMessage: 'Add dark mode'
284
- })
306
+ changedFiles: [
307
+ { path: 'a.js', action: 'modify' },
308
+ { path: 'b.js', action: 'modify' }
309
+ ],
310
+ commitMessage: 'Add dark mode',
311
+ operation: 'git_push'
312
+ }))
285
313
 
286
314
  expect(prompt.title).toBe('Ship Confirmation')
287
315
  expect(prompt.details).toContain('Branch: feature/dark-mode')
@@ -289,17 +317,18 @@ describe('PlanMode P3.4', () => {
289
317
  })
290
318
 
291
319
  it('should generate cleanup approval prompt', () => {
292
- const prompt = planMode.generateApprovalPrompt('cleanup', {
320
+ const prompt = planMode.generateApprovalPrompt('cleanup', createApprovalContext({
293
321
  filesToDelete: ['temp.js'],
294
- linesOfCode: 50
295
- })
322
+ linesOfCode: 50,
323
+ operation: 'delete_files'
324
+ }))
296
325
 
297
326
  expect(prompt.title).toBe('Cleanup Confirmation')
298
327
  expect(prompt.message).toContain('delete')
299
328
  })
300
329
 
301
330
  it('should generate default prompt for unknown commands', () => {
302
- const prompt = planMode.generateApprovalPrompt('unknown', {})
331
+ const prompt = planMode.generateApprovalPrompt('unknown', createApprovalContext())
303
332
 
304
333
  expect(prompt.title).toBe('Confirmation Required')
305
334
  expect(prompt.options.length).toBe(2)
@@ -318,9 +347,9 @@ describe('PlanMode P3.4', () => {
318
347
 
319
348
  it('should show progress during execution', () => {
320
349
  planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
321
- planMode.proposePlan(TEST_PROJECT_ID, {
350
+ planMode.proposePlan(TEST_PROJECT_ID, createPlan({
322
351
  steps: [{ description: 'Step 1' }, { description: 'Step 2' }]
323
- })
352
+ }))
324
353
  planMode.approvePlan(TEST_PROJECT_ID)
325
354
  planMode.startExecution(TEST_PROJECT_ID)
326
355