prjct-cli 0.45.0 → 0.45.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -0
- package/bin/prjct.ts +117 -10
- package/core/__tests__/agentic/memory-system.test.ts +39 -26
- package/core/__tests__/agentic/plan-mode.test.ts +64 -46
- package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
- package/core/__tests__/services/project-index.test.ts +353 -0
- package/core/__tests__/types/fs.test.ts +3 -3
- package/core/__tests__/utils/date-helper.test.ts +10 -10
- package/core/__tests__/utils/output.test.ts +9 -6
- package/core/__tests__/utils/project-commands.test.ts +5 -6
- package/core/agentic/agent-router.ts +9 -10
- package/core/agentic/chain-of-thought.ts +16 -4
- package/core/agentic/command-executor.ts +66 -40
- package/core/agentic/context-builder.ts +8 -5
- package/core/agentic/ground-truth.ts +15 -9
- package/core/agentic/index.ts +145 -152
- package/core/agentic/loop-detector.ts +40 -11
- package/core/agentic/memory-system.ts +98 -35
- package/core/agentic/orchestrator-executor.ts +135 -71
- package/core/agentic/plan-mode.ts +46 -16
- package/core/agentic/prompt-builder.ts +108 -42
- package/core/agentic/services.ts +10 -9
- package/core/agentic/skill-loader.ts +9 -15
- package/core/agentic/smart-context.ts +129 -79
- package/core/agentic/template-executor.ts +13 -12
- package/core/agentic/template-loader.ts +7 -4
- package/core/agentic/tool-registry.ts +16 -13
- package/core/agents/index.ts +1 -1
- package/core/agents/performance.ts +10 -27
- package/core/ai-tools/formatters.ts +8 -6
- package/core/ai-tools/generator.ts +4 -4
- package/core/ai-tools/index.ts +1 -1
- package/core/ai-tools/registry.ts +21 -11
- package/core/bus/bus.ts +23 -16
- package/core/bus/index.ts +2 -2
- package/core/cli/linear.ts +3 -5
- package/core/cli/start.ts +28 -25
- package/core/commands/analysis.ts +58 -39
- package/core/commands/analytics.ts +52 -44
- package/core/commands/base.ts +15 -13
- package/core/commands/cleanup.ts +6 -13
- package/core/commands/command-data.ts +28 -4
- package/core/commands/commands.ts +57 -24
- package/core/commands/context.ts +4 -4
- package/core/commands/design.ts +3 -10
- package/core/commands/index.ts +5 -8
- package/core/commands/maintenance.ts +7 -4
- package/core/commands/planning.ts +179 -56
- package/core/commands/register.ts +13 -9
- package/core/commands/registry.ts +15 -14
- package/core/commands/setup.ts +26 -14
- package/core/commands/shipping.ts +11 -16
- package/core/commands/snapshots.ts +16 -32
- package/core/commands/uninstall.ts +541 -0
- package/core/commands/workflow.ts +24 -28
- package/core/constants/index.ts +10 -22
- package/core/context/generator.ts +82 -33
- package/core/context-tools/files-tool.ts +18 -19
- package/core/context-tools/imports-tool.ts +13 -33
- package/core/context-tools/index.ts +29 -54
- package/core/context-tools/recent-tool.ts +16 -22
- package/core/context-tools/signatures-tool.ts +17 -26
- package/core/context-tools/summary-tool.ts +20 -22
- package/core/context-tools/token-counter.ts +25 -20
- package/core/context-tools/types.ts +5 -5
- package/core/domain/agent-generator.ts +7 -5
- package/core/domain/agent-loader.ts +2 -2
- package/core/domain/analyzer.ts +19 -16
- package/core/domain/architecture-generator.ts +6 -3
- package/core/domain/context-estimator.ts +3 -4
- package/core/domain/snapshot-manager.ts +25 -22
- package/core/domain/task-stack.ts +24 -14
- package/core/errors.ts +1 -1
- package/core/events/events.ts +2 -4
- package/core/events/index.ts +1 -2
- package/core/index.ts +28 -16
- package/core/infrastructure/agent-detector.ts +3 -3
- package/core/infrastructure/ai-provider.ts +23 -20
- package/core/infrastructure/author-detector.ts +16 -10
- package/core/infrastructure/capability-installer.ts +2 -2
- package/core/infrastructure/claude-agent.ts +6 -6
- package/core/infrastructure/command-installer.ts +22 -17
- package/core/infrastructure/config-manager.ts +18 -14
- package/core/infrastructure/editors-config.ts +8 -4
- package/core/infrastructure/path-manager.ts +8 -6
- package/core/infrastructure/permission-manager.ts +20 -17
- package/core/infrastructure/setup.ts +42 -38
- package/core/infrastructure/update-checker.ts +5 -5
- package/core/integrations/issue-tracker/enricher.ts +8 -19
- package/core/integrations/issue-tracker/index.ts +2 -2
- package/core/integrations/issue-tracker/manager.ts +15 -15
- package/core/integrations/issue-tracker/types.ts +5 -22
- package/core/integrations/jira/client.ts +67 -59
- package/core/integrations/jira/index.ts +11 -14
- package/core/integrations/jira/mcp-adapter.ts +5 -10
- package/core/integrations/jira/service.ts +10 -10
- package/core/integrations/linear/client.ts +27 -18
- package/core/integrations/linear/index.ts +9 -12
- package/core/integrations/linear/service.ts +11 -11
- package/core/integrations/linear/sync.ts +8 -8
- package/core/outcomes/analyzer.ts +5 -18
- package/core/outcomes/index.ts +2 -2
- package/core/outcomes/recorder.ts +3 -3
- package/core/plugin/builtin/webhook.ts +19 -15
- package/core/plugin/hooks.ts +29 -21
- package/core/plugin/index.ts +7 -7
- package/core/plugin/loader.ts +19 -19
- package/core/plugin/registry.ts +12 -23
- package/core/schemas/agents.ts +1 -1
- package/core/schemas/analysis.ts +1 -1
- package/core/schemas/enriched-task.ts +62 -49
- package/core/schemas/ideas.ts +13 -13
- package/core/schemas/index.ts +17 -27
- package/core/schemas/issues.ts +40 -25
- package/core/schemas/metrics.ts +25 -25
- package/core/schemas/outcomes.ts +70 -62
- package/core/schemas/permissions.ts +15 -12
- package/core/schemas/prd.ts +27 -14
- package/core/schemas/project.ts +3 -3
- package/core/schemas/roadmap.ts +47 -34
- package/core/schemas/schemas.ts +3 -4
- package/core/schemas/shipped.ts +3 -3
- package/core/schemas/state.ts +43 -29
- package/core/server/index.ts +5 -6
- package/core/server/routes-extended.ts +68 -72
- package/core/server/routes.ts +3 -3
- package/core/server/server.ts +31 -26
- package/core/services/agent-generator.ts +237 -0
- package/core/services/agent-service.ts +2 -2
- package/core/services/breakdown-service.ts +2 -4
- package/core/services/context-generator.ts +299 -0
- package/core/services/context-selector.ts +420 -0
- package/core/services/doctor-service.ts +426 -0
- package/core/services/file-categorizer.ts +448 -0
- package/core/services/file-scorer.ts +270 -0
- package/core/services/git-analyzer.ts +267 -0
- package/core/services/index.ts +27 -10
- package/core/services/memory-service.ts +3 -4
- package/core/services/project-index.ts +911 -0
- package/core/services/project-service.ts +4 -4
- package/core/services/skill-installer.ts +14 -17
- package/core/services/skill-lock.ts +3 -3
- package/core/services/skill-service.ts +12 -6
- package/core/services/stack-detector.ts +245 -0
- package/core/services/sync-service.ts +87 -345
- package/core/services/watch-service.ts +294 -0
- package/core/session/compaction.ts +23 -31
- package/core/session/index.ts +11 -5
- package/core/session/log-migration.ts +3 -3
- package/core/session/metrics.ts +19 -14
- package/core/session/session-log-manager.ts +12 -17
- package/core/session/task-session-manager.ts +25 -25
- package/core/session/utils.ts +1 -1
- package/core/storage/ideas-storage.ts +41 -57
- package/core/storage/index-storage.ts +514 -0
- package/core/storage/index.ts +41 -17
- package/core/storage/metrics-storage.ts +39 -34
- package/core/storage/queue-storage.ts +35 -45
- package/core/storage/shipped-storage.ts +17 -20
- package/core/storage/state-storage.ts +50 -30
- package/core/storage/storage-manager.ts +6 -6
- package/core/storage/storage.ts +18 -15
- package/core/sync/auth-config.ts +3 -3
- package/core/sync/index.ts +13 -19
- package/core/sync/oauth-handler.ts +3 -3
- package/core/sync/sync-client.ts +4 -9
- package/core/sync/sync-manager.ts +12 -14
- package/core/types/commands.ts +42 -7
- package/core/types/index.ts +284 -305
- package/core/types/integrations.ts +3 -3
- package/core/types/storage.ts +14 -14
- package/core/types/utils.ts +3 -3
- package/core/utils/agent-stream.ts +3 -1
- package/core/utils/animations.ts +14 -11
- package/core/utils/branding.ts +7 -7
- package/core/utils/cache.ts +1 -3
- package/core/utils/collection-filters.ts +3 -15
- package/core/utils/date-helper.ts +2 -7
- package/core/utils/file-helper.ts +13 -8
- package/core/utils/jsonl-helper.ts +13 -10
- package/core/utils/keychain.ts +4 -8
- package/core/utils/logger.ts +1 -1
- package/core/utils/next-steps.ts +3 -3
- package/core/utils/output.ts +58 -11
- package/core/utils/project-commands.ts +6 -6
- package/core/utils/project-credentials.ts +5 -12
- package/core/utils/runtime.ts +2 -2
- package/core/utils/session-helper.ts +3 -4
- package/core/utils/version.ts +3 -3
- package/core/wizard/index.ts +13 -0
- package/core/wizard/onboarding.ts +633 -0
- package/core/workflow/state-machine.ts +7 -7
- package/dist/bin/prjct.mjs +18755 -15574
- package/dist/core/infrastructure/command-installer.js +86 -79
- package/dist/core/infrastructure/editors-config.js +6 -6
- package/dist/core/infrastructure/setup.js +246 -225
- package/dist/core/utils/version.js +9 -9
- package/package.json +11 -12
- package/scripts/build.js +3 -3
- package/scripts/postinstall.js +2 -2
- package/templates/mcp-config.json +6 -1
- package/templates/permissions/permissive.jsonc +1 -1
- package/templates/permissions/strict.jsonc +5 -9
- package/templates/global/docs/agents.md +0 -88
- package/templates/global/docs/architecture.md +0 -103
- package/templates/global/docs/commands.md +0 -96
- package/templates/global/docs/validation.md +0 -95
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.45.3] - 2026-01-29
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- remove --provenance (requires public repo) - PRJ-147
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.45.2] - 2026-01-29
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- use Production environment for npm secrets - PRJ-147
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [0.45.1] - 2026-01-29
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
- use semver-sorted tags for version detection - PRJ-147
|
|
22
|
+
- npm auth configuration for CI publish - PRJ-147
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## [0.42.1] - 2026-01-29
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
- npm auth configuration for CI publish - PRJ-147
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## [0.42.0] - 2026-01-29
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
- automated release pipeline - PRJ-147 (#68)
|
|
37
|
+
- add project indexing and analysis services (PRJ-85, PRJ-87) (#66)
|
|
38
|
+
- metrics display in output (PRJ-68, PRJ-69) (#54)
|
|
39
|
+
- add prjct uninstall command (PRJ-146) (#65)
|
|
40
|
+
- add prjct doctor command (PRJ-117) (#62)
|
|
41
|
+
- smart watch mode - auto-sync on file changes (PRJ-123) (#61)
|
|
42
|
+
- add --quiet flag for silent output (PRJ-97) (#60)
|
|
43
|
+
- interactive onboarding wizard (PRJ-124) (#58)
|
|
44
|
+
- smart context filtering tools for AI agents (PRJ-127) (#57)
|
|
45
|
+
- workflow state machine + bidirectional Linear sync (#55)
|
|
46
|
+
- progress indicators for long-running operations (PRJ-129) (#52)
|
|
47
|
+
- agent activity stream for real-time visibility (PRJ-135) (#51)
|
|
48
|
+
- show explicit next steps after each command (PRJ-136) (#50)
|
|
49
|
+
- multi-agent output Phase 3 - Auto-detect + Continue.dev (PRJ-126) (#49)
|
|
50
|
+
- multi-agent output Phase 2 - Copilot + Windsurf (PRJ-126) (#48)
|
|
51
|
+
- multi-agent context output - Phase 1 (PRJ-126) (#47)
|
|
52
|
+
- bidirectional sync Linear ↔ prjct (PRJ-142) (#46)
|
|
53
|
+
|
|
54
|
+
### Bug Fixes
|
|
55
|
+
|
|
56
|
+
- add Bun setup for test runner in CI - PRJ-147
|
|
57
|
+
- use npm instead of bun for CI tests - PRJ-147
|
|
58
|
+
- remove IDE files from repo - PRJ-144, PRJ-145
|
|
59
|
+
- add --help handler in CLI entry point for CI compatibility
|
|
60
|
+
- update tests for CI compatibility
|
|
61
|
+
- CI workflow - remove unsupported bun reporter flag and fix verification
|
|
62
|
+
- enforce workflow steps in templates (PRJ-143) (#56)
|
|
63
|
+
- add $PRJCT_CLI prefix to relative paths in templates (PRJ-143)
|
|
64
|
+
- use stderr for Linear connection log to not break JSON output
|
|
65
|
+
|
|
66
|
+
### Performance
|
|
67
|
+
|
|
68
|
+
- parallelize sync operations for 30-50% speedup (PRJ-116) (#59)
|
|
69
|
+
|
|
70
|
+
### Refactoring
|
|
71
|
+
|
|
72
|
+
- migrate from ESLint + Prettier to Biome
|
|
73
|
+
- consolidate and optimize CI workflows
|
|
74
|
+
- extract StackDetector from sync-service (PRJ-86) (#64)
|
|
75
|
+
- extract ContextFileGenerator from sync-service (PRJ-88) (#63)
|
|
76
|
+
|
|
77
|
+
|
|
3
78
|
## [0.45.0] - 2026-01-29
|
|
4
79
|
|
|
5
80
|
### Feature: Smart Context Filtering Tools (PRJ-127)
|
package/bin/prjct.ts
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
* auto-install on first CLI use. This is the reliable path.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import fs from 'fs'
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import { VERSION } from '../core/utils/version'
|
|
15
|
-
import editorsConfig from '../core/infrastructure/editors-config'
|
|
16
|
-
import { startServer, DEFAULT_PORT } from '../core/server/server'
|
|
17
|
-
import configManager from '../core/infrastructure/config-manager'
|
|
11
|
+
import fs from 'node:fs'
|
|
12
|
+
import os from 'node:os'
|
|
13
|
+
import path from 'node:path'
|
|
18
14
|
import { detectAllProviders } from '../core/infrastructure/ai-provider'
|
|
15
|
+
import configManager from '../core/infrastructure/config-manager'
|
|
16
|
+
import editorsConfig from '../core/infrastructure/editors-config'
|
|
17
|
+
import { DEFAULT_PORT, startServer } from '../core/server/server'
|
|
18
|
+
import { VERSION } from '../core/utils/version'
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Check if routers are installed for detected providers
|
|
@@ -52,6 +52,15 @@ function checkRoutersInstalled(): boolean {
|
|
|
52
52
|
// Check for special subcommands that bypass normal CLI
|
|
53
53
|
const args = process.argv.slice(2)
|
|
54
54
|
|
|
55
|
+
// Parse --quiet / -q flag (must be done early, before any output)
|
|
56
|
+
const quietIndex = args.findIndex((arg) => arg === '--quiet' || arg === '-q')
|
|
57
|
+
const isQuietMode = quietIndex !== -1
|
|
58
|
+
if (isQuietMode) {
|
|
59
|
+
args.splice(quietIndex, 1) // Remove flag from args
|
|
60
|
+
const { setQuietMode } = await import('../core/utils/output')
|
|
61
|
+
setQuietMode(true)
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
// Colors for output
|
|
56
65
|
const CYAN = '\x1b[36m'
|
|
57
66
|
const YELLOW = '\x1b[33m'
|
|
@@ -78,7 +87,7 @@ if (args[0] === 'start' || args[0] === 'setup') {
|
|
|
78
87
|
console.error('No prjct project found. Run "prjct init" first.')
|
|
79
88
|
process.exitCode = 1
|
|
80
89
|
} else {
|
|
81
|
-
const port = parseInt(args[1]) || DEFAULT_PORT
|
|
90
|
+
const port = parseInt(args[1], 10) || DEFAULT_PORT
|
|
82
91
|
await startServer(projectId, projectPath, port)
|
|
83
92
|
}
|
|
84
93
|
} catch (error) {
|
|
@@ -99,9 +108,57 @@ if (args[0] === 'start' || args[0] === 'setup') {
|
|
|
99
108
|
console.log(JSON.stringify(result, null, 2))
|
|
100
109
|
process.exitCode = result.tool === 'error' ? 1 : 0
|
|
101
110
|
}
|
|
111
|
+
} else if (args[0] === 'doctor') {
|
|
112
|
+
// Health check command
|
|
113
|
+
const { doctorService } = await import('../core/services/doctor-service')
|
|
114
|
+
const exitCode = await doctorService.run(process.cwd())
|
|
115
|
+
process.exitCode = exitCode
|
|
116
|
+
} else if (args[0] === 'uninstall') {
|
|
117
|
+
// Complete system removal
|
|
118
|
+
const { uninstall } = await import('../core/commands/uninstall')
|
|
119
|
+
|
|
120
|
+
// Parse flags
|
|
121
|
+
const force = args.includes('--force') || args.includes('-f')
|
|
122
|
+
const backup = args.includes('--backup') || args.includes('-b')
|
|
123
|
+
const dryRun = args.includes('--dry-run') || args.includes('-n')
|
|
124
|
+
const keepPackage = args.includes('--keep-package')
|
|
125
|
+
|
|
126
|
+
const result = await uninstall({ force, backup, dryRun, keepPackage })
|
|
127
|
+
process.exitCode = result.success ? 0 : 1
|
|
128
|
+
} else if (args[0] === 'watch') {
|
|
129
|
+
// Watch mode - auto-sync on file changes
|
|
130
|
+
const projectPath = process.cwd()
|
|
131
|
+
const projectId = await configManager.getProjectId(projectPath)
|
|
132
|
+
|
|
133
|
+
if (!projectId) {
|
|
134
|
+
console.error('No prjct project found. Run "prjct init" first.')
|
|
135
|
+
process.exitCode = 1
|
|
136
|
+
} else {
|
|
137
|
+
const { watchService } = await import('../core/services/watch-service')
|
|
138
|
+
|
|
139
|
+
// Parse options
|
|
140
|
+
const verbose = args.includes('--verbose') || args.includes('-v')
|
|
141
|
+
const debounceArg = args.find((a) => a.startsWith('--debounce='))
|
|
142
|
+
const debounceMs = debounceArg ? parseInt(debounceArg.split('=')[1], 10) : undefined
|
|
143
|
+
const intervalArg = args.find((a) => a.startsWith('--interval='))
|
|
144
|
+
const minIntervalMs = intervalArg ? parseInt(intervalArg.split('=')[1], 10) * 1000 : undefined
|
|
145
|
+
|
|
146
|
+
const result = await watchService.start(projectPath, {
|
|
147
|
+
verbose,
|
|
148
|
+
quiet: isQuietMode,
|
|
149
|
+
debounceMs,
|
|
150
|
+
minIntervalMs,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
if (!result.success) {
|
|
154
|
+
console.error(result.error)
|
|
155
|
+
process.exitCode = 1
|
|
156
|
+
}
|
|
157
|
+
// Watch mode runs indefinitely until Ctrl+C
|
|
158
|
+
}
|
|
102
159
|
} else if (args[0] === 'linear') {
|
|
103
160
|
// Linear CLI subcommand - direct access to Linear SDK
|
|
104
|
-
const { spawn } = await import('child_process')
|
|
161
|
+
const { spawn } = await import('node:child_process')
|
|
105
162
|
const projectPath = process.cwd()
|
|
106
163
|
const projectId = await configManager.getProjectId(projectPath)
|
|
107
164
|
|
|
@@ -125,6 +182,56 @@ if (args[0] === 'start' || args[0] === 'setup') {
|
|
|
125
182
|
process.exitCode = code || 0
|
|
126
183
|
})
|
|
127
184
|
}
|
|
185
|
+
} else if (args[0] === 'help' || args[0] === '-h' || args[0] === '--help') {
|
|
186
|
+
// Show help - bypass setup check to always show help
|
|
187
|
+
console.log(`
|
|
188
|
+
prjct - Context layer for AI coding agents
|
|
189
|
+
Works with Claude Code, Gemini CLI, Antigravity, Cursor IDE, and more.
|
|
190
|
+
|
|
191
|
+
QUICK START
|
|
192
|
+
-----------
|
|
193
|
+
Claude/Gemini:
|
|
194
|
+
1. prjct start Configure your AI provider
|
|
195
|
+
2. cd my-project && prjct init
|
|
196
|
+
3. Open in Claude Code or Gemini CLI
|
|
197
|
+
4. Type: p. sync Analyze project
|
|
198
|
+
|
|
199
|
+
Cursor IDE:
|
|
200
|
+
1. cd my-project && prjct init
|
|
201
|
+
2. Open in Cursor
|
|
202
|
+
3. Type: /sync Analyze project
|
|
203
|
+
|
|
204
|
+
COMMANDS (inside your AI agent)
|
|
205
|
+
-------------------------------
|
|
206
|
+
Claude/Gemini Cursor Description
|
|
207
|
+
─────────────────────────────────────────────────────
|
|
208
|
+
p. sync /sync Analyze project
|
|
209
|
+
p. task "desc" /task "desc" Start a task
|
|
210
|
+
p. done /done Complete subtask
|
|
211
|
+
p. ship "name" /ship "name" Ship with PR
|
|
212
|
+
|
|
213
|
+
TERMINAL COMMANDS (this CLI)
|
|
214
|
+
----------------------------
|
|
215
|
+
prjct start First-time setup (Claude/Gemini global config)
|
|
216
|
+
prjct init Initialize project (required for Cursor)
|
|
217
|
+
prjct setup Reconfigure installations
|
|
218
|
+
prjct sync Sync project state
|
|
219
|
+
prjct watch Auto-sync on file changes (Ctrl+C to stop)
|
|
220
|
+
prjct doctor Check system health and dependencies
|
|
221
|
+
prjct uninstall Complete system removal of prjct
|
|
222
|
+
|
|
223
|
+
FLAGS
|
|
224
|
+
-----
|
|
225
|
+
--quiet, -q Suppress all output (only errors to stderr)
|
|
226
|
+
--version, -v Show version
|
|
227
|
+
--help, -h Show this help
|
|
228
|
+
|
|
229
|
+
MORE INFO
|
|
230
|
+
---------
|
|
231
|
+
Documentation: https://prjct.app
|
|
232
|
+
GitHub: https://github.com/jlopezlira/prjct-cli
|
|
233
|
+
`)
|
|
234
|
+
process.exitCode = 0
|
|
128
235
|
} else if (args[0] === 'version' || args[0] === '-v' || args[0] === '--version') {
|
|
129
236
|
// Show version with provider status
|
|
130
237
|
const detection = detectAllProviders()
|
|
@@ -211,7 +318,7 @@ ${CYAN}${BOLD} Welcome to prjct!${RESET}
|
|
|
211
318
|
const { default: setup } = await import('../core/infrastructure/setup')
|
|
212
319
|
await setup.run()
|
|
213
320
|
}
|
|
214
|
-
} catch (
|
|
321
|
+
} catch (_error) {
|
|
215
322
|
// Silent fail on version check
|
|
216
323
|
}
|
|
217
324
|
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* P3.3: Semantic Memory Database
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'bun:test'
|
|
7
|
+
import fs from 'node:fs/promises'
|
|
8
|
+
import path from 'node:path'
|
|
7
9
|
import memorySystem from '../../agentic/memory-system'
|
|
8
10
|
import pathManager from '../../infrastructure/path-manager'
|
|
9
|
-
import fs from 'fs/promises'
|
|
10
|
-
import path from 'path'
|
|
11
11
|
|
|
12
12
|
let testCounter = 0
|
|
13
13
|
const getTestProjectId = () => `test-memory-${Date.now()}-${++testCounter}`
|
|
@@ -33,7 +33,7 @@ describe('MemorySystem P3.3', () => {
|
|
|
33
33
|
title: 'Test Memory',
|
|
34
34
|
content: 'This is test content',
|
|
35
35
|
tags: ['code_style', 'naming_convention'],
|
|
36
|
-
userTriggered: true
|
|
36
|
+
userTriggered: true,
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
@@ -52,19 +52,19 @@ describe('MemorySystem P3.3', () => {
|
|
|
52
52
|
const memoryId = await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
53
53
|
title: 'Original Title',
|
|
54
54
|
content: 'Original content',
|
|
55
|
-
tags: ['code_style']
|
|
55
|
+
tags: ['code_style'],
|
|
56
56
|
})
|
|
57
57
|
|
|
58
58
|
const updated = await memorySystem.updateMemory(TEST_PROJECT_ID, memoryId, {
|
|
59
59
|
title: 'Updated Title',
|
|
60
60
|
content: 'Updated content',
|
|
61
|
-
tags: ['naming_convention', 'architecture']
|
|
61
|
+
tags: ['naming_convention', 'architecture'],
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
expect(updated).toBe(true)
|
|
65
65
|
|
|
66
66
|
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
67
|
-
const memory = memories.find(m => m.id === memoryId)
|
|
67
|
+
const memory = memories.find((m) => m.id === memoryId)
|
|
68
68
|
|
|
69
69
|
expect(memory!.title).toBe('Updated Title')
|
|
70
70
|
expect(memory!.content).toBe('Updated content')
|
|
@@ -74,7 +74,7 @@ describe('MemorySystem P3.3', () => {
|
|
|
74
74
|
|
|
75
75
|
it('should return false for non-existent memory', async () => {
|
|
76
76
|
const result = await memorySystem.updateMemory(TEST_PROJECT_ID, 'non_existent_id', {
|
|
77
|
-
title: 'New Title'
|
|
77
|
+
title: 'New Title',
|
|
78
78
|
})
|
|
79
79
|
expect(result).toBe(false)
|
|
80
80
|
})
|
|
@@ -85,14 +85,14 @@ describe('MemorySystem P3.3', () => {
|
|
|
85
85
|
const memoryId = await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
86
86
|
title: 'To Delete',
|
|
87
87
|
content: 'Will be deleted',
|
|
88
|
-
tags: ['test']
|
|
88
|
+
tags: ['test'],
|
|
89
89
|
})
|
|
90
90
|
|
|
91
91
|
const deleted = await memorySystem.deleteMemory(TEST_PROJECT_ID, memoryId)
|
|
92
92
|
expect(deleted).toBe(true)
|
|
93
93
|
|
|
94
94
|
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
95
|
-
expect(memories.find(m => m.id === memoryId)).toBeUndefined()
|
|
95
|
+
expect(memories.find((m) => m.id === memoryId)).toBeUndefined()
|
|
96
96
|
})
|
|
97
97
|
})
|
|
98
98
|
|
|
@@ -101,27 +101,35 @@ describe('MemorySystem P3.3', () => {
|
|
|
101
101
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
102
102
|
title: 'Memory 1',
|
|
103
103
|
content: 'Content 1',
|
|
104
|
-
tags: ['code_style', 'naming_convention']
|
|
104
|
+
tags: ['code_style', 'naming_convention'],
|
|
105
105
|
})
|
|
106
106
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
107
107
|
title: 'Memory 2',
|
|
108
108
|
content: 'Content 2',
|
|
109
|
-
tags: ['architecture', 'naming_convention']
|
|
109
|
+
tags: ['architecture', 'naming_convention'],
|
|
110
110
|
})
|
|
111
111
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
112
112
|
title: 'Memory 3',
|
|
113
113
|
content: 'Content 3',
|
|
114
|
-
tags: ['commit_style']
|
|
114
|
+
tags: ['commit_style'],
|
|
115
115
|
})
|
|
116
116
|
})
|
|
117
117
|
|
|
118
118
|
it('should find memories with ANY tag (OR)', async () => {
|
|
119
|
-
const results = await memorySystem.findByTags(
|
|
119
|
+
const results = await memorySystem.findByTags(
|
|
120
|
+
TEST_PROJECT_ID,
|
|
121
|
+
['code_style', 'architecture'],
|
|
122
|
+
false
|
|
123
|
+
)
|
|
120
124
|
expect(results.length).toBe(2)
|
|
121
125
|
})
|
|
122
126
|
|
|
123
127
|
it('should find memories with ALL tags (AND)', async () => {
|
|
124
|
-
const results = await memorySystem.findByTags(
|
|
128
|
+
const results = await memorySystem.findByTags(
|
|
129
|
+
TEST_PROJECT_ID,
|
|
130
|
+
['naming_convention', 'architecture'],
|
|
131
|
+
true
|
|
132
|
+
)
|
|
125
133
|
expect(results.length).toBe(1)
|
|
126
134
|
expect(results[0].title).toBe('Memory 2')
|
|
127
135
|
})
|
|
@@ -132,12 +140,12 @@ describe('MemorySystem P3.3', () => {
|
|
|
132
140
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
133
141
|
title: 'React Hooks Pattern',
|
|
134
142
|
content: 'Use custom hooks for reusable logic',
|
|
135
|
-
tags: ['code_style']
|
|
143
|
+
tags: ['code_style'],
|
|
136
144
|
})
|
|
137
145
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
138
146
|
title: 'API Design',
|
|
139
147
|
content: 'REST endpoints follow /api/v1 pattern',
|
|
140
|
-
tags: ['architecture']
|
|
148
|
+
tags: ['architecture'],
|
|
141
149
|
})
|
|
142
150
|
})
|
|
143
151
|
|
|
@@ -165,17 +173,17 @@ describe('MemorySystem P3.3', () => {
|
|
|
165
173
|
title: 'Commit Style',
|
|
166
174
|
content: 'Use conventional commits',
|
|
167
175
|
tags: ['commit_style', 'ship_workflow'],
|
|
168
|
-
userTriggered: true
|
|
176
|
+
userTriggered: true,
|
|
169
177
|
})
|
|
170
178
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
171
179
|
title: 'Test Behavior',
|
|
172
180
|
content: 'Run tests before shipping',
|
|
173
|
-
tags: ['test_behavior', 'ship_workflow']
|
|
181
|
+
tags: ['test_behavior', 'ship_workflow'],
|
|
174
182
|
})
|
|
175
183
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
176
184
|
title: 'Code Style',
|
|
177
185
|
content: 'Use TypeScript strict mode',
|
|
178
|
-
tags: ['code_style']
|
|
186
|
+
tags: ['code_style'],
|
|
179
187
|
})
|
|
180
188
|
})
|
|
181
189
|
|
|
@@ -184,8 +192,8 @@ describe('MemorySystem P3.3', () => {
|
|
|
184
192
|
const results = await memorySystem.getRelevantMemories(TEST_PROJECT_ID, context, 5)
|
|
185
193
|
|
|
186
194
|
expect(results.length).toBeGreaterThan(0)
|
|
187
|
-
const hasRelevantTags = results.some(
|
|
188
|
-
m.tags.includes('commit_style') || m.tags.includes('ship_workflow')
|
|
195
|
+
const hasRelevantTags = results.some(
|
|
196
|
+
(m) => m.tags.includes('commit_style') || m.tags.includes('ship_workflow')
|
|
189
197
|
)
|
|
190
198
|
expect(hasRelevantTags).toBe(true)
|
|
191
199
|
})
|
|
@@ -194,7 +202,7 @@ describe('MemorySystem P3.3', () => {
|
|
|
194
202
|
const context = { commandName: 'ship', params: {} }
|
|
195
203
|
const results = await memorySystem.getRelevantMemories(TEST_PROJECT_ID, context, 5)
|
|
196
204
|
|
|
197
|
-
const userTriggeredIndex = results.findIndex(m => m.userTriggered)
|
|
205
|
+
const userTriggeredIndex = results.findIndex((m) => m.userTriggered)
|
|
198
206
|
expect(userTriggeredIndex).toBeLessThanOrEqual(1)
|
|
199
207
|
})
|
|
200
208
|
|
|
@@ -207,7 +215,12 @@ describe('MemorySystem P3.3', () => {
|
|
|
207
215
|
|
|
208
216
|
describe('autoRemember', () => {
|
|
209
217
|
it('should create memory from user decision', async () => {
|
|
210
|
-
await memorySystem.autoRemember(
|
|
218
|
+
await memorySystem.autoRemember(
|
|
219
|
+
TEST_PROJECT_ID,
|
|
220
|
+
'commit_footer',
|
|
221
|
+
'prjct',
|
|
222
|
+
'User chose prjct footer'
|
|
223
|
+
)
|
|
211
224
|
|
|
212
225
|
const memories = await memorySystem.getAllMemories(TEST_PROJECT_ID)
|
|
213
226
|
expect(memories.length).toBe(1)
|
|
@@ -232,12 +245,12 @@ describe('MemorySystem P3.3', () => {
|
|
|
232
245
|
title: 'Memory 1',
|
|
233
246
|
content: 'Content 1',
|
|
234
247
|
tags: ['code_style'],
|
|
235
|
-
userTriggered: true
|
|
248
|
+
userTriggered: true,
|
|
236
249
|
})
|
|
237
250
|
await memorySystem.createMemory(TEST_PROJECT_ID, {
|
|
238
251
|
title: 'Memory 2',
|
|
239
252
|
content: 'Content 2',
|
|
240
|
-
tags: ['code_style', 'architecture']
|
|
253
|
+
tags: ['code_style', 'architecture'],
|
|
241
254
|
})
|
|
242
255
|
|
|
243
256
|
const stats = await memorySystem.getMemoryStats(TEST_PROJECT_ID)
|
|
@@ -3,14 +3,9 @@
|
|
|
3
3
|
* P3.4: Plan Mode + Approval Flow
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import planMode, {
|
|
8
|
-
|
|
9
|
-
PLAN_REQUIRED_COMMANDS,
|
|
10
|
-
DESTRUCTIVE_COMMANDS,
|
|
11
|
-
PLANNING_TOOLS
|
|
12
|
-
} from '../../agentic/plan-mode'
|
|
13
|
-
import type { ProposedPlan, ApprovalContext, ChangedFile } from '../../types'
|
|
6
|
+
import { beforeEach, describe, expect, it } from 'bun:test'
|
|
7
|
+
import planMode, { PLAN_STATUS } from '../../agentic/plan-mode'
|
|
8
|
+
import type { ApprovalContext, ProposedPlan } from '../../types'
|
|
14
9
|
|
|
15
10
|
// Helper to create complete ProposedPlan objects
|
|
16
11
|
const createPlan = (overrides: Partial<ProposedPlan> = {}): ProposedPlan => ({
|
|
@@ -109,7 +104,9 @@ describe('PlanMode P3.4', () => {
|
|
|
109
104
|
|
|
110
105
|
describe('startPlanning', () => {
|
|
111
106
|
it('should create a new plan with correct initial state', () => {
|
|
112
|
-
const plan = planMode.startPlanning(TEST_PROJECT_ID, 'feature', {
|
|
107
|
+
const plan = planMode.startPlanning(TEST_PROJECT_ID, 'feature', {
|
|
108
|
+
description: 'Add dark mode',
|
|
109
|
+
})
|
|
113
110
|
|
|
114
111
|
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
115
112
|
expect(plan.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
@@ -161,7 +158,7 @@ describe('PlanMode P3.4', () => {
|
|
|
161
158
|
type: 'file_content',
|
|
162
159
|
source: 'src/index.js',
|
|
163
160
|
data: 'content',
|
|
164
|
-
gatheredAt: new Date().toISOString()
|
|
161
|
+
gatheredAt: new Date().toISOString(),
|
|
165
162
|
})
|
|
166
163
|
|
|
167
164
|
const plan = planMode.getActivePlan(TEST_PROJECT_ID)
|
|
@@ -173,11 +170,14 @@ describe('PlanMode P3.4', () => {
|
|
|
173
170
|
describe('proposePlan', () => {
|
|
174
171
|
it('should set status to pending approval', () => {
|
|
175
172
|
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
176
|
-
planMode.proposePlan(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
173
|
+
planMode.proposePlan(
|
|
174
|
+
TEST_PROJECT_ID,
|
|
175
|
+
createPlan({
|
|
176
|
+
summary: 'Add dark mode feature',
|
|
177
|
+
approach: 'CSS variables with theme context',
|
|
178
|
+
steps: [{ description: 'Create theme context' }, { description: 'Add toggle' }],
|
|
179
|
+
})
|
|
180
|
+
)
|
|
181
181
|
|
|
182
182
|
const plan = planMode.getActivePlan(TEST_PROJECT_ID)
|
|
183
183
|
expect(plan!.status).toBe(PLAN_STATUS.PENDING_APPROVAL)
|
|
@@ -185,11 +185,14 @@ describe('PlanMode P3.4', () => {
|
|
|
185
185
|
|
|
186
186
|
it('should return formatted plan for display', () => {
|
|
187
187
|
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
188
|
-
const formatted = planMode.proposePlan(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
const formatted = planMode.proposePlan(
|
|
189
|
+
TEST_PROJECT_ID,
|
|
190
|
+
createPlan({
|
|
191
|
+
summary: 'Test plan',
|
|
192
|
+
approach: 'Test approach',
|
|
193
|
+
steps: [{ description: 'Step 1' }],
|
|
194
|
+
})
|
|
195
|
+
)
|
|
193
196
|
|
|
194
197
|
expect(formatted!.summary).toBe('Test plan')
|
|
195
198
|
expect(formatted!.approach).toBe('Test approach')
|
|
@@ -210,9 +213,12 @@ describe('PlanMode P3.4', () => {
|
|
|
210
213
|
|
|
211
214
|
it('should convert proposed steps to executable steps', () => {
|
|
212
215
|
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
213
|
-
planMode.proposePlan(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
+
planMode.proposePlan(
|
|
217
|
+
TEST_PROJECT_ID,
|
|
218
|
+
createPlan({
|
|
219
|
+
steps: [{ description: 'Step 1' }, { description: 'Step 2' }],
|
|
220
|
+
})
|
|
221
|
+
)
|
|
216
222
|
const result = planMode.approvePlan(TEST_PROJECT_ID)
|
|
217
223
|
|
|
218
224
|
expect(result!.steps.length).toBe(2)
|
|
@@ -249,12 +255,15 @@ describe('PlanMode P3.4', () => {
|
|
|
249
255
|
describe('execution flow', () => {
|
|
250
256
|
beforeEach(() => {
|
|
251
257
|
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
252
|
-
planMode.proposePlan(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
+
planMode.proposePlan(
|
|
259
|
+
TEST_PROJECT_ID,
|
|
260
|
+
createPlan({
|
|
261
|
+
steps: [
|
|
262
|
+
{ description: 'Step 1', tool: 'Write' },
|
|
263
|
+
{ description: 'Step 2', tool: 'Bash' },
|
|
264
|
+
],
|
|
265
|
+
})
|
|
266
|
+
)
|
|
258
267
|
planMode.approvePlan(TEST_PROJECT_ID)
|
|
259
268
|
})
|
|
260
269
|
|
|
@@ -301,15 +310,18 @@ describe('PlanMode P3.4', () => {
|
|
|
301
310
|
|
|
302
311
|
describe('generateApprovalPrompt', () => {
|
|
303
312
|
it('should generate ship approval prompt', () => {
|
|
304
|
-
const prompt = planMode.generateApprovalPrompt(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
+
const prompt = planMode.generateApprovalPrompt(
|
|
314
|
+
'ship',
|
|
315
|
+
createApprovalContext({
|
|
316
|
+
branch: 'feature/dark-mode',
|
|
317
|
+
changedFiles: [
|
|
318
|
+
{ path: 'a.js', action: 'modify' },
|
|
319
|
+
{ path: 'b.js', action: 'modify' },
|
|
320
|
+
],
|
|
321
|
+
commitMessage: 'Add dark mode',
|
|
322
|
+
operation: 'git_push',
|
|
323
|
+
})
|
|
324
|
+
)
|
|
313
325
|
|
|
314
326
|
expect(prompt.title).toBe('Ship Confirmation')
|
|
315
327
|
expect(prompt.details).toContain('Branch: feature/dark-mode')
|
|
@@ -317,11 +329,14 @@ describe('PlanMode P3.4', () => {
|
|
|
317
329
|
})
|
|
318
330
|
|
|
319
331
|
it('should generate cleanup approval prompt', () => {
|
|
320
|
-
const prompt = planMode.generateApprovalPrompt(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
332
|
+
const prompt = planMode.generateApprovalPrompt(
|
|
333
|
+
'cleanup',
|
|
334
|
+
createApprovalContext({
|
|
335
|
+
filesToDelete: ['temp.js'],
|
|
336
|
+
linesOfCode: 50,
|
|
337
|
+
operation: 'delete_files',
|
|
338
|
+
})
|
|
339
|
+
)
|
|
325
340
|
|
|
326
341
|
expect(prompt.title).toBe('Cleanup Confirmation')
|
|
327
342
|
expect(prompt.message).toContain('delete')
|
|
@@ -347,9 +362,12 @@ describe('PlanMode P3.4', () => {
|
|
|
347
362
|
|
|
348
363
|
it('should show progress during execution', () => {
|
|
349
364
|
planMode.startPlanning(TEST_PROJECT_ID, 'feature', {})
|
|
350
|
-
planMode.proposePlan(
|
|
351
|
-
|
|
352
|
-
|
|
365
|
+
planMode.proposePlan(
|
|
366
|
+
TEST_PROJECT_ID,
|
|
367
|
+
createPlan({
|
|
368
|
+
steps: [{ description: 'Step 1' }, { description: 'Step 2' }],
|
|
369
|
+
})
|
|
370
|
+
)
|
|
353
371
|
planMode.approvePlan(TEST_PROJECT_ID)
|
|
354
372
|
planMode.startExecution(TEST_PROJECT_ID)
|
|
355
373
|
|