prjct-cli 0.23.0 → 0.25.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 CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.25.0] - 2025-12-30
4
+
5
+ ### Maintenance Release
6
+
7
+ Version bump for release preparation.
8
+
9
+ ## [0.24.0] - 2025-12-28
10
+
11
+ ### Breaking Change: Unified Task Command
12
+
13
+ Consolidated `/p:now`, `/p:feature`, and `/p:work` into a single `/p:task` command with agentic classification.
14
+
15
+ **New Command: `/p:task`**
16
+ - Unified entry point for all work
17
+ - Agentic type classification (not keyword-based)
18
+ - 7-phase development workflow for all task types
19
+ - Git branch management with type-based prefixes
20
+
21
+ **Agentic Classification:**
22
+ The agent analyzes task descriptions holistically to determine type:
23
+ - `feature` - Adds new functionality
24
+ - `bug` - Something broken or incorrect
25
+ - `improvement` - Enhances existing functionality
26
+ - `refactor` - Reorganizes without behavior change
27
+ - `chore` - Maintenance, deps, docs
28
+
29
+ **Migration:**
30
+ ```
31
+ /p:now "fix login bug" → /p:task "fix login bug"
32
+ /p:feature "add dark mode" → /p:task "add dark mode"
33
+ /p:work "update docs" → /p:task "update docs"
34
+ ```
35
+
36
+ **Deprecated Commands:**
37
+ - `/p:now` - Redirects to `/p:task`
38
+ - `/p:feature` - Redirects to `/p:task`
39
+ - `/p:work` - Redirects to `/p:task`
40
+
41
+ **Files Changed:**
42
+ - `templates/commands/task.md` - New unified template
43
+ - `templates/commands/now.md` - Deprecated, redirects
44
+ - `templates/commands/feature.md` - Deprecated, redirects
45
+ - `core/commands/command-data.ts` - Registry updates
46
+ - `templates/global/CLAUDE.md` - Updated workflow docs
47
+ - `CLAUDE.md` - Updated project docs
48
+
3
49
  ## [0.23.0] - 2025-12-28
4
50
 
5
51
  ### Feature: Branch + PR Workflow
package/CLAUDE.md CHANGED
@@ -86,19 +86,18 @@ User Action → Storage (JSON) → Context (MD) → Sync Events
86
86
  ## Core Workflow
87
87
 
88
88
  ```
89
- /p:sync → /p:now "task" → [work] → /p:done → /p:ship
89
+ /p:sync → /p:task "description" → [work] → /p:done → /p:ship
90
90
  ```
91
91
 
92
92
  ## Commands
93
93
 
94
- ### Core Commands (14)
94
+ ### Core Commands
95
95
  | Command | Purpose |
96
96
  |---------|---------|
97
97
  | `/p:init` | Initialize project with deep analysis |
98
98
  | `/p:idea` | Transform ideas into architectures |
99
- | `/p:feature` | Add feature with value analysis |
99
+ | `/p:task` | Start task with agentic classification + 7-phase workflow |
100
100
  | `/p:spec` | Create detailed specifications |
101
- | `/p:now [task]` | Start/show current task |
102
101
  | `/p:pause` | Pause active task |
103
102
  | `/p:resume` | Resume paused task |
104
103
  | `/p:next` | Show priority queue |
@@ -109,6 +108,13 @@ User Action → Storage (JSON) → Context (MD) → Sync Events
109
108
  | `/p:sync` | Analyze repo, generate agents |
110
109
  | `/p:suggest` | Context-aware recommendations |
111
110
 
111
+ ### Deprecated Commands
112
+ | Command | Migration |
113
+ |---------|-----------|
114
+ | `/p:now` | Use `/p:task` instead |
115
+ | `/p:feature` | Use `/p:task` instead |
116
+ | `/p:work` | Use `/p:task` instead |
117
+
112
118
  ### Optional Commands
113
119
  | Command | Purpose |
114
120
  |---------|---------|
@@ -123,9 +129,10 @@ User Action → Storage (JSON) → Context (MD) → Sync Events
123
129
 
124
130
  Messages starting with `p.` trigger commands:
125
131
  ```
126
- p. start auth → /p:now "auth"
127
- p. done → /p:done
128
- p. ship login → /p:ship "login"
132
+ p. task add auth → /p:task "add auth"
133
+ p. task fix login → /p:task "fix login"
134
+ p. done → /p:done
135
+ p. ship login → /p:ship "login"
129
136
  ```
130
137
 
131
138
  ## Template-Driven Execution
@@ -51,16 +51,27 @@ export const COMMANDS: CommandMeta[] = [
51
51
  requiresProject: true,
52
52
  features: ['Simple ideas -> Quick capture', 'Complex ideas -> Full architecture'],
53
53
  },
54
+ {
55
+ name: 'task',
56
+ group: 'core',
57
+ description: 'Start task with agentic classification and 7-phase workflow',
58
+ usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
59
+ params: '<description>',
60
+ implemented: true,
61
+ hasTemplate: true,
62
+ requiresProject: true,
63
+ features: ['Agentic type classification', '7-phase workflow', 'Git branch management', 'Task breakdown'],
64
+ },
54
65
  {
55
66
  name: 'feature',
56
67
  group: 'core',
57
- description: 'Add feature with value analysis and task breakdown',
58
- usage: { claude: '/p:feature "add testing"', terminal: 'prjct feature "add testing"' },
68
+ description: 'DEPRECATED - Use /p:task instead',
69
+ usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
59
70
  params: '<description>',
60
71
  implemented: true,
61
72
  hasTemplate: true,
62
73
  requiresProject: true,
63
- features: ['Value analysis', 'Auto roadmap generation', 'Task breakdown'],
74
+ deprecated: true,
64
75
  },
65
76
  {
66
77
  name: 'spec',
@@ -75,22 +86,24 @@ export const COMMANDS: CommandMeta[] = [
75
86
  {
76
87
  name: 'now',
77
88
  group: 'core',
78
- description: 'Set or show current task with session tracking',
79
- usage: { claude: '/p:now ["task"]', terminal: 'prjct now ["task"]' },
80
- params: '[task] [estimate]',
89
+ description: 'DEPRECATED - Use /p:task instead',
90
+ usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
91
+ params: '[task]',
81
92
  implemented: true,
82
93
  hasTemplate: true,
83
94
  requiresProject: true,
95
+ deprecated: true,
84
96
  },
85
97
  {
86
98
  name: 'work',
87
99
  group: 'core',
88
- description: 'Set or show current task (alias for now)',
89
- usage: { claude: '/p:work ["task"]', terminal: 'prjct work ["task"]' },
100
+ description: 'DEPRECATED - Use /p:task instead',
101
+ usage: { claude: '/p:task "<description>"', terminal: 'prjct task "<description>"' },
90
102
  params: '[task]',
91
103
  implemented: true,
92
104
  hasTemplate: true,
93
105
  requiresProject: true,
106
+ deprecated: true,
94
107
  },
95
108
  {
96
109
  name: 'pause',
@@ -130,28 +130,63 @@ export class SetupCommands extends PrjctCommandsBase {
130
130
  const settingsPath = path.join(claudeDir, 'settings.json')
131
131
  const statusLinePath = path.join(claudeDir, 'prjct-statusline.sh')
132
132
 
133
+ // Version is embedded at install time
133
134
  const scriptContent = `#!/bin/bash
134
135
  # prjct Status Line for Claude Code
135
- # Shows prjct with animated spinner when command is running
136
+ # Shows version update notifications and current task
137
+
138
+ # Current CLI version (embedded at install time)
139
+ CLI_VERSION="${VERSION}"
136
140
 
137
141
  # Read JSON context from stdin (provided by Claude Code)
138
142
  read -r json
139
143
 
140
- # Spinner frames
141
- frames=('⠋' '⠙' '⠹' '⠸' '⠼' '' '⠦' '⠧' '' '⠏')
142
-
143
- # Calculate frame based on time (changes every 80ms)
144
- frame=$(($(date +%s%N 2>/dev/null || echo 0) / 80000000 % 10))
145
-
146
- # Check if prjct command is running
147
- running_file="$HOME/.prjct-cli/.running"
148
-
149
- if [ -f "$running_file" ]; then
150
- task=$(cat "$running_file" 2>/dev/null || echo "working")
151
- echo "⚡ prjct \${frames[$frame]} $task"
152
- else
153
- echo " prjct"
144
+ # Extract cwd from JSON
145
+ CWD=$(echo "$json" | grep -o '"cwd"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"cwd"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
146
+
147
+ # Check if this is a prjct project
148
+ CONFIG="$CWD/.prjct/prjct.config.json"
149
+ if [[ -f "$CONFIG" ]]; then
150
+ # Extract projectId
151
+ PROJECT_ID=$(grep -o '"projectId"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG" | sed 's/.*"projectId"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
152
+
153
+ if [[ -n "$PROJECT_ID" ]]; then
154
+ PROJECT_JSON="$HOME/.prjct-cli/projects/$PROJECT_ID/project.json"
155
+
156
+ # Check version mismatch
157
+ if [[ -f "$PROJECT_JSON" ]]; then
158
+ PROJECT_VERSION=$(grep -o '"cliVersion"[[:space:]]*:[[:space:]]*"[^"]*"' "$PROJECT_JSON" | sed 's/.*"cliVersion"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
159
+
160
+ # If no cliVersion or different version, show update notice
161
+ if [[ -z "$PROJECT_VERSION" ]] || [[ "$PROJECT_VERSION" != "$CLI_VERSION" ]]; then
162
+ echo "⚠️ prjct v$CLI_VERSION available! Run /p:sync"
163
+ exit 0
164
+ fi
165
+ else
166
+ # No project.json means project needs sync
167
+ echo "⚠️ prjct v$CLI_VERSION available! Run /p:sync"
168
+ exit 0
169
+ fi
170
+
171
+ # Show current task if exists
172
+ STATE="$HOME/.prjct-cli/projects/$PROJECT_ID/storage/state.json"
173
+ if [[ -f "$STATE" ]]; then
174
+ TASK=$(grep -o '"description"[[:space:]]*:[[:space:]]*"[^"]*"' "$STATE" | head -1 | sed 's/.*"description"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
175
+ STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$STATE" | head -1 | sed 's/.*"status"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
176
+
177
+ if [[ -n "$TASK" ]] && [[ "$STATUS" == "active" ]]; then
178
+ # Truncate task to 40 chars
179
+ TASK_SHORT="\${TASK:0:40}"
180
+ [[ \${#TASK} -gt 40 ]] && TASK_SHORT="$TASK_SHORT..."
181
+ echo "🎯 $TASK_SHORT"
182
+ exit 0
183
+ fi
184
+ fi
185
+ fi
154
186
  fi
187
+
188
+ # Default: show prjct branding
189
+ echo "⚡ prjct"
155
190
  `
156
191
  fs.writeFileSync(statusLinePath, scriptContent, { mode: 0o755 })
157
192
 
@@ -204,8 +239,8 @@ fi
204
239
  console.log(` ${chalk.bold('1.')} Initialize your project:`)
205
240
  console.log(` ${chalk.green('cd your-project && prjct init')}`)
206
241
  console.log('')
207
- console.log(` ${chalk.bold('2.')} Set your current focus:`)
208
- console.log(` ${chalk.green('prjct now "build auth"')}`)
242
+ console.log(` ${chalk.bold('2.')} Start your first task:`)
243
+ console.log(` ${chalk.green('prjct task "build auth"')}`)
209
244
  console.log('')
210
245
  console.log(` ${chalk.bold('3.')} Ship & celebrate:`)
211
246
  console.log(` ${chalk.green('prjct ship "user login"')}`)
@@ -13,6 +13,9 @@
13
13
  */
14
14
 
15
15
  import { execSync } from 'child_process'
16
+ import fs from 'fs'
17
+ import path from 'path'
18
+ import os from 'os'
16
19
  import installer from './command-installer'
17
20
  import editorsConfig from './editors-config'
18
21
  import { VERSION } from '../utils/version'
@@ -106,6 +109,9 @@ export async function run(): Promise<SetupResults> {
106
109
 
107
110
  // Step 4b: Install documentation files
108
111
  await installer.installDocs()
112
+
113
+ // Step 4c: Install status line with version check
114
+ await installStatusLine()
109
115
  }
110
116
 
111
117
  // Step 5: Save version in editors-config
@@ -120,6 +126,101 @@ export async function run(): Promise<SetupResults> {
120
126
  // Default export for CommonJS require
121
127
  export default { run }
122
128
 
129
+ /**
130
+ * Install status line script with version check
131
+ */
132
+ async function installStatusLine(): Promise<void> {
133
+ try {
134
+ const claudeDir = path.join(os.homedir(), '.claude')
135
+ const settingsPath = path.join(claudeDir, 'settings.json')
136
+ const statusLinePath = path.join(claudeDir, 'prjct-statusline.sh')
137
+
138
+ // Ensure .claude directory exists
139
+ if (!fs.existsSync(claudeDir)) {
140
+ fs.mkdirSync(claudeDir, { recursive: true })
141
+ }
142
+
143
+ // Version is embedded at install time
144
+ const scriptContent = `#!/bin/bash
145
+ # prjct Status Line for Claude Code
146
+ # Shows version update notifications and current task
147
+
148
+ # Current CLI version (embedded at install time)
149
+ CLI_VERSION="${VERSION}"
150
+
151
+ # Read JSON context from stdin (provided by Claude Code)
152
+ read -r json
153
+
154
+ # Extract cwd from JSON
155
+ CWD=$(echo "$json" | grep -o '"cwd"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"cwd"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
156
+
157
+ # Check if this is a prjct project
158
+ CONFIG="$CWD/.prjct/prjct.config.json"
159
+ if [[ -f "$CONFIG" ]]; then
160
+ # Extract projectId
161
+ PROJECT_ID=$(grep -o '"projectId"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG" | sed 's/.*"projectId"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
162
+
163
+ if [[ -n "$PROJECT_ID" ]]; then
164
+ PROJECT_JSON="$HOME/.prjct-cli/projects/$PROJECT_ID/project.json"
165
+
166
+ # Check version mismatch
167
+ if [[ -f "$PROJECT_JSON" ]]; then
168
+ PROJECT_VERSION=$(grep -o '"cliVersion"[[:space:]]*:[[:space:]]*"[^"]*"' "$PROJECT_JSON" | sed 's/.*"cliVersion"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
169
+
170
+ # If no cliVersion or different version, show update notice
171
+ if [[ -z "$PROJECT_VERSION" ]] || [[ "$PROJECT_VERSION" != "$CLI_VERSION" ]]; then
172
+ echo "⚠️ prjct v$CLI_VERSION available! Run /p:sync"
173
+ exit 0
174
+ fi
175
+ else
176
+ # No project.json means project needs sync
177
+ echo "⚠️ prjct v$CLI_VERSION available! Run /p:sync"
178
+ exit 0
179
+ fi
180
+
181
+ # Show current task if exists
182
+ STATE="$HOME/.prjct-cli/projects/$PROJECT_ID/storage/state.json"
183
+ if [[ -f "$STATE" ]]; then
184
+ TASK=$(grep -o '"description"[[:space:]]*:[[:space:]]*"[^"]*"' "$STATE" | head -1 | sed 's/.*"description"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
185
+ STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$STATE" | head -1 | sed 's/.*"status"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/')
186
+
187
+ if [[ -n "$TASK" ]] && [[ "$STATUS" == "active" ]]; then
188
+ # Truncate task to 40 chars
189
+ TASK_SHORT="\${TASK:0:40}"
190
+ [[ \${#TASK} -gt 40 ]] && TASK_SHORT="$TASK_SHORT..."
191
+ echo "🎯 $TASK_SHORT"
192
+ exit 0
193
+ fi
194
+ fi
195
+ fi
196
+ fi
197
+
198
+ # Default: show prjct branding
199
+ echo "⚡ prjct"
200
+ `
201
+ fs.writeFileSync(statusLinePath, scriptContent, { mode: 0o755 })
202
+
203
+ // Update settings.json to use this status line
204
+ let settings: Record<string, unknown> = {}
205
+ if (fs.existsSync(settingsPath)) {
206
+ try {
207
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'))
208
+ } catch {
209
+ // Invalid JSON, start fresh
210
+ }
211
+ }
212
+
213
+ settings.statusLine = {
214
+ type: 'command',
215
+ command: statusLinePath
216
+ }
217
+
218
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2))
219
+ } catch {
220
+ // Silently fail - status line is optional
221
+ }
222
+ }
223
+
123
224
  /**
124
225
  * Show setup results
125
226
  */
@@ -19,6 +19,7 @@ export const ProjectItemSchema = z.object({
19
19
  repoPath: z.string(),
20
20
  description: z.string().optional(),
21
21
  version: z.string().optional(),
22
+ cliVersion: z.string().optional(), // prjct-cli version used to sync
22
23
  techStack: z.array(z.string()),
23
24
  fileCount: z.number(),
24
25
  commitCount: z.number(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
5
5
  "main": "core/index.ts",
6
6
  "bin": {