prjct-cli 0.8.6 → 0.9.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 (47) hide show
  1. package/CHANGELOG.md +216 -0
  2. package/CLAUDE.md +34 -0
  3. package/core/agentic/agent-router.js +482 -0
  4. package/core/agentic/command-executor.js +70 -15
  5. package/core/agentic/context-builder.js +4 -3
  6. package/core/agentic/context-filter.js +545 -0
  7. package/core/agentic/prompt-builder.js +48 -38
  8. package/core/agentic/tool-registry.js +35 -0
  9. package/core/command-registry.js +104 -164
  10. package/core/commands.js +84 -0
  11. package/core/domain/agent-generator.js +55 -44
  12. package/core/domain/architecture-generator.js +561 -0
  13. package/core/domain/task-stack.js +496 -0
  14. package/core/infrastructure/legacy-installer-detector.js +546 -0
  15. package/core/infrastructure/session-manager.js +14 -2
  16. package/core/infrastructure/setup.js +29 -11
  17. package/core/utils/jsonl-helper.js +137 -0
  18. package/package.json +1 -1
  19. package/scripts/install.sh +45 -8
  20. package/scripts/postinstall.js +5 -5
  21. package/templates/agents/AGENTS.md +3 -3
  22. package/templates/commands/analyze.md +10 -53
  23. package/templates/commands/ask.md +25 -338
  24. package/templates/commands/bug.md +11 -70
  25. package/templates/commands/build.md +8 -35
  26. package/templates/commands/cleanup.md +9 -32
  27. package/templates/commands/dash.md +241 -0
  28. package/templates/commands/design.md +5 -28
  29. package/templates/commands/done.md +6 -20
  30. package/templates/commands/feature.md +12 -225
  31. package/templates/commands/help.md +26 -313
  32. package/templates/commands/idea.md +7 -25
  33. package/templates/commands/init.md +15 -191
  34. package/templates/commands/migrate-all.md +25 -84
  35. package/templates/commands/next.md +6 -26
  36. package/templates/commands/now.md +6 -25
  37. package/templates/commands/pause.md +18 -0
  38. package/templates/commands/progress.md +5 -50
  39. package/templates/commands/recap.md +5 -54
  40. package/templates/commands/resume.md +97 -0
  41. package/templates/commands/ship.md +14 -135
  42. package/templates/commands/status.md +7 -32
  43. package/templates/commands/suggest.md +36 -495
  44. package/templates/commands/sync.md +7 -24
  45. package/templates/commands/work.md +44 -0
  46. package/templates/commands/workflow.md +3 -25
  47. package/templates/planning-methodology.md +195 -0
@@ -1,4 +1,7 @@
1
1
  const fs = require('fs').promises
2
+ const fsSync = require('fs')
3
+ const readline = require('readline')
4
+ const path = require('path')
2
5
 
3
6
  /**
4
7
  * JSONL Helper - Centralized JSONL parsing and writing
@@ -190,6 +193,134 @@ async function isJsonLinesEmpty(filePath) {
190
193
  return count === 0
191
194
  }
192
195
 
196
+ /**
197
+ * Read JSONL file with streaming (memory-efficient for large files)
198
+ * Only reads last N lines instead of loading entire file
199
+ *
200
+ * @param {string} filePath - Path to JSONL file
201
+ * @param {number} maxLines - Maximum lines to read (default: 1000)
202
+ * @returns {Promise<Array<Object>>} - Array of parsed objects (last N lines)
203
+ */
204
+ async function readJsonLinesStreaming(filePath, maxLines = 1000) {
205
+ try {
206
+ const fileStream = fsSync.createReadStream(filePath)
207
+ const rl = readline.createInterface({
208
+ input: fileStream,
209
+ crlfDelay: Infinity,
210
+ })
211
+
212
+ const lines = []
213
+
214
+ for await (const line of rl) {
215
+ if (line.trim()) {
216
+ try {
217
+ lines.push(JSON.parse(line))
218
+ } catch {
219
+ // Skip malformed lines
220
+ }
221
+
222
+ // Keep only last maxLines
223
+ if (lines.length > maxLines) {
224
+ lines.shift()
225
+ }
226
+ }
227
+ }
228
+
229
+ return lines
230
+ } catch (error) {
231
+ if (error.code === 'ENOENT') {
232
+ return []
233
+ }
234
+ throw error
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Get file size in MB
240
+ *
241
+ * @param {string} filePath - Path to file
242
+ * @returns {Promise<number>} - File size in MB
243
+ */
244
+ async function getFileSizeMB(filePath) {
245
+ try {
246
+ const stats = await fs.stat(filePath)
247
+ return stats.size / (1024 * 1024)
248
+ } catch (error) {
249
+ if (error.code === 'ENOENT') {
250
+ return 0
251
+ }
252
+ throw error
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Rotate JSONL file if it exceeds size limit
258
+ * Moves large file to archive with timestamp
259
+ *
260
+ * @param {string} filePath - Path to JSONL file
261
+ * @param {number} maxSizeMB - Maximum size in MB before rotation (default: 10)
262
+ * @returns {Promise<boolean>} - True if rotated, false if not needed
263
+ */
264
+ async function rotateJsonLinesIfNeeded(filePath, maxSizeMB = 10) {
265
+ const sizeMB = await getFileSizeMB(filePath)
266
+
267
+ if (sizeMB < maxSizeMB) {
268
+ return false // No rotation needed
269
+ }
270
+
271
+ // Generate archive filename with timestamp
272
+ const timestamp = new Date().toISOString().split('T')[0] // YYYY-MM-DD
273
+ const dir = path.dirname(filePath)
274
+ const ext = path.extname(filePath)
275
+ const base = path.basename(filePath, ext)
276
+ const archivePath = path.join(dir, `${base}-${timestamp}${ext}`)
277
+
278
+ // Move file to archive
279
+ await fs.rename(filePath, archivePath)
280
+
281
+ console.log(`📦 Rotated ${path.basename(filePath)} (${sizeMB.toFixed(1)}MB) → ${path.basename(archivePath)}`)
282
+
283
+ return true
284
+ }
285
+
286
+ /**
287
+ * Append JSON line with automatic rotation
288
+ * Checks file size before append and rotates if needed
289
+ *
290
+ * @param {string} filePath - Path to JSONL file
291
+ * @param {Object} object - Object to append
292
+ * @param {number} maxSizeMB - Maximum size before rotation (default: 10)
293
+ * @returns {Promise<void>}
294
+ */
295
+ async function appendJsonLineWithRotation(filePath, object, maxSizeMB = 10) {
296
+ // Rotate if needed (before appending)
297
+ await rotateJsonLinesIfNeeded(filePath, maxSizeMB)
298
+
299
+ // Append normally
300
+ await appendJsonLine(filePath, object)
301
+ }
302
+
303
+ /**
304
+ * Warn if file is large before reading
305
+ * Returns size and whether it's considered large
306
+ *
307
+ * @param {string} filePath - Path to file
308
+ * @param {number} warnThresholdMB - Threshold in MB to warn (default: 50)
309
+ * @returns {Promise<{sizeMB: number, isLarge: boolean}>}
310
+ */
311
+ async function checkFileSizeWarning(filePath, warnThresholdMB = 50) {
312
+ const sizeMB = await getFileSizeMB(filePath)
313
+ const isLarge = sizeMB > warnThresholdMB
314
+
315
+ if (isLarge) {
316
+ console.warn(
317
+ `⚠️ Large file detected: ${path.basename(filePath)} (${sizeMB.toFixed(1)}MB). Reading may use significant memory.`
318
+ )
319
+ }
320
+
321
+ return { sizeMB, isLarge }
322
+ }
323
+
193
324
  module.exports = {
194
325
  parseJsonLines,
195
326
  stringifyJsonLines,
@@ -203,4 +334,10 @@ module.exports = {
203
334
  getFirstJsonLines,
204
335
  mergeJsonLines,
205
336
  isJsonLinesEmpty,
337
+ // NEW: Memory-efficient functions
338
+ readJsonLinesStreaming,
339
+ getFileSizeMB,
340
+ rotateJsonLinesIfNeeded,
341
+ appendJsonLineWithRotation,
342
+ checkFileSizeWarning,
206
343
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.8.6",
3
+ "version": "0.9.1",
4
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": {
@@ -9,22 +9,59 @@
9
9
  YELLOW='\033[1;33m'
10
10
  CYAN='\033[0;36m'
11
11
  GREEN='\033[0;32m'
12
+ RED='\033[0;31m'
13
+ BOLD='\033[1m'
14
+ DIM='\033[2m'
12
15
  NC='\033[0m'
13
16
 
17
+ # Check if legacy installation exists
18
+ LEGACY_DIR="$HOME/.prjct-cli"
19
+ HAS_LEGACY=false
20
+ LEGACY_VERSION="unknown"
21
+
22
+ if [ -d "$LEGACY_DIR" ]; then
23
+ # Check if it's a git clone (legacy curl install)
24
+ if [ -d "$LEGACY_DIR/.git" ]; then
25
+ HAS_LEGACY=true
26
+ if [ -f "$LEGACY_DIR/package.json" ]; then
27
+ LEGACY_VERSION=$(grep -o '"version":[[:space:]]*"[^"]*"' "$LEGACY_DIR/package.json" | head -1 | cut -d'"' -f4)
28
+ fi
29
+ fi
30
+ fi
31
+
14
32
  echo ""
15
33
  echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
16
34
  echo -e "${YELLOW}⚠️ This installation method is DEPRECATED${NC}"
17
35
  echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
18
36
  echo ""
19
- echo -e "Please use npm instead:"
20
- echo ""
21
- echo -e " ${GREEN}npm install -g prjct-cli${NC}"
22
- echo ""
23
- echo -e "Benefits of npm installation:"
24
- echo -e "${CYAN}Automatic setup${NC} - No manual configuration needed"
25
- echo -e " • ${CYAN}Auto-migration${NC} - Legacy projects migrated automatically"
26
- echo -e "${CYAN}Beautiful ASCII art${NC} - See the installation success"
37
+
38
+ if [ "$HAS_LEGACY" = true ]; then
39
+ echo -e "${RED}⚠️ Legacy curl installation detected!${NC}"
40
+ echo ""
41
+ echo -e " ${DIM}Version: ${LEGACY_VERSION}${NC}"
42
+ echo -e " ${DIM}Location: ~/.prjct-cli/${NC}"
43
+ echo ""
44
+ echo -e "${CYAN}Migration Required:${NC}"
45
+ echo ""
46
+ echo -e " 1. ${BOLD}Install via npm:${NC}"
47
+ echo -e " ${GREEN}npm install -g prjct-cli${NC}"
48
+ echo ""
49
+ echo -e " 2. ${BOLD}Automatic cleanup:${NC}"
50
+ echo -e " ${DIM}Legacy installation will be cleaned automatically${NC}"
51
+ echo -e " ${DIM}Your project data will be preserved${NC}"
52
+ echo ""
53
+ else
54
+ echo -e "${CYAN}Please install using npm:${NC}"
55
+ echo ""
56
+ echo -e " ${GREEN}npm install -g prjct-cli${NC}"
57
+ echo ""
58
+ fi
59
+
60
+ echo -e "${BOLD}Benefits of npm installation:${NC}"
61
+ echo -e " • ${CYAN}Automatic cleanup${NC} - Removes old curl installations"
62
+ echo -e " • ${CYAN}Data preservation${NC} - Your projects are migrated safely"
27
63
  echo -e " • ${CYAN}Easy updates${NC} - Just npm update -g prjct-cli"
64
+ echo -e " • ${CYAN}Proper versioning${NC} - npm handles everything"
28
65
  echo ""
29
66
  echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
30
67
  echo ""
@@ -3,13 +3,13 @@
3
3
  /**
4
4
  * Post-install hook for prjct-cli (OPTIONAL)
5
5
  *
6
- * Intenta ejecutar setup si npm scripts están habilitados.
7
- * Si falla o no se ejecuta, no hay problema - el setup se ejecutará
8
- * automáticamente en el primer uso del CLI (como Astro, Vite, etc.)
6
+ * Attempts to run setup if npm scripts are enabled.
7
+ * If it fails or doesn't run, no problem - setup will run
8
+ * automatically on first CLI use (like Astro, Vite, etc.)
9
9
  *
10
- * Este hook es una optimización pero NO es crítico.
10
+ * This hook is an optimization but NOT critical.
11
11
  *
12
- * @version 0.8.5
12
+ * @version 0.8.8
13
13
  */
14
14
 
15
15
  const path = require('path')
@@ -167,13 +167,13 @@ Semantic understanding, not pattern matching.
167
167
 
168
168
  | Intent | Command | Examples |
169
169
  | ---------- | ---------- | -------------------------------------------- |
170
- | Start task | `/p:now` | "work on X", "starting API", "voy a hacer X" |
171
- | Finish | `/p:done` | "done", "finished", "terminé", "listo" |
170
+ | Start task | `/p:now` | "work on X", "starting API", "begin auth" |
171
+ | Finish | `/p:done` | "done", "finished", "completed", "all set" |
172
172
  | Ship | `/p:ship` | "ship this", "deploy X", "it's ready" |
173
173
  | Idea | `/p:idea` | "I have an idea", "what if we..." |
174
174
  | Progress | `/p:recap` | "show progress", "how am I doing" |
175
175
  | Stuck | `/p:stuck` | "I'm stuck", "help with X" |
176
- | Next | `/p:next` | "what's next", "qué sigue" |
176
+ | Next | `/p:next` | "what's next", "show queue", "priority list" |
177
177
 
178
178
  **Any language works** - if you understand intent, execute the command.
179
179
 
@@ -1,63 +1,20 @@
1
1
  ---
2
2
  allowed-tools: [Read, Grep, Glob, Bash, TodoWrite]
3
- description: 'Analyze repository and generate summary'
3
+ description: 'Analyze repo + generate summary'
4
4
  ---
5
5
 
6
6
  # /p:analyze
7
7
 
8
8
  ## Flow
9
+ 1. Scan structure → Detect tech (package.json, Gemfile, etc.)
10
+ 2. Analyze patterns → Git status
11
+ 3. Generate → `analysis/repo-summary.md`
9
12
 
10
- 1. Scan: project structure (Glob)
11
- 2. Detect: technologies (package.json, requirements.txt, etc.)
12
- 3. Analyze: architecture patterns
13
- 4. Git: status and stats
14
- 5. Generate: comprehensive report
15
- 6. Save: `analysis/repo-summary.md`
16
-
17
- ## Report Format
18
-
19
- ```markdown
20
- # Repository Analysis
21
-
22
- ## Overview
23
-
24
- - Type: {type}
25
- - Language: {lang}
26
- - Framework: {framework}
27
-
28
- ## Git Status
29
-
30
- - Last commit: {hash} "{msg}" ({time_ago})
31
- - Status: {clean/has_changes}
32
-
33
- ## Stack
34
-
35
- - Languages: {list}
36
- - Frameworks: {list}
37
- - Dependencies: {count}
38
-
39
- ## Architecture
40
-
41
- - Pattern: {pattern}
42
- - Entry points: {files}
43
-
44
- ## Recommended Agents
45
-
46
- Base (6): PM, UX, FE, BE, QA, Scribe
47
- Additional: {conditional_agents}
48
-
49
- Generated: {timestamp}
50
- ```
13
+ ## Report
14
+ - Overview: type, lang, framework
15
+ - Stack: technologies detected
16
+ - Architecture: patterns, entry points
17
+ - Agents: recommend specialists
51
18
 
52
19
  ## Response
53
-
54
- ```
55
- 🔍 Analysis complete!
56
-
57
- Project: {name} ({type})
58
- Stack: {stack}
59
-
60
- 📄 Full report: analysis/repo-summary.md
61
-
62
- /p:roadmap | /p:now
63
- ```
20
+ `🔍 {project} | Stack: {tech} | Saved: analysis/repo-summary.md`