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
@@ -59,7 +59,7 @@ jobs:
59
59
  with:
60
60
  node-version: '20'
61
61
  - run: npm ci
62
- - run: npm test
62
+ - run: npm test # or pnpm test / yarn test / bun test depending on the repo
63
63
  ```
64
64
 
65
65
  ### docker-compose
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: testing
3
- description: Testing specialist for Jest, Vitest, Pytest, and testing libraries. Use PROACTIVELY when user works on tests, coverage, or test infrastructure.
3
+ description: Testing specialist for Bun test, Jest, Pytest, and testing libraries. Use PROACTIVELY when user works on tests, coverage, or test infrastructure.
4
4
  tools: Read, Write, Bash
5
5
  model: sonnet
6
6
  ---
@@ -9,7 +9,7 @@ You are a testing specialist agent for this project.
9
9
 
10
10
  ## Your Expertise
11
11
 
12
- - **JS/TS**: Jest, Vitest, Mocha, Bun test
12
+ - **JS/TS**: Bun test, Jest, Mocha
13
13
  - **React**: Testing Library, Enzyme
14
14
  - **Python**: Pytest, unittest
15
15
  - **Go**: testing package, testify
@@ -18,15 +18,15 @@ You are a testing specialist agent for this project.
18
18
  ## Project Context
19
19
 
20
20
  When invoked, analyze the project's testing setup:
21
- 1. Check for test config (jest.config.js, vitest.config.ts, pytest.ini)
21
+ 1. Check for test config (bunfig.toml, jest.config.js, pytest.ini)
22
22
  2. Identify test file patterns
23
23
  3. Check for existing test utilities
24
24
 
25
25
  ## Code Patterns
26
26
 
27
- ### Vitest/Jest (Unit)
27
+ ### Bun (Unit)
28
28
  ```typescript
29
- import { describe, it, expect, vi } from 'vitest'
29
+ import { describe, it, expect, mock } from 'bun:test'
30
30
  import { calculateTotal } from './cart'
31
31
 
32
32
  describe('calculateTotal', () => {
@@ -48,7 +48,7 @@ import { Button } from './Button'
48
48
 
49
49
  describe('Button', () => {
50
50
  it('calls onClick when clicked', () => {
51
- const onClick = vi.fn()
51
+ const onClick = mock(() => {})
52
52
  render(<Button onClick={onClick}>Click me</Button>)
53
53
 
54
54
  fireEvent.click(screen.getByRole('button'))
@@ -118,7 +118,6 @@ func TestCalculateTotal(t *testing.T) {
118
118
  # JavaScript
119
119
  npm test
120
120
  bun test
121
- vitest run
122
121
 
123
122
  # Python
124
123
  pytest
@@ -131,9 +130,6 @@ go test -cover ./...
131
130
 
132
131
  ### Coverage
133
132
  ```bash
134
- # Vitest
135
- vitest run --coverage
136
-
137
133
  # Jest
138
134
  jest --coverage
139
135
 
@@ -30,13 +30,22 @@ Run in sequence, stop on failure:
30
30
 
31
31
  ```bash
32
32
  # 1. Lint (if configured)
33
- npm run lint || bun run lint
33
+ # Use the project's own tooling (do not assume JS/Bun).
34
+ # Examples:
35
+ # - JS: pnpm run lint / yarn lint / npm run lint / bun run lint
36
+ # - Python: ruff/flake8 (only if project already uses it)
34
37
 
35
- # 2. Type check (if TypeScript)
36
- npm run typecheck || tsc --noEmit
38
+ # 2. Type check (if configured)
39
+ # - TS: pnpm run typecheck / yarn typecheck / npm run typecheck / bun run typecheck
37
40
 
38
41
  # 3. Tests (if configured)
39
- npm test || bun test
42
+ # Use the project's own test runner:
43
+ # - JS: {packageManager} test (e.g. pnpm test, yarn test, npm test, bun test)
44
+ # - Python: pytest
45
+ # - Go: go test ./...
46
+ # - Rust: cargo test
47
+ # - .NET: dotnet test
48
+ # - Java: mvn test / ./gradlew test
40
49
  ```
41
50
 
42
51
  If any fail:
@@ -125,12 +134,12 @@ Read from `.prjct/ship.config.json` if exists:
125
134
  "typecheck": true,
126
135
  "test": true
127
136
  },
128
- "testCommand": "bun test",
129
- "lintCommand": "bun run lint"
137
+ "testCommand": "pytest",
138
+ "lintCommand": "npm run lint"
130
139
  }
131
140
  ```
132
141
 
133
- If no config, auto-detect from package.json scripts.
142
+ If no config, auto-detect from the repository (package.json scripts, pytest.ini, Cargo.toml, go.mod, etc.).
134
143
 
135
144
  ## Dry Run Mode
136
145
 
@@ -0,0 +1,22 @@
1
+ Execute shell commands in a persistent bash session.
2
+
3
+ Use this tool for terminal operations like git, npm, docker, build commands, and system utilities. NOT for file operations (use Read, Write, Edit instead).
4
+
5
+ Capabilities:
6
+ - Run any shell command
7
+ - Persistent session (environment persists between calls)
8
+ - Support for background execution
9
+ - Configurable timeout (up to 10 minutes)
10
+
11
+ Best practices:
12
+ - Quote paths with spaces using double quotes
13
+ - Use absolute paths to avoid cd
14
+ - Chain dependent commands with &&
15
+ - Run independent commands in parallel (multiple tool calls)
16
+ - Never use for file reading (use Read tool)
17
+ - Never use echo/printf to communicate (output text directly)
18
+
19
+ Git operations:
20
+ - Never update git config
21
+ - Never use destructive commands without explicit request
22
+ - Always use HEREDOC for commit messages
@@ -0,0 +1,18 @@
1
+ Edit files using exact string replacement.
2
+
3
+ Use this tool to make precise changes to existing files. Requires reading the file first to ensure accurate matching.
4
+
5
+ Capabilities:
6
+ - Replace exact string matches in files
7
+ - Support for replace_all to change all occurrences
8
+ - Preserves file formatting and indentation
9
+
10
+ Requirements:
11
+ - Must read the file first (tool will error otherwise)
12
+ - old_string must be unique in the file (or use replace_all)
13
+ - Preserve exact indentation from the original
14
+
15
+ Best practices:
16
+ - Include enough context to make old_string unique
17
+ - Use replace_all for renaming variables/functions
18
+ - Never include line numbers in old_string or new_string
@@ -0,0 +1,19 @@
1
+ Find files by pattern matching.
2
+
3
+ Use this tool to locate files using glob patterns. Fast and efficient for any codebase size.
4
+
5
+ Capabilities:
6
+ - Match files using glob patterns (e.g., "**/*.ts", "src/**/*.tsx")
7
+ - Returns paths sorted by modification time
8
+ - Works with any codebase size
9
+
10
+ Pattern examples:
11
+ - "**/*.ts" - all TypeScript files
12
+ - "src/**/*.tsx" - React components in src
13
+ - "**/test*.ts" - test files anywhere
14
+ - "core/**/*" - all files in core directory
15
+
16
+ Best practices:
17
+ - Use specific patterns to narrow results
18
+ - Prefer glob over bash find command
19
+ - Run multiple patterns in parallel if needed
@@ -0,0 +1,21 @@
1
+ Search file contents using regex patterns.
2
+
3
+ Use this tool to search for code patterns, function definitions, imports, and text across the codebase. Built on ripgrep for speed.
4
+
5
+ Capabilities:
6
+ - Full regex syntax support
7
+ - Filter by file type or glob pattern
8
+ - Multiple output modes: files_with_matches, content, count
9
+ - Context lines before/after matches (-A, -B, -C)
10
+ - Multiline matching support
11
+
12
+ Output modes:
13
+ - files_with_matches (default): just file paths
14
+ - content: matching lines with context
15
+ - count: match counts per file
16
+
17
+ Best practices:
18
+ - Use specific patterns to reduce noise
19
+ - Filter by file type when possible (type: "ts")
20
+ - Use content mode with context for understanding matches
21
+ - Never use bash grep/rg directly (use this tool)
@@ -0,0 +1,14 @@
1
+ Read files from the filesystem.
2
+
3
+ Use this tool to read file contents before making edits. Always read a file before attempting to modify it to understand the current state and structure.
4
+
5
+ Capabilities:
6
+ - Read any text file by absolute path
7
+ - Supports line offset and limit for large files
8
+ - Returns content with line numbers for easy reference
9
+ - Can read images, PDFs, and Jupyter notebooks
10
+
11
+ Best practices:
12
+ - Always read before editing
13
+ - Use offset/limit for files > 2000 lines
14
+ - Read multiple related files in parallel when exploring
@@ -0,0 +1,20 @@
1
+ Launch specialized agents for complex tasks.
2
+
3
+ Use this tool to delegate multi-step tasks to autonomous agents. Each agent type has specific capabilities and tools.
4
+
5
+ Agent types:
6
+ - Explore: Fast codebase exploration, file search, pattern finding
7
+ - Plan: Software architecture, implementation planning
8
+ - general-purpose: Research, code search, multi-step tasks
9
+
10
+ When to use:
11
+ - Complex multi-step tasks
12
+ - Open-ended exploration
13
+ - When multiple search rounds may be needed
14
+ - Tasks matching agent descriptions
15
+
16
+ Best practices:
17
+ - Provide clear, detailed prompts
18
+ - Launch multiple agents in parallel when independent
19
+ - Use Explore for codebase questions
20
+ - Use Plan for implementation design
@@ -0,0 +1,16 @@
1
+ Fetch and analyze web content.
2
+
3
+ Use this tool to retrieve content from URLs and process it with AI. Useful for documentation, API references, and external resources.
4
+
5
+ Capabilities:
6
+ - Fetch any URL content
7
+ - Automatic HTML to markdown conversion
8
+ - AI-powered content extraction based on prompt
9
+ - 15-minute cache for repeated requests
10
+ - Automatic HTTP to HTTPS upgrade
11
+
12
+ Best practices:
13
+ - Provide specific prompts for extraction
14
+ - Handle redirects by following the provided URL
15
+ - Use for documentation and reference lookup
16
+ - Results may be summarized for large content
@@ -0,0 +1,18 @@
1
+ Search the web for current information.
2
+
3
+ Use this tool to find up-to-date information beyond the knowledge cutoff. Returns search results with links.
4
+
5
+ Capabilities:
6
+ - Real-time web search
7
+ - Domain filtering (allow/block specific sites)
8
+ - Returns formatted results with URLs
9
+
10
+ Requirements:
11
+ - MUST include Sources section with URLs after answering
12
+ - Use current year in queries for recent info
13
+
14
+ Best practices:
15
+ - Be specific in search queries
16
+ - Include year for time-sensitive searches
17
+ - Always cite sources in response
18
+ - Filter domains when targeting specific sites
@@ -0,0 +1,17 @@
1
+ Write or create files on the filesystem.
2
+
3
+ Use this tool to create new files or completely overwrite existing ones. For modifications to existing files, prefer the Edit tool instead.
4
+
5
+ Capabilities:
6
+ - Create new files with specified content
7
+ - Overwrite existing files completely
8
+ - Create parent directories automatically
9
+
10
+ Requirements:
11
+ - Must read existing file first before overwriting
12
+ - Use absolute paths only
13
+
14
+ Best practices:
15
+ - Prefer Edit for modifications to existing files
16
+ - Only create new files when truly necessary
17
+ - Never create documentation files unless explicitly requested
@@ -1,312 +0,0 @@
1
- /**
2
- * Command Executor Class
3
- * Orchestrates command execution with agentic delegation.
4
- */
5
-
6
- import path from 'path'
7
- import os from 'os'
8
- import templateLoader from '../template-loader'
9
- import contextBuilder from '../context-builder'
10
- import promptBuilder from '../prompt-builder'
11
- import toolRegistry from '../tool-registry'
12
- import loopDetector from '../loop-detector'
13
- import chainOfThought from '../chain-of-thought'
14
- import memorySystem from '../memory-system'
15
- import groundTruth from '../ground-truth'
16
- import planMode from '../plan-mode'
17
- import { signalStart, signalEnd } from './status-signal'
18
- import type { ExecutionResult, SimpleExecutionResult, ExecutionToolsFn } from './types'
19
-
20
- export class CommandExecutor {
21
- /**
22
- * Signal that a command is running (for status line)
23
- */
24
- signalStart(commandName: string): void {
25
- signalStart(commandName)
26
- }
27
-
28
- /**
29
- * Signal that command has finished (for status line)
30
- */
31
- signalEnd(): void {
32
- signalEnd()
33
- }
34
-
35
- /**
36
- * Execute a prjct command with full agentic delegation
37
- */
38
- async execute(
39
- commandName: string,
40
- params: Record<string, unknown>,
41
- projectPath: string
42
- ): Promise<ExecutionResult> {
43
- // Signal start for status line
44
- this.signalStart(commandName)
45
-
46
- // Context for loop detection
47
- const loopContext = (params.task as string) || (params.description as string) || ''
48
-
49
- // Check if we're in a loop BEFORE attempting
50
- if (loopDetector.shouldEscalate(commandName, loopContext)) {
51
- const escalation = loopDetector.getEscalationInfo(commandName, loopContext)
52
- this.signalEnd()
53
- return {
54
- success: false,
55
- error: escalation?.message,
56
- escalation,
57
- isLoopDetected: true,
58
- suggestion: escalation?.suggestion,
59
- }
60
- }
61
-
62
- try {
63
- // 1. Load template
64
- const template = await templateLoader.load(commandName)
65
-
66
- // 2. Build METADATA context only (lazy loading - no file reads yet)
67
- const metadataContext = await contextBuilder.build(projectPath, params)
68
-
69
- // 2.55. P3.4 PLAN MODE: Check if command requires planning
70
- const requiresPlanning = planMode.requiresPlanning(commandName)
71
- const isDestructive = planMode.isDestructive(commandName)
72
- const isInPlanningMode = planMode.isInPlanningMode(metadataContext.projectId!)
73
-
74
- // Start planning mode if required and not already in it
75
- let activePlan = null
76
- if (requiresPlanning && !isInPlanningMode && !params.skipPlanning) {
77
- activePlan = planMode.startPlanning(metadataContext.projectId!, commandName, params)
78
- } else if (isInPlanningMode) {
79
- activePlan = planMode.getActivePlan(metadataContext.projectId!)
80
- }
81
-
82
- // 2.6. GROUND TRUTH: Verify actual state before critical operations
83
- let groundTruthResult = null
84
- if (groundTruth.requiresVerification(commandName)) {
85
- const preState = await contextBuilder.loadStateForCommand(metadataContext, commandName)
86
- groundTruthResult = await groundTruth.verify(
87
- commandName,
88
- metadataContext as unknown as Parameters<typeof groundTruth.verify>[1],
89
- preState
90
- )
91
-
92
- // Log warnings but don't block (user can override)
93
- if (!groundTruthResult.verified && groundTruthResult.warnings.length > 0) {
94
- console.log(groundTruth.formatWarnings(groundTruthResult))
95
- }
96
- }
97
-
98
- // 2.8. CHAIN OF THOUGHT: Reasoning for critical commands
99
- let reasoning = null
100
- if (chainOfThought.requiresReasoning(commandName)) {
101
- const reasoningState = await contextBuilder.loadStateForCommand(metadataContext, commandName)
102
- reasoning = await chainOfThought.reason(
103
- commandName,
104
- metadataContext as unknown as Parameters<typeof chainOfThought.reason>[1],
105
- reasoningState as Parameters<typeof chainOfThought.reason>[2]
106
- )
107
-
108
- // If reasoning shows critical issues, warn but continue
109
- if (reasoning.reasoning && !reasoning.reasoning.allPassed) {
110
- console.log('⚠️ Chain of Thought detected issues:')
111
- console.log(chainOfThought.formatPlan(reasoning))
112
- }
113
- }
114
-
115
- // 3. AGENTIC: Claude decides agent assignment via templates
116
- let context: Record<string, unknown> = metadataContext as unknown as Record<string, unknown>
117
-
118
- // Provide agent info to context so Claude can delegate
119
- context = {
120
- ...context,
121
- agentsPath: path.join(os.homedir(), '.prjct-cli', 'projects', metadataContext.projectId || '', 'agents'),
122
- agentRoutingPath: path.join(__dirname, '..', '..', '..', 'templates', 'agentic', 'agent-routing.md'),
123
- agenticDelegation: true,
124
- }
125
-
126
- // 6. Load state with filtered context
127
- const state = await contextBuilder.loadState(metadataContext)
128
-
129
- // 7. MEMORY: Load learned patterns AND relevant memories for this command
130
- let learnedPatterns = null
131
- let relevantMemories = null
132
- if (metadataContext.projectId) {
133
- learnedPatterns = {
134
- commit_footer: await memorySystem.getSmartDecision(metadataContext.projectId, 'commit_footer'),
135
- branch_naming: await memorySystem.getSmartDecision(metadataContext.projectId, 'branch_naming'),
136
- test_before_ship: await memorySystem.getSmartDecision(metadataContext.projectId, 'test_before_ship'),
137
- preferred_agent: await memorySystem.getSmartDecision(
138
- metadataContext.projectId,
139
- `preferred_agent_${commandName}`
140
- ),
141
- }
142
-
143
- // P3.3: Get relevant memories for context
144
- relevantMemories = await memorySystem.getRelevantMemories(
145
- metadataContext.projectId,
146
- { commandName, params },
147
- 5
148
- )
149
- }
150
-
151
- // 9. Build prompt - NO agent assignment here, Claude decides via templates
152
- const planInfo = {
153
- isPlanning: requiresPlanning || isInPlanningMode,
154
- requiresApproval: isDestructive && !params.approved,
155
- active: activePlan,
156
- allowedTools: planMode.getAllowedTools(isInPlanningMode, template.frontmatter['allowed-tools'] || []),
157
- }
158
- // Agent is null - Claude assigns via Task tool using agent-routing.md
159
- const prompt = promptBuilder.build(
160
- template,
161
- context as Parameters<typeof promptBuilder.build>[1],
162
- state,
163
- null,
164
- learnedPatterns,
165
- null,
166
- relevantMemories,
167
- planInfo
168
- )
169
-
170
- // Log agentic mode
171
- console.log(`🤖 Agentic delegation enabled - Claude will assign agent via Task tool`)
172
-
173
- // Record successful attempt
174
- loopDetector.recordSuccess(commandName, loopContext)
175
-
176
- // Signal end for status line
177
- this.signalEnd()
178
-
179
- return {
180
- success: true,
181
- template,
182
- context,
183
- state,
184
- prompt,
185
- agenticDelegation: true,
186
- agentsPath: context.agentsPath as string,
187
- agentRoutingPath: context.agentRoutingPath as string,
188
- reasoning,
189
- groundTruth: groundTruthResult,
190
- learnedPatterns,
191
- relevantMemories,
192
- memory: {
193
- create: (memory: unknown) =>
194
- memorySystem.createMemory(metadataContext.projectId!, memory as Parameters<typeof memorySystem.createMemory>[1]),
195
- autoRemember: (type: string, value: string, ctx?: string) =>
196
- memorySystem.autoRemember(metadataContext.projectId!, type, value, ctx),
197
- search: (query: string) => memorySystem.searchMemories(metadataContext.projectId!, query),
198
- findByTags: (tags: string[]) => memorySystem.findByTags(metadataContext.projectId!, tags),
199
- getStats: () => memorySystem.getMemoryStats(metadataContext.projectId!),
200
- },
201
- plan: {
202
- active: activePlan,
203
- isPlanning: requiresPlanning || isInPlanningMode,
204
- isDestructive,
205
- requiresApproval: isDestructive && !params.approved,
206
- recordInfo: (info: unknown) =>
207
- planMode.recordGatheredInfo(metadataContext.projectId!, info as Parameters<typeof planMode.recordGatheredInfo>[1]),
208
- setAnalysis: (analysis: unknown) => planMode.setAnalysis(metadataContext.projectId!, analysis),
209
- propose: (plan: unknown) =>
210
- planMode.proposePlan(metadataContext.projectId!, plan as Parameters<typeof planMode.proposePlan>[1]),
211
- approve: (feedback?: string | null) => planMode.approvePlan(metadataContext.projectId!, feedback),
212
- reject: (reason?: string | null) => planMode.rejectPlan(metadataContext.projectId!, reason),
213
- getApprovalPrompt: () =>
214
- planMode.generateApprovalPrompt(commandName, context as Parameters<typeof planMode.generateApprovalPrompt>[1]),
215
- startExecution: () => planMode.startExecution(metadataContext.projectId!),
216
- getNextStep: () => planMode.getNextStep(metadataContext.projectId!),
217
- completeStep: (result?: unknown) => planMode.completeStep(metadataContext.projectId!, result),
218
- failStep: (error: string) => planMode.failStep(metadataContext.projectId!, error),
219
- abort: (reason?: string) => planMode.abortPlan(metadataContext.projectId!, reason),
220
- getStatus: () => planMode.formatStatus(metadataContext.projectId!),
221
- getAllowedTools: () =>
222
- planMode.getAllowedTools(isInPlanningMode, template.frontmatter['allowed-tools'] || []),
223
- },
224
- }
225
- } catch (error) {
226
- // Signal end for status line
227
- this.signalEnd()
228
-
229
- // Record failed attempt for loop detection
230
- const attemptInfo = loopDetector.recordAttempt(commandName, loopContext, {
231
- success: false,
232
- error: (error as Error).message,
233
- })
234
-
235
- // Check if we should escalate after this failure
236
- if (attemptInfo.shouldEscalate) {
237
- const escalation = loopDetector.getEscalationInfo(commandName, loopContext)
238
- return {
239
- success: false,
240
- error: escalation?.message,
241
- escalation,
242
- isLoopDetected: true,
243
- suggestion: escalation?.suggestion,
244
- }
245
- }
246
-
247
- return {
248
- success: false,
249
- error: (error as Error).message,
250
- attemptNumber: attemptInfo.attemptNumber,
251
- isLooping: attemptInfo.isLooping,
252
- }
253
- }
254
- }
255
-
256
- /**
257
- * Execute tool with permission check
258
- */
259
- async executeTool(toolName: string, args: unknown[], allowedTools: string[]): Promise<unknown> {
260
- // Check if tool is allowed
261
- if (!toolRegistry.isAllowed(toolName, allowedTools)) {
262
- throw new Error(`Tool ${toolName} not allowed for this command`)
263
- }
264
-
265
- // Get tool function
266
- const tool = toolRegistry.get(toolName)
267
- if (!tool) {
268
- throw new Error(`Tool ${toolName} not found`)
269
- }
270
-
271
- // Execute tool
272
- return await tool(...args)
273
- }
274
-
275
- /**
276
- * Simple execution for direct tool access (legacy migration helper)
277
- */
278
- async executeSimple(
279
- commandName: string,
280
- executionFn: ExecutionToolsFn,
281
- projectPath: string
282
- ): Promise<SimpleExecutionResult> {
283
- try {
284
- // Load template to get allowed tools
285
- const template = await templateLoader.load(commandName)
286
- const allowedTools = template.frontmatter['allowed-tools'] || []
287
-
288
- // Build context
289
- const context = await contextBuilder.build(projectPath)
290
-
291
- // Create tools proxy that checks permissions
292
- const tools = {
293
- read: async (filePath: string) => this.executeTool('Read', [filePath], allowedTools),
294
- write: async (filePath: string, content: string) => this.executeTool('Write', [filePath, content], allowedTools),
295
- bash: async (command: string) => this.executeTool('Bash', [command], allowedTools),
296
- }
297
-
298
- // Execute user function with tools
299
- const result = await executionFn(tools, context)
300
-
301
- return {
302
- success: true,
303
- result,
304
- }
305
- } catch (error) {
306
- return {
307
- success: false,
308
- error: (error as Error).message,
309
- }
310
- }
311
- }
312
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Command Executor
3
- * Orchestrates command execution with agentic delegation.
4
- *
5
- * @module agentic/command-executor
6
- * @version 3.4
7
- */
8
-
9
- export type { ExecutionResult, SimpleExecutionResult, ExecutionToolsFn } from './types'
10
- export { signalStart, signalEnd } from './status-signal'
11
- export { CommandExecutor } from './command-executor'
12
-
13
- import { CommandExecutor } from './command-executor'
14
-
15
- const commandExecutor = new CommandExecutor()
16
- export default commandExecutor
@@ -1,38 +0,0 @@
1
- /**
2
- * Status Signal
3
- * Running file for status line integration
4
- */
5
-
6
- import fs from 'fs'
7
- import path from 'path'
8
- import os from 'os'
9
-
10
- const RUNNING_FILE = path.join(os.homedir(), '.prjct-cli', '.running')
11
-
12
- /**
13
- * Signal that a command is running (for status line)
14
- */
15
- export function signalStart(commandName: string): void {
16
- try {
17
- const dir = path.dirname(RUNNING_FILE)
18
- if (!fs.existsSync(dir)) {
19
- fs.mkdirSync(dir, { recursive: true })
20
- }
21
- fs.writeFileSync(RUNNING_FILE, `/p:${commandName}`)
22
- } catch {
23
- // Silently ignore - status line is optional
24
- }
25
- }
26
-
27
- /**
28
- * Signal that command has finished (for status line)
29
- */
30
- export function signalEnd(): void {
31
- try {
32
- if (fs.existsSync(RUNNING_FILE)) {
33
- fs.unlinkSync(RUNNING_FILE)
34
- }
35
- } catch {
36
- // Silently ignore - status line is optional
37
- }
38
- }