prjct-cli 0.4.8 ā 0.5.0
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 +337 -0
- package/CLAUDE.md +109 -3
- package/README.md +228 -93
- package/core/agent-detector.js +55 -122
- package/core/agent-generator.js +516 -0
- package/core/command-installer.js +109 -806
- package/core/commands.js +5 -34
- package/core/editors-config.js +9 -28
- package/core/git-integration.js +401 -0
- package/package.json +10 -7
- package/scripts/install.sh +0 -1
- package/templates/agents/be.template.md +42 -0
- package/templates/agents/data.template.md +41 -0
- package/templates/agents/devops.template.md +41 -0
- package/templates/agents/fe.template.md +42 -0
- package/templates/agents/mobile.template.md +41 -0
- package/templates/agents/pm.template.md +84 -0
- package/templates/agents/qa.template.md +54 -0
- package/templates/agents/scribe.template.md +95 -0
- package/templates/agents/security.template.md +41 -0
- package/templates/agents/ux.template.md +49 -0
- package/templates/commands/analyze.md +137 -3
- package/templates/commands/done.md +154 -5
- package/templates/commands/init.md +61 -3
- package/templates/commands/ship.md +146 -6
- package/templates/commands/sync.md +220 -0
- package/templates/examples/natural-language-examples.md +234 -22
- package/core/agents/codex-agent.js +0 -256
- package/core/agents/terminal-agent.js +0 -465
- package/templates/workflows/analyze.md +0 -159
- package/templates/workflows/cleanup.md +0 -73
- package/templates/workflows/context.md +0 -72
- package/templates/workflows/design.md +0 -88
- package/templates/workflows/done.md +0 -20
- package/templates/workflows/fix.md +0 -201
- package/templates/workflows/git.md +0 -192
- package/templates/workflows/help.md +0 -13
- package/templates/workflows/idea.md +0 -22
- package/templates/workflows/init.md +0 -80
- package/templates/workflows/natural-language-handler.md +0 -183
- package/templates/workflows/next.md +0 -44
- package/templates/workflows/now.md +0 -19
- package/templates/workflows/progress.md +0 -113
- package/templates/workflows/recap.md +0 -66
- package/templates/workflows/roadmap.md +0 -95
- package/templates/workflows/ship.md +0 -18
- package/templates/workflows/stuck.md +0 -25
- package/templates/workflows/task.md +0 -109
- package/templates/workflows/test.md +0 -243
package/core/commands.js
CHANGED
|
@@ -389,23 +389,9 @@ class PrjctCommands {
|
|
|
389
389
|
const hasExistingCode = await this.detectExistingCode(projectPath)
|
|
390
390
|
|
|
391
391
|
if (hasExistingCode) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
sync: true,
|
|
396
|
-
silent: true,
|
|
397
|
-
}, projectPath)
|
|
398
|
-
|
|
399
|
-
if (analysisResult.success && analysisResult.syncResults) {
|
|
400
|
-
const sync = analysisResult.syncResults
|
|
401
|
-
analysisMessage = '\n\nš Analysis Complete:\n' +
|
|
402
|
-
`ā
Found ${analysisResult.analysis.commands.length} commands, ${analysisResult.analysis.features.length} features\n` +
|
|
403
|
-
(sync.tasksMarkedComplete > 0 ? `ā
Synced ${sync.tasksMarkedComplete} completed tasks\n` : '') +
|
|
404
|
-
(sync.featuresAdded > 0 ? `ā
Added ${sync.featuresAdded} features to shipped.md\n` : '')
|
|
405
|
-
}
|
|
406
|
-
} catch (error) {
|
|
407
|
-
console.error('[prjct] Analysis warning:', error.message)
|
|
408
|
-
}
|
|
392
|
+
// Instead of silently analyzing, prompt the AI agent to run /p:analyze workflow
|
|
393
|
+
analysisMessage = '\n\nš Existing codebase detected!\n' +
|
|
394
|
+
`\nš” Run ${this.agentInfo.config.commandPrefix}analyze to analyze your project and sync tasks`
|
|
409
395
|
}
|
|
410
396
|
|
|
411
397
|
const displayPath = pathManager.getDisplayPath(globalPath)
|
|
@@ -2220,25 +2206,10 @@ ${diagram}
|
|
|
2220
2206
|
try {
|
|
2221
2207
|
await this.initializeAgent()
|
|
2222
2208
|
|
|
2223
|
-
// Check if already configured
|
|
2224
|
-
const editorsConfig = require('./editors-config')
|
|
2225
|
-
const configExists = await editorsConfig.configExists()
|
|
2226
|
-
|
|
2227
|
-
if (configExists) {
|
|
2228
|
-
return {
|
|
2229
|
-
success: false,
|
|
2230
|
-
message: this.agent.formatResponse(
|
|
2231
|
-
'prjct is already set up!\n\nTo reconfigure editors: prjct setup',
|
|
2232
|
-
'warning'
|
|
2233
|
-
),
|
|
2234
|
-
}
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
2209
|
// ASCII Art
|
|
2238
2210
|
const chalk = require('chalk')
|
|
2239
2211
|
console.log('')
|
|
2240
2212
|
console.log('')
|
|
2241
|
-
console.log(chalk.bold.magenta(' (ļ¾āć®ā)ļ¾*:dļ¾ā§'))
|
|
2242
2213
|
console.log(chalk.bold.cyan(' āāāāāāā āāāāāāā āāā āāāāāāāāāāāāāāāā'))
|
|
2243
2214
|
console.log(chalk.bold.cyan(' āāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā'))
|
|
2244
2215
|
console.log(chalk.bold.blue(' āāāāāāāāāāāāāāāā āāāāāā āāā'))
|
|
@@ -2277,8 +2248,8 @@ ${diagram}
|
|
|
2277
2248
|
})
|
|
2278
2249
|
console.log('')
|
|
2279
2250
|
|
|
2280
|
-
// Interactive selection
|
|
2281
|
-
const installResult = await commandInstaller.interactiveInstall(
|
|
2251
|
+
// Interactive selection (allow uninstall = true)
|
|
2252
|
+
const installResult = await commandInstaller.interactiveInstall(true)
|
|
2282
2253
|
|
|
2283
2254
|
if (!installResult.success) {
|
|
2284
2255
|
return {
|
package/core/editors-config.js
CHANGED
|
@@ -3,14 +3,14 @@ const path = require('path')
|
|
|
3
3
|
const os = require('os')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* EditorsConfig - Manages
|
|
6
|
+
* EditorsConfig - Manages Claude installation tracking
|
|
7
7
|
*
|
|
8
|
-
* Tracks
|
|
8
|
+
* Tracks prjct commands installation in Claude (Code + Desktop),
|
|
9
9
|
* enabling automatic updates when npm package is updated.
|
|
10
10
|
*
|
|
11
11
|
* Config location: ~/.prjct-cli/config/installed-editors.json
|
|
12
12
|
*
|
|
13
|
-
* @version 0.
|
|
13
|
+
* @version 0.5.0
|
|
14
14
|
*/
|
|
15
15
|
class EditorsConfig {
|
|
16
16
|
constructor() {
|
|
@@ -31,7 +31,7 @@ class EditorsConfig {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* Load
|
|
34
|
+
* Load installation configuration
|
|
35
35
|
* @returns {Promise<Object|null>} Configuration object or null if not found
|
|
36
36
|
*/
|
|
37
37
|
async loadConfig() {
|
|
@@ -48,21 +48,20 @@ class EditorsConfig {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* Save
|
|
52
|
-
* @param {string[]} editors - Array of editor keys (e.g., ['claude', 'cursor'])
|
|
53
|
-
* @param {Object} paths - Object mapping editor keys to installation paths
|
|
51
|
+
* Save installation configuration
|
|
54
52
|
* @param {string} version - Current prjct-cli version
|
|
53
|
+
* @param {string} claudePath - Path to Claude commands directory
|
|
55
54
|
* @returns {Promise<boolean>} Success status
|
|
56
55
|
*/
|
|
57
|
-
async saveConfig(
|
|
56
|
+
async saveConfig(version, claudePath) {
|
|
58
57
|
try {
|
|
59
58
|
await this.ensureConfigDir()
|
|
60
59
|
|
|
61
60
|
const config = {
|
|
62
61
|
version,
|
|
63
|
-
|
|
62
|
+
editor: 'claude',
|
|
64
63
|
lastInstall: new Date().toISOString(),
|
|
65
|
-
|
|
64
|
+
path: claudePath,
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
await fs.writeFile(
|
|
@@ -78,24 +77,6 @@ class EditorsConfig {
|
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
/**
|
|
82
|
-
* Get tracked editors from configuration
|
|
83
|
-
* @returns {Promise<string[]>} Array of editor keys
|
|
84
|
-
*/
|
|
85
|
-
async getTrackedEditors() {
|
|
86
|
-
const config = await this.loadConfig()
|
|
87
|
-
return config ? config.editors : []
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get editor paths from configuration
|
|
92
|
-
* @returns {Promise<Object>} Object mapping editor keys to paths
|
|
93
|
-
*/
|
|
94
|
-
async getEditorPaths() {
|
|
95
|
-
const config = await this.loadConfig()
|
|
96
|
-
return config ? config.paths : {}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
80
|
/**
|
|
100
81
|
* Get last installed version
|
|
101
82
|
* @returns {Promise<string|null>} Version string or null
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
const { execSync } = require('child_process')
|
|
2
|
+
const fs = require('fs').promises
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* GitIntegration - Git repository analysis and validation
|
|
6
|
+
*
|
|
7
|
+
* Provides git integration for prjct-cli to analyze repository state,
|
|
8
|
+
* validate user claims against actual commits, and track project progress.
|
|
9
|
+
*
|
|
10
|
+
* @version 0.5.0
|
|
11
|
+
*/
|
|
12
|
+
class GitIntegration {
|
|
13
|
+
constructor(projectPath = process.cwd()) {
|
|
14
|
+
this.projectPath = projectPath
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if current directory is a git repository
|
|
19
|
+
* @returns {Promise<boolean>} True if git repo exists
|
|
20
|
+
*/
|
|
21
|
+
async isGitRepo() {
|
|
22
|
+
try {
|
|
23
|
+
execSync('git rev-parse --git-dir', {
|
|
24
|
+
cwd: this.projectPath,
|
|
25
|
+
stdio: 'ignore',
|
|
26
|
+
})
|
|
27
|
+
return true
|
|
28
|
+
} catch {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get information about the last commit
|
|
35
|
+
* @returns {Promise<Object|null>} Commit info or null if no commits
|
|
36
|
+
*/
|
|
37
|
+
async getLastCommit() {
|
|
38
|
+
if (!(await this.isGitRepo())) {
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const output = execSync(
|
|
44
|
+
'git log -1 --format="%H|%s|%ar|%an"',
|
|
45
|
+
{
|
|
46
|
+
cwd: this.projectPath,
|
|
47
|
+
encoding: 'utf-8',
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const [hash, message, timeAgo, author] = output.trim().split('|')
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
hash: hash.substring(0, 7), // Short hash
|
|
55
|
+
fullHash: hash,
|
|
56
|
+
message,
|
|
57
|
+
timeAgo,
|
|
58
|
+
author,
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
return null // No commits yet
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get working directory status
|
|
67
|
+
* @returns {Promise<Object|null>} Status info or null if not git repo
|
|
68
|
+
*/
|
|
69
|
+
async getWorkingDirStatus() {
|
|
70
|
+
if (!(await this.isGitRepo())) {
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const status = execSync('git status --porcelain', {
|
|
76
|
+
cwd: this.projectPath,
|
|
77
|
+
encoding: 'utf-8',
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const lines = status.trim().split('\n').filter(Boolean)
|
|
81
|
+
|
|
82
|
+
const modified = lines.filter(
|
|
83
|
+
l => l.startsWith(' M') || l.startsWith('M'),
|
|
84
|
+
).length
|
|
85
|
+
const added = lines.filter(
|
|
86
|
+
l => l.startsWith('A') || l.startsWith('??'),
|
|
87
|
+
).length
|
|
88
|
+
const deleted = lines.filter(
|
|
89
|
+
l => l.startsWith(' D') || l.startsWith('D'),
|
|
90
|
+
).length
|
|
91
|
+
const renamed = lines.filter(l => l.startsWith('R')).length
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
modified,
|
|
95
|
+
added,
|
|
96
|
+
deleted,
|
|
97
|
+
renamed,
|
|
98
|
+
totalChanges: lines.length,
|
|
99
|
+
isClean: lines.length === 0,
|
|
100
|
+
files: lines.map(l => l.substring(3)), // Remove status prefix
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get diff summary between HEAD and working directory
|
|
109
|
+
* @returns {Promise<Object|null>} Diff summary or null
|
|
110
|
+
*/
|
|
111
|
+
async getDiffSummary() {
|
|
112
|
+
if (!(await this.isGitRepo())) {
|
|
113
|
+
return null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const diff = execSync('git diff HEAD --name-only', {
|
|
118
|
+
cwd: this.projectPath,
|
|
119
|
+
encoding: 'utf-8',
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const files = diff.trim().split('\n').filter(Boolean)
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
files,
|
|
126
|
+
count: files.length,
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
return null
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get files changed since a specific time
|
|
135
|
+
* @param {Date|number} since - Timestamp or Date object
|
|
136
|
+
* @returns {Promise<Array>} Array of changed files
|
|
137
|
+
*/
|
|
138
|
+
async getChangesSince(since) {
|
|
139
|
+
if (!(await this.isGitRepo())) {
|
|
140
|
+
return []
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const timestamp =
|
|
145
|
+
since instanceof Date ? since.toISOString() : new Date(since).toISOString()
|
|
146
|
+
|
|
147
|
+
const files = execSync(
|
|
148
|
+
`git log --since="${timestamp}" --name-only --pretty=format:`,
|
|
149
|
+
{
|
|
150
|
+
cwd: this.projectPath,
|
|
151
|
+
encoding: 'utf-8',
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return [...new Set(files.trim().split('\n').filter(Boolean))]
|
|
156
|
+
} catch {
|
|
157
|
+
return []
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Validate user claim against git state
|
|
163
|
+
* @param {string} claim - User's claim (e.g., "login is complete")
|
|
164
|
+
* @returns {Promise<Object>} Validation result
|
|
165
|
+
*/
|
|
166
|
+
async validateUserClaim(claim) {
|
|
167
|
+
if (!(await this.isGitRepo())) {
|
|
168
|
+
return {
|
|
169
|
+
valid: true,
|
|
170
|
+
warning: null,
|
|
171
|
+
note: 'Not a git repository - cannot validate against commits',
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const lastCommit = await this.getLastCommit()
|
|
176
|
+
const workingStatus = await this.getWorkingDirStatus()
|
|
177
|
+
|
|
178
|
+
if (!lastCommit) {
|
|
179
|
+
return {
|
|
180
|
+
valid: true,
|
|
181
|
+
warning: null,
|
|
182
|
+
note: 'No commits yet - cannot validate',
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Extract keywords from claim
|
|
187
|
+
const keywords = this.extractKeywords(claim)
|
|
188
|
+
const completionClaimed = /complete|done|finished|ready|shipped/i.test(claim)
|
|
189
|
+
|
|
190
|
+
// Check if keywords appear in last commit
|
|
191
|
+
const inLastCommit = keywords.some(keyword =>
|
|
192
|
+
lastCommit.message.toLowerCase().includes(keyword),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
// Check if there are uncommitted changes
|
|
196
|
+
const hasUncommittedChanges = !workingStatus.isClean
|
|
197
|
+
|
|
198
|
+
// Validation logic
|
|
199
|
+
if (completionClaimed && !inLastCommit && hasUncommittedChanges) {
|
|
200
|
+
return {
|
|
201
|
+
valid: false,
|
|
202
|
+
warning: `ā ļø Discrepancy detected: You claim "${claim}" but it's not in the last commit`,
|
|
203
|
+
details: {
|
|
204
|
+
lastCommit: lastCommit.message,
|
|
205
|
+
uncommittedFiles: workingStatus.totalChanges,
|
|
206
|
+
suggestion:
|
|
207
|
+
'Consider committing your changes if the work is truly complete',
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (completionClaimed && !inLastCommit && !hasUncommittedChanges) {
|
|
213
|
+
return {
|
|
214
|
+
valid: true,
|
|
215
|
+
warning: `ā¹ļø Note: "${claim}" not mentioned in recent commits`,
|
|
216
|
+
details: {
|
|
217
|
+
lastCommit: lastCommit.message,
|
|
218
|
+
note: 'Work may have been completed in earlier commits',
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
valid: true,
|
|
225
|
+
warning: null,
|
|
226
|
+
note: inLastCommit
|
|
227
|
+
? `ā
Confirmed in last commit: "${lastCommit.message}"`
|
|
228
|
+
: null,
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Extract meaningful keywords from a claim
|
|
234
|
+
* @param {string} claim - User's claim
|
|
235
|
+
* @returns {Array<string>} Extracted keywords
|
|
236
|
+
*/
|
|
237
|
+
extractKeywords(claim) {
|
|
238
|
+
// Remove common words
|
|
239
|
+
const stopWords = new Set([
|
|
240
|
+
'the',
|
|
241
|
+
'is',
|
|
242
|
+
'are',
|
|
243
|
+
'was',
|
|
244
|
+
'were',
|
|
245
|
+
'a',
|
|
246
|
+
'an',
|
|
247
|
+
'and',
|
|
248
|
+
'or',
|
|
249
|
+
'but',
|
|
250
|
+
'in',
|
|
251
|
+
'on',
|
|
252
|
+
'at',
|
|
253
|
+
'to',
|
|
254
|
+
'for',
|
|
255
|
+
'of',
|
|
256
|
+
'with',
|
|
257
|
+
'by',
|
|
258
|
+
'from',
|
|
259
|
+
'up',
|
|
260
|
+
'about',
|
|
261
|
+
'into',
|
|
262
|
+
'through',
|
|
263
|
+
'during',
|
|
264
|
+
'before',
|
|
265
|
+
'after',
|
|
266
|
+
'above',
|
|
267
|
+
'below',
|
|
268
|
+
'between',
|
|
269
|
+
'under',
|
|
270
|
+
'complete',
|
|
271
|
+
'done',
|
|
272
|
+
'finished',
|
|
273
|
+
'ready',
|
|
274
|
+
'shipped',
|
|
275
|
+
])
|
|
276
|
+
|
|
277
|
+
return claim
|
|
278
|
+
.toLowerCase()
|
|
279
|
+
.split(/\s+/)
|
|
280
|
+
.filter(word => word.length > 2 && !stopWords.has(word))
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get git statistics for analysis
|
|
285
|
+
* @returns {Promise<Object>} Git statistics
|
|
286
|
+
*/
|
|
287
|
+
async getGitStats() {
|
|
288
|
+
if (!(await this.isGitRepo())) {
|
|
289
|
+
return {
|
|
290
|
+
isGitRepo: false,
|
|
291
|
+
hasCommits: false,
|
|
292
|
+
totalCommits: 0,
|
|
293
|
+
contributors: [],
|
|
294
|
+
lastCommit: null,
|
|
295
|
+
workingStatus: null,
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
// Total commits
|
|
301
|
+
const totalCommits = parseInt(
|
|
302
|
+
execSync('git rev-list --count HEAD', {
|
|
303
|
+
cwd: this.projectPath,
|
|
304
|
+
encoding: 'utf-8',
|
|
305
|
+
}).trim(),
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
// Contributors
|
|
309
|
+
const contributorsOutput = execSync(
|
|
310
|
+
'git log --format="%an" | sort -u',
|
|
311
|
+
{
|
|
312
|
+
cwd: this.projectPath,
|
|
313
|
+
encoding: 'utf-8',
|
|
314
|
+
},
|
|
315
|
+
)
|
|
316
|
+
const contributors = contributorsOutput.trim().split('\n').filter(Boolean)
|
|
317
|
+
|
|
318
|
+
const lastCommit = await this.getLastCommit()
|
|
319
|
+
const workingStatus = await this.getWorkingDirStatus()
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
isGitRepo: true,
|
|
323
|
+
hasCommits: totalCommits > 0,
|
|
324
|
+
totalCommits,
|
|
325
|
+
contributors,
|
|
326
|
+
lastCommit,
|
|
327
|
+
workingStatus,
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
return {
|
|
331
|
+
isGitRepo: true,
|
|
332
|
+
hasCommits: false,
|
|
333
|
+
totalCommits: 0,
|
|
334
|
+
contributors: [],
|
|
335
|
+
lastCommit: null,
|
|
336
|
+
workingStatus: null,
|
|
337
|
+
error: error.message,
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Check if a specific feature/file is in git history
|
|
344
|
+
* @param {string} searchTerm - Term to search for
|
|
345
|
+
* @returns {Promise<boolean>} True if found in history
|
|
346
|
+
*/
|
|
347
|
+
async isInGitHistory(searchTerm) {
|
|
348
|
+
if (!(await this.isGitRepo())) {
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
try {
|
|
353
|
+
const result = execSync(
|
|
354
|
+
`git log --all --grep="${searchTerm}" --oneline`,
|
|
355
|
+
{
|
|
356
|
+
cwd: this.projectPath,
|
|
357
|
+
encoding: 'utf-8',
|
|
358
|
+
},
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
return result.trim().length > 0
|
|
362
|
+
} catch {
|
|
363
|
+
return false
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get branch information
|
|
369
|
+
* @returns {Promise<Object|null>} Branch info or null
|
|
370
|
+
*/
|
|
371
|
+
async getBranchInfo() {
|
|
372
|
+
if (!(await this.isGitRepo())) {
|
|
373
|
+
return null
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
try {
|
|
377
|
+
const currentBranch = execSync('git branch --show-current', {
|
|
378
|
+
cwd: this.projectPath,
|
|
379
|
+
encoding: 'utf-8',
|
|
380
|
+
}).trim()
|
|
381
|
+
|
|
382
|
+
const allBranches = execSync('git branch --list', {
|
|
383
|
+
cwd: this.projectPath,
|
|
384
|
+
encoding: 'utf-8',
|
|
385
|
+
})
|
|
386
|
+
.trim()
|
|
387
|
+
.split('\n')
|
|
388
|
+
.map(b => b.trim().replace('* ', ''))
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
current: currentBranch,
|
|
392
|
+
all: allBranches,
|
|
393
|
+
count: allBranches.length,
|
|
394
|
+
}
|
|
395
|
+
} catch {
|
|
396
|
+
return null
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
module.exports = new GitIntegration()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prjct-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
|
|
5
5
|
"main": "core/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"prjct": "./bin/prjct"
|
|
@@ -25,13 +25,16 @@
|
|
|
25
25
|
"website:install": "cd website && npm install"
|
|
26
26
|
},
|
|
27
27
|
"keywords": [
|
|
28
|
-
"
|
|
28
|
+
"claude-code",
|
|
29
|
+
"claude-desktop",
|
|
30
|
+
"developer-momentum",
|
|
29
31
|
"indie-hacker",
|
|
32
|
+
"ship-fast",
|
|
30
33
|
"ai-assistant",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
34
|
+
"productivity",
|
|
35
|
+
"developer-tools",
|
|
36
|
+
"no-bs",
|
|
37
|
+
"focus"
|
|
35
38
|
],
|
|
36
39
|
"author": "prjct.dev",
|
|
37
40
|
"license": "MIT",
|
package/scripts/install.sh
CHANGED
|
@@ -99,7 +99,6 @@ clear
|
|
|
99
99
|
# Clean header with Catppuccin colors
|
|
100
100
|
echo ""
|
|
101
101
|
echo ""
|
|
102
|
-
echo -e " ${BOLD}${CYAN}(ļ¾āć®ā)ļ¾*:dļ¾ā§${NC}"
|
|
103
102
|
echo -e " ${BOLD}${CYAN}āāāāāāā āāāāāāā āāā āāāāāāāāāāāāāāāā${NC}"
|
|
104
103
|
echo -e " ${BOLD}${CYAN}āāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā${NC}"
|
|
105
104
|
echo -e " ${BOLD}${CYAN}āāāāāāāāāāāāāāāā āāāāāā āāā${NC}"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: p_agent_be
|
|
3
|
+
description: Backend Engineer for [PROJECT_NAME]. Expert in [FRAMEWORK]. Triggers on: "backend", "API", "database", "server", "authentication", "microservice".
|
|
4
|
+
tools: str_replace_editor, create_file, delete_file, find_files, list_dir, search_files, view_file, run_terminal_command
|
|
5
|
+
model: opus
|
|
6
|
+
color: yellow
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a Senior Backend Engineer for **[PROJECT_NAME]**.
|
|
10
|
+
|
|
11
|
+
## Project Context
|
|
12
|
+
- **Stack**: [DETECTED_STACK]
|
|
13
|
+
- **Architecture**: [DETECTED_PATTERN]
|
|
14
|
+
- **Primary Language**: [PRIMARY_LANGUAGE]
|
|
15
|
+
|
|
16
|
+
## Core Expertise
|
|
17
|
+
- **API Design**: RESTful, GraphQL, efficient endpoints
|
|
18
|
+
- **Database**: Schema design, queries, optimization
|
|
19
|
+
- **Authentication**: JWT, OAuth, session management
|
|
20
|
+
- **Architecture**: Clean code, SOLID principles, DRY
|
|
21
|
+
- **Performance**: Caching, query optimization, scalability
|
|
22
|
+
|
|
23
|
+
## NOT Your Expertise
|
|
24
|
+
- Frontend UI implementation
|
|
25
|
+
- DevOps infrastructure (defer to DevOps)
|
|
26
|
+
- UX design decisions
|
|
27
|
+
|
|
28
|
+
## Development Principles
|
|
29
|
+
1. **SOLID Principles**: Single responsibility, dependency inversion
|
|
30
|
+
2. **Security First**: Validate inputs, protect endpoints
|
|
31
|
+
3. **Scalability**: Design for growth
|
|
32
|
+
4. **Testing**: Unit tests, integration tests
|
|
33
|
+
5. **Documentation**: Clear API docs
|
|
34
|
+
|
|
35
|
+
## Focus Areas
|
|
36
|
+
- API endpoints and business logic
|
|
37
|
+
- Database schema and queries
|
|
38
|
+
- Authentication and authorization
|
|
39
|
+
- Data validation and error handling
|
|
40
|
+
- Performance optimization
|
|
41
|
+
|
|
42
|
+
Remember: You build the server layer. Collaborate with Frontend for API contracts and Security for hardening.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: p_agent_data
|
|
3
|
+
description: Data Science Engineer for [PROJECT_NAME]. Expert in ML, data analysis, and pipelines. Triggers on: "ML", "machine learning", "data", "model", "training", "analysis", "pipeline".
|
|
4
|
+
tools: str_replace_editor, create_file, delete_file, find_files, list_dir, search_files, view_file, run_terminal_command
|
|
5
|
+
model: opus
|
|
6
|
+
color: teal
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a Data Science Engineer for **[PROJECT_NAME]**.
|
|
10
|
+
|
|
11
|
+
## Project Context
|
|
12
|
+
- **Stack**: [DETECTED_STACK]
|
|
13
|
+
- **Type**: [PROJECT_TYPE]
|
|
14
|
+
|
|
15
|
+
## Core Expertise
|
|
16
|
+
- **Machine Learning**: Model training, evaluation, deployment
|
|
17
|
+
- **Data Pipelines**: ETL, data processing
|
|
18
|
+
- **Analysis**: Statistical analysis, visualization
|
|
19
|
+
- **Optimization**: Model performance, inference speed
|
|
20
|
+
- **MLOps**: Model versioning, monitoring
|
|
21
|
+
|
|
22
|
+
## NOT Your Expertise
|
|
23
|
+
- Frontend UI implementation
|
|
24
|
+
- Infrastructure (defer to DevOps)
|
|
25
|
+
- Non-ML backend logic
|
|
26
|
+
|
|
27
|
+
## Data Science Principles
|
|
28
|
+
1. **Data Quality**: Garbage in, garbage out
|
|
29
|
+
2. **Reproducibility**: Version everything
|
|
30
|
+
3. **Validation**: Always validate models
|
|
31
|
+
4. **Monitoring**: Track model performance
|
|
32
|
+
5. **Ethics**: Consider bias and fairness
|
|
33
|
+
|
|
34
|
+
## Focus Areas
|
|
35
|
+
- Model development and training
|
|
36
|
+
- Data preprocessing and feature engineering
|
|
37
|
+
- Model evaluation and validation
|
|
38
|
+
- Deployment and monitoring
|
|
39
|
+
- Data visualization
|
|
40
|
+
|
|
41
|
+
Remember: Models are only as good as the data and evaluation. Prioritize data quality and proper validation.
|