prjct-cli 0.4.5 → 0.4.6

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
@@ -15,7 +15,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
15
  - Cross-platform file operations
16
16
  - Windows Terminal integration
17
17
 
18
- ## [0.4.5] - 2025-10-02
18
+ ## [0.4.6] - 2025-10-02
19
+
20
+ ### Added
21
+ - **`prjct start` Command** - First-time setup with interactive editor selection
22
+ - Beautiful ASCII art welcome message
23
+ - Auto-detects installed AI editors (Claude Code, Cursor, Windsurf)
24
+ - Interactive prompt to choose which editors to install commands to
25
+ - Replaces confusing `prjct install` command with clearer naming
26
+ - Only runs once (blocks if already configured, suggests `prjct setup` to reconfigure)
27
+
28
+ - **Auto-Initialization** - Commands auto-run `prjct init` when needed
29
+ - All core commands (now, done, ship, next, idea, recap, stuck, context) check initialization
30
+ - Shows warning and runs init automatically if project not configured
31
+ - Zero friction - users don't need to remember to run init first
32
+ - Seamless workflow: `cd project/ && prjct now "task"` just works
33
+
34
+ ### Changed
35
+ - **Simplified Installation Flow**
36
+ - `npm install -g prjct-cli` → Shows welcome message, tells user to run `prjct start`
37
+ - `prjct start` → Interactive setup (first-time only)
38
+ - `prjct init` → Initialize project (links to global data)
39
+ - `prjct setup` → Reconfigure editors (replaces old `prjct install`)
40
+ - `npm update -g prjct-cli` → Auto-updates commands in tracked editors
41
+
42
+ - **Post-Install Behavior**
43
+ - Removed auto-installation on npm install (was non-interactive and confusing)
44
+ - First install shows: `Run: prjct start to get started`
45
+ - Updates auto-update commands in previously selected editors
46
+ - Cleaner, more predictable behavior
19
47
 
20
48
  ### Fixed
21
49
  - **Critical Bug Fixes** - All commands now enforce global architecture correctly
@@ -28,10 +56,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
28
56
  - **Added 'Apps' directory** to migration scanner for better project detection
29
57
 
30
58
  ### Technical Details
59
+ - **New Commands**:
60
+ - `start()` - First-time setup with ASCII art and interactive editor selection
61
+ - `setup()` - Renamed from `install()` for clarity
62
+ - `ensureProjectInit()` - Helper function for auto-initialization
31
63
  - **Global Architecture**: All commands now use `pathManager.getGlobalProjectPath(projectId)`
32
64
  - design(), cleanup(), getDaysSinceLastShip() fully migrated
33
65
  - Prevents LOCAL .prjct/ creation
34
66
  - Requires project initialization before command execution
67
+ - **Auto-Init Integration**: now(), done(), ship(), next(), idea(), recap(), stuck(), context() all auto-initialize
35
68
  - **Migration Enhancement**: Added ~/Apps to common directories scan
36
69
  - **Post-Install Fix**: currentVersion variable properly declared at function start
37
70
 
package/bin/prjct CHANGED
@@ -8,6 +8,9 @@ async function main() {
8
8
 
9
9
  let result;
10
10
  switch(command) {
11
+ case 'start':
12
+ result = await commands.start();
13
+ break;
11
14
  case 'init':
12
15
  result = await commands.init();
13
16
  break;
@@ -107,23 +110,23 @@ async function main() {
107
110
 
108
111
  result = await commands.migrateAll(migrateOptions);
109
112
  break;
110
- case 'install':
111
- const installOptions = {};
112
- const installArgs = args.slice(1);
113
-
114
- for (let i = 0; i < installArgs.length; i++) {
115
- if (installArgs[i] === '--force') {
116
- installOptions.force = true;
117
- } else if (installArgs[i] === '--editor') {
118
- installOptions.editor = installArgs[++i];
119
- } else if (installArgs[i] === '--create-templates') {
120
- installOptions.createTemplates = true;
121
- } else if (installArgs[i] === '--no-interactive') {
122
- installOptions.interactive = false;
113
+ case 'setup':
114
+ const setupOptions = {};
115
+ const setupArgs = args.slice(1);
116
+
117
+ for (let i = 0; i < setupArgs.length; i++) {
118
+ if (setupArgs[i] === '--force') {
119
+ setupOptions.force = true;
120
+ } else if (setupArgs[i] === '--editor') {
121
+ setupOptions.editor = setupArgs[++i];
122
+ } else if (setupArgs[i] === '--create-templates') {
123
+ setupOptions.createTemplates = true;
124
+ } else if (setupArgs[i] === '--no-interactive') {
125
+ setupOptions.interactive = false;
123
126
  }
124
127
  }
125
128
 
126
- result = await commands.install(installOptions);
129
+ result = await commands.setup(setupOptions);
127
130
  break;
128
131
  case 'analyze':
129
132
  const analyzeOptions = {};
@@ -155,6 +158,10 @@ async function main() {
155
158
  result = {
156
159
  success: true,
157
160
  message: `Available commands:
161
+ Setup:
162
+ start First-time setup (install commands to editors)
163
+ setup Reconfigure editor installations
164
+
158
165
  Core workflow:
159
166
  init Initialize prjct in current project
160
167
  now [task] Set or show current task
@@ -173,9 +180,8 @@ async function main() {
173
180
  design [target] Design system/architecture
174
181
  analyze Analyze codebase and sync state
175
182
  migrate-all Migrate all legacy projects
176
- install Install commands to AI editors
177
183
 
178
- Install options:
184
+ Setup options:
179
185
  --force Force update existing commands
180
186
  --editor <name> Install to specific editor (claude|cursor|codex|windsurf)
181
187
  --no-interactive Skip interactive selection, install to all
@@ -188,6 +194,10 @@ async function main() {
188
194
  message: `Unknown command: ${command}
189
195
 
190
196
  Available commands:
197
+ Setup:
198
+ start First-time setup (install commands to editors)
199
+ setup Reconfigure editor installations
200
+
191
201
  Core workflow:
192
202
  init Initialize prjct in current project
193
203
  now [task] Set or show current task
@@ -206,9 +216,8 @@ Available commands:
206
216
  design [target] Design system/architecture
207
217
  analyze Analyze codebase and sync state
208
218
  migrate-all Migrate all legacy projects
209
- install Install commands to AI editors
210
219
 
211
- Install options:
220
+ Setup options:
212
221
  --force Force update existing commands
213
222
  --editor <name> Install to specific editor (claude|cursor|codex|windsurf)
214
223
  --no-interactive Skip interactive selection, install to all
package/core/commands.js CHANGED
@@ -249,6 +249,31 @@ class PrjctCommands {
249
249
  return this.currentAuthor
250
250
  }
251
251
 
252
+ /**
253
+ * Auto-initialize project if not configured
254
+ * Shows warning and runs init automatically
255
+ *
256
+ * @param {string} projectPath - Local project path
257
+ * @returns {Promise<{success: boolean, message?: string}>} Success or init result
258
+ */
259
+ async ensureProjectInit(projectPath) {
260
+ if (await configManager.isConfigured(projectPath)) {
261
+ return { success: true }
262
+ }
263
+
264
+ const chalk = require('chalk')
265
+ console.log(chalk.yellow('⚠️ Project not initialized'))
266
+ console.log(chalk.cyan('🔧 Running prjct init...\n'))
267
+
268
+ const initResult = await this.init(projectPath)
269
+ if (!initResult.success) {
270
+ return initResult
271
+ }
272
+
273
+ console.log(chalk.green('✅ Project initialized!\n'))
274
+ return { success: true }
275
+ }
276
+
252
277
  /**
253
278
  * Get the global project path for a project
254
279
  * Ensures migration if needed
@@ -413,6 +438,12 @@ class PrjctCommands {
413
438
  await this.initializeAgent()
414
439
  await this.ensureAuthor()
415
440
 
441
+ // Auto-init if not configured
442
+ const initCheck = await this.ensureProjectInit(projectPath)
443
+ if (!initCheck.success) {
444
+ return initCheck
445
+ }
446
+
416
447
  const nowFile = await this.getFilePath(projectPath, 'core', 'now.md')
417
448
 
418
449
  if (!task) {
@@ -494,6 +525,13 @@ class PrjctCommands {
494
525
  async done(projectPath = process.cwd()) {
495
526
  try {
496
527
  await this.initializeAgent()
528
+
529
+ // Auto-init if not configured
530
+ const initCheck = await this.ensureProjectInit(projectPath)
531
+ if (!initCheck.success) {
532
+ return initCheck
533
+ }
534
+
497
535
  const nowFile = await this.getFilePath(projectPath, 'core', 'now.md')
498
536
  const nextFile = await this.getFilePath(projectPath, 'core', 'next.md')
499
537
 
@@ -655,6 +693,12 @@ ${nextStep.agent}
655
693
  try {
656
694
  await this.initializeAgent()
657
695
 
696
+ // Auto-init if not configured
697
+ const initCheck = await this.ensureProjectInit(projectPath)
698
+ if (!initCheck.success) {
699
+ return initCheck
700
+ }
701
+
658
702
  if (!feature) {
659
703
  return {
660
704
  success: false,
@@ -764,6 +808,13 @@ ${nextStep.agent}
764
808
  async next(projectPath = process.cwd()) {
765
809
  try {
766
810
  await this.initializeAgent()
811
+
812
+ // Auto-init if not configured
813
+ const initCheck = await this.ensureProjectInit(projectPath)
814
+ if (!initCheck.success) {
815
+ return initCheck
816
+ }
817
+
767
818
  const nextFile = await this.getFilePath(projectPath, 'core', 'next.md')
768
819
  const content = await this.agent.readFile(nextFile)
769
820
 
@@ -806,6 +857,12 @@ ${nextStep.agent}
806
857
  try {
807
858
  await this.initializeAgent()
808
859
 
860
+ // Auto-init if not configured
861
+ const initCheck = await this.ensureProjectInit(projectPath)
862
+ if (!initCheck.success) {
863
+ return initCheck
864
+ }
865
+
809
866
  if (!text) {
810
867
  return {
811
868
  success: false,
@@ -862,6 +919,12 @@ ${nextStep.agent}
862
919
  try {
863
920
  await this.initializeAgent()
864
921
 
922
+ // Auto-init if not configured
923
+ const initCheck = await this.ensureProjectInit(projectPath)
924
+ if (!initCheck.success) {
925
+ return initCheck
926
+ }
927
+
865
928
  const nowFilePath = await this.getFilePath(projectPath, 'core', 'now.md')
866
929
  const nextFilePath = await this.getFilePath(projectPath, 'core', 'next.md')
867
930
  const ideasFilePath = await this.getFilePath(projectPath, 'planning', 'ideas.md')
@@ -1100,6 +1163,12 @@ ${nextStep.agent}
1100
1163
  try {
1101
1164
  await this.initializeAgent()
1102
1165
 
1166
+ // Auto-init if not configured
1167
+ const initCheck = await this.ensureProjectInit(projectPath)
1168
+ if (!initCheck.success) {
1169
+ return initCheck
1170
+ }
1171
+
1103
1172
  if (!issue) {
1104
1173
  return {
1105
1174
  success: false,
@@ -1394,6 +1463,12 @@ ${diagram}
1394
1463
  try {
1395
1464
  await this.initializeAgent()
1396
1465
 
1466
+ // Auto-init if not configured
1467
+ const initCheck = await this.ensureProjectInit(projectPath)
1468
+ if (!initCheck.success) {
1469
+ return initCheck
1470
+ }
1471
+
1397
1472
  const projectInfo = await this.detectProjectType(projectPath)
1398
1473
 
1399
1474
  const nowFilePath = await this.getFilePath(projectPath, 'core', 'now.md')
@@ -1866,12 +1941,109 @@ ${diagram}
1866
1941
  }
1867
1942
 
1868
1943
  /**
1869
- * Install commands to AI editors
1944
+ * First-time setup - Install commands to AI editors with ASCII art welcome
1945
+ *
1946
+ * @returns {Promise<Object>} Result object with success flag and message
1947
+ */
1948
+ async start() {
1949
+ try {
1950
+ await this.initializeAgent()
1951
+
1952
+ // Check if already configured
1953
+ const editorsConfig = require('./editors-config')
1954
+ const configExists = await editorsConfig.configExists()
1955
+
1956
+ if (configExists) {
1957
+ return {
1958
+ success: false,
1959
+ message: this.agent.formatResponse(
1960
+ 'prjct is already set up!\n\nTo reconfigure editors: prjct setup',
1961
+ 'warning'
1962
+ ),
1963
+ }
1964
+ }
1965
+
1966
+ // ASCII Art
1967
+ const chalk = require('chalk')
1968
+ console.log(
1969
+ chalk.cyan(`
1970
+ ___ ____ _ ____ _____
1971
+ / _ \\| _ \\ | / ___|_ _|
1972
+ | |_| | |_) |_| | | | |
1973
+ | __/| _ <| | | |___ | |
1974
+ | | | |_) | | |\\____| | |
1975
+ |_| |____/|_| | |_|
1976
+ `)
1977
+ )
1978
+
1979
+ console.log(chalk.cyan('\n📦 Welcome to prjct-cli!\n'))
1980
+
1981
+ // Detect editors
1982
+ const commandInstaller = require('./command-installer')
1983
+ const detection = await commandInstaller.detectEditors()
1984
+ const detectedEditors = Object.entries(detection).filter(([_, info]) => info.detected)
1985
+
1986
+ if (detectedEditors.length === 0) {
1987
+ return {
1988
+ success: false,
1989
+ message: this.agent.formatResponse(
1990
+ 'No AI editors detected.\n\nSupported: Claude Code, Cursor, Windsurf',
1991
+ 'error'
1992
+ ),
1993
+ }
1994
+ }
1995
+
1996
+ console.log(chalk.cyan('🔍 Detected AI editors:'))
1997
+ detectedEditors.forEach(([key, info]) => {
1998
+ console.log(chalk.green(` [✓] ${info.name} (${info.path})`))
1999
+ })
2000
+ console.log('')
2001
+
2002
+ // Interactive selection
2003
+ const installResult = await commandInstaller.interactiveInstall(false)
2004
+
2005
+ if (!installResult.success) {
2006
+ return {
2007
+ success: false,
2008
+ message: this.agent.formatResponse(installResult.message || 'Setup failed', 'error'),
2009
+ }
2010
+ }
2011
+
2012
+ // Install Context7 MCP
2013
+ const mcpResult = await commandInstaller.installContext7MCP()
2014
+
2015
+ // Success message
2016
+ let message = `✅ Commands installed in: ${installResult.editors.join(', ')}\n`
2017
+
2018
+ if (mcpResult.success && mcpResult.editors.length > 0) {
2019
+ message += `\n🔌 Context7 MCP enabled in: ${mcpResult.editors.join(', ')}`
2020
+ }
2021
+
2022
+ message += '\n\n✨ prjct is ready to use!'
2023
+ message += '\n\nNext steps:'
2024
+ message += '\n cd your-project/'
2025
+ message += '\n prjct init'
2026
+
2027
+ return {
2028
+ success: true,
2029
+ message: this.agent.formatResponse(message, 'celebrate'),
2030
+ }
2031
+ } catch (error) {
2032
+ await this.initializeAgent()
2033
+ return {
2034
+ success: false,
2035
+ message: this.agent.formatResponse(`Setup failed: ${error.message}`, 'error'),
2036
+ }
2037
+ }
2038
+ }
2039
+
2040
+ /**
2041
+ * Setup/reconfigure commands in AI editors
1870
2042
  *
1871
2043
  * @param {Object} [options={}] - Installation options
1872
2044
  * @returns {Promise<Object>} Result object with success flag and message
1873
2045
  */
1874
- async install(options = {}) {
2046
+ async setup(options = {}) {
1875
2047
  try {
1876
2048
  await this.initializeAgent()
1877
2049
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "AI-integrated project management for indie hackers - works with Claude Code, Cursor, and Warp",
5
5
  "main": "core/index.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@ const { execSync } = require('child_process')
21
21
 
22
22
  async function main() {
23
23
  try {
24
- // Get current package version (needed by multiple code paths)
24
+ // Get current package version
25
25
  const packageJson = require('../package.json')
26
26
  const currentVersion = packageJson.version
27
27
 
@@ -41,41 +41,9 @@ async function main() {
41
41
  const configExists = await editorsConfig.configExists()
42
42
 
43
43
  if (!configExists) {
44
- // First-time install - auto-detect and install to all editors
45
- console.log(chalk.cyan('\n🔍 First-time installation detected...\n'))
46
-
47
- // Load command installer
48
- const commandInstaller = require('../core/command-installer')
49
-
50
- // Detect available editors
51
- const detected = await commandInstaller.detectEditors()
52
- const detectedEditors = Object.entries(detected)
53
- .filter(([_, info]) => info.detected)
54
- .map(([key, _]) => key)
55
-
56
- if (detectedEditors.length === 0) {
57
- // No editors detected, user will install manually later
58
- console.log(chalk.yellow('ℹ️ No AI editors detected'))
59
- console.log(chalk.gray(' Run `prjct install` when you set up Claude Code, Cursor, or Windsurf\n'))
60
- return
61
- }
62
-
63
- console.log(chalk.cyan(`📦 Installing commands to: ${detectedEditors.map(k => commandInstaller.editors[k]?.name || k).join(', ')}\n`))
64
-
65
- // Install to all detected editors
66
- const results = await commandInstaller.installToAll(false)
67
-
68
- if (results.success) {
69
- console.log(chalk.green(`✅ Commands installed in: ${results.editors.join(', ')}`))
70
- console.log(chalk.gray(` Commands installed: ${results.totalInstalled}`))
71
- console.log(chalk.cyan(`\n✨ prjct-cli ${currentVersion} is ready!\n`))
72
- } else {
73
- console.log(chalk.yellow('⚠️ Some editors could not be configured'))
74
- if (process.env.DEBUG) {
75
- console.log(chalk.gray(` Error: ${results.message || 'Unknown error'}`))
76
- }
77
- }
78
-
44
+ // First-time install - show welcome message
45
+ console.log(chalk.cyan('\n prjct-cli installed successfully!\n'))
46
+ console.log(chalk.gray('Run: ') + chalk.cyan('prjct start') + chalk.gray(' to get started\n'))
79
47
  return
80
48
  }
81
49
 
@@ -87,9 +55,8 @@ async function main() {
87
55
  return
88
56
  }
89
57
 
90
- // Get tracked editors and paths
58
+ // Get tracked editors
91
59
  const trackedEditors = await editorsConfig.getTrackedEditors()
92
- const editorPaths = await editorsConfig.getEditorPaths()
93
60
 
94
61
  if (trackedEditors.length === 0) {
95
62
  // No editors tracked yet