prjct-cli 0.29.9 → 0.30.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,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.30.0] - 2026-01-12
4
+
5
+ ### Fix: Distribution System Overhaul (CRITICAL)
6
+
7
+ **Problem:** Users running `npm update -g prjct-cli` weren't getting updates because:
8
+ 1. Old p.md had fallback to local cache files
9
+ 2. postinstall copied 40+ files, too many failure points
10
+
11
+ **Solution:**
12
+ - **Removed fallback** in p.md - No more reading from stale local files
13
+ - **p.md now always reads from npm root** - `npm root -g` + template path
14
+ - **Simplified postinstall** - Only copies p.md (critical) + statusline (best-effort)
15
+
16
+ **How it works now:**
17
+ ```
18
+ p. sync → Claude reads ~/.claude/commands/p.md
19
+ → p.md says "run npm root -g, read from there"
20
+ → Claude reads /opt/homebrew/lib/node_modules/prjct-cli/templates/commands/sync.md
21
+ → Template always comes from installed npm package
22
+ ```
23
+
24
+ **Files:**
25
+ - `templates/commands/p.md` - Removed fallback, simplified
26
+ - `scripts/postinstall.js` - Minimal, only copies essential files
27
+
28
+ ---
29
+
3
30
  ## [0.28.0] - 2026-01-12
4
31
 
5
32
  ### Feature: Per-Project Task Filtering for Status Bar
@@ -12541,7 +12541,7 @@ var require_package = __commonJS({
12541
12541
  "package.json"(exports, module) {
12542
12542
  module.exports = {
12543
12543
  name: "prjct-cli",
12544
- version: "0.29.8",
12544
+ version: "0.29.10",
12545
12545
  description: "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
12546
12546
  main: "core/index.ts",
12547
12547
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.29.9",
3
+ "version": "0.30.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": {
@@ -1,190 +1,107 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Post-install hook for prjct-cli
4
+ * postinstall - Minimal, reliable setup
5
5
  *
6
- * Runs setup after npm install:
7
- * 1. Syncs commands to ~/.claude/commands/p/
8
- * 2. Installs global CLAUDE.md config
9
- * 3. Installs statusline
10
- * 4. Updates project versions
11
- *
12
- * IMPORTANT: This script uses COMPILED JavaScript from dist/
13
- * It does NOT require TypeScript directly.
14
- *
15
- * @version 2.0.0
6
+ * CRITICAL: Only copies p.md router to ~/.claude/commands/
7
+ * p.md reads templates from npm root, so updates work automatically.
8
+ * Statusline is best-effort (optional).
16
9
  */
17
10
 
18
- const path = require('path')
19
- const { execSync } = require('child_process')
20
11
  const fs = require('fs')
12
+ const path = require('path')
13
+ const os = require('os')
21
14
 
22
15
  const ROOT = path.resolve(__dirname, '..')
16
+ const HOME = os.homedir()
17
+ const CLAUDE_DIR = path.join(HOME, '.claude')
18
+ const COMMANDS_DIR = path.join(CLAUDE_DIR, 'commands')
23
19
 
24
- /**
25
- * Detect if this is a global npm install
26
- */
27
- function isGlobalInstall() {
28
- // Check npm config (most reliable)
29
- if (process.env.npm_config_global === 'true') {
30
- return true
31
- }
20
+ console.log('\n prjct-cli postinstall\n')
32
21
 
33
- // Check install location against known global paths
34
- const installPath = __dirname
35
- const globalPaths = [
36
- // macOS Intel
37
- '/usr/local/lib/node_modules',
38
- // macOS M1/M2 (Homebrew)
39
- '/opt/homebrew/lib/node_modules',
40
- // Linux
41
- '/usr/lib/node_modules',
42
- // Custom npm prefix
43
- path.join(process.env.HOME || '', '.npm-global', 'lib', 'node_modules'),
44
- // nvm
45
- path.join(process.env.HOME || '', '.nvm'),
46
- // Windows
47
- path.join(process.env.APPDATA || '', 'npm', 'node_modules'),
48
- // pnpm global
49
- path.join(process.env.HOME || '', '.local', 'share', 'pnpm'),
50
- // Volta
51
- path.join(process.env.HOME || '', '.volta'),
52
- ]
53
-
54
- if (globalPaths.some((p) => installPath.includes(p))) {
55
- return true
56
- }
22
+ // 1. Copy p.md router (CRITICAL - this is the only essential file)
23
+ try {
24
+ fs.mkdirSync(COMMANDS_DIR, { recursive: true })
57
25
 
58
- // Fallback: if we're in ANY node_modules that's not in cwd, assume global
59
- if (installPath.includes('node_modules') && !installPath.includes(process.cwd())) {
60
- return true
61
- }
62
-
63
- return false
64
- }
65
-
66
- /**
67
- * Check if bun is available
68
- */
69
- function hasBun() {
70
- try {
71
- execSync('bun --version', { stdio: 'ignore' })
72
- return true
73
- } catch {
74
- return false
75
- }
76
- }
77
-
78
- /**
79
- * Run setup using compiled JavaScript (for Node.js users)
80
- */
81
- async function runSetupCompiled() {
82
- const setupPath = path.join(ROOT, 'dist', 'core', 'infrastructure', 'setup.js')
83
-
84
- if (!fs.existsSync(setupPath)) {
85
- console.log(' Setup module not found. Skipping setup.')
86
- console.log(' Run `prjct setup` manually after install.')
87
- return false
88
- }
26
+ const pmdSrc = path.join(ROOT, 'templates', 'commands', 'p.md')
27
+ const pmdDest = path.join(COMMANDS_DIR, 'p.md')
89
28
 
90
- try {
91
- const setup = require(setupPath)
92
- await setup.run()
93
- return true
94
- } catch (error) {
95
- console.warn(' Setup warning:', error.message)
96
- console.log(' Run `prjct setup` manually after install.')
97
- return false
29
+ if (fs.existsSync(pmdSrc)) {
30
+ fs.copyFileSync(pmdSrc, pmdDest)
31
+ console.log(' \u2713 p.md router installed')
32
+ } else {
33
+ console.log(' ! p.md not found in package')
98
34
  }
35
+ } catch (error) {
36
+ console.log(' ! Could not install p.md:', error.message)
37
+ console.log(' Run: npx prjct-cli setup')
99
38
  }
100
39
 
101
- /**
102
- * Run setup using bun (for bun users - faster)
103
- */
104
- async function runSetupBun() {
105
- const setupPath = path.join(ROOT, 'core', 'infrastructure', 'setup.ts')
106
-
107
- try {
108
- execSync(`bun ${setupPath}`, { cwd: ROOT, stdio: 'inherit' })
109
- return true
110
- } catch (error) {
111
- // Fallback to compiled version
112
- return runSetupCompiled()
113
- }
114
- }
40
+ // 2. Statusline (best-effort, not critical)
41
+ try {
42
+ const STATUSLINE_SRC = path.join(ROOT, 'assets', 'statusline')
43
+ const STATUSLINE_DEST = path.join(HOME, '.prjct-cli', 'statusline')
44
+
45
+ if (fs.existsSync(STATUSLINE_SRC)) {
46
+ // Create dirs
47
+ fs.mkdirSync(path.join(STATUSLINE_DEST, 'lib'), { recursive: true })
48
+ fs.mkdirSync(path.join(STATUSLINE_DEST, 'components'), { recursive: true })
49
+ fs.mkdirSync(path.join(STATUSLINE_DEST, 'themes'), { recursive: true })
50
+
51
+ // Copy main script
52
+ const mainScript = path.join(STATUSLINE_SRC, 'statusline.sh')
53
+ if (fs.existsSync(mainScript)) {
54
+ fs.copyFileSync(mainScript, path.join(STATUSLINE_DEST, 'statusline.sh'))
55
+ fs.chmodSync(path.join(STATUSLINE_DEST, 'statusline.sh'), 0o755)
56
+ }
115
57
 
116
- /**
117
- * Update statusline version in existing scripts
118
- */
119
- function updateStatusLineVersion() {
120
- try {
121
- const homeDir = process.env.HOME || require('os').homedir()
122
- const packageJson = require(path.join(ROOT, 'package.json'))
123
- const version = packageJson.version
124
-
125
- const statusLinePaths = [
126
- path.join(homeDir, '.prjct-cli', 'statusline', 'statusline.sh'),
127
- path.join(homeDir, '.claude', 'prjct-statusline.sh'),
128
- ]
129
-
130
- for (const statusLinePath of statusLinePaths) {
131
- if (fs.existsSync(statusLinePath)) {
132
- const stats = fs.lstatSync(statusLinePath)
133
- const actualPath = stats.isSymbolicLink()
134
- ? fs.readlinkSync(statusLinePath)
135
- : statusLinePath
136
-
137
- if (fs.existsSync(actualPath)) {
138
- let content = fs.readFileSync(actualPath, 'utf8')
139
- if (content.includes('CLI_VERSION=')) {
140
- const updated = content.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${version}"`)
141
- fs.writeFileSync(actualPath, updated, { mode: 0o755 })
142
- return true
143
- }
58
+ // Copy subdirs
59
+ for (const subdir of ['lib', 'components', 'themes']) {
60
+ const srcDir = path.join(STATUSLINE_SRC, subdir)
61
+ if (fs.existsSync(srcDir)) {
62
+ for (const f of fs.readdirSync(srcDir)) {
63
+ fs.copyFileSync(
64
+ path.join(srcDir, f),
65
+ path.join(STATUSLINE_DEST, subdir, f)
66
+ )
144
67
  }
145
68
  }
146
69
  }
147
- return false
148
- } catch {
149
- return false
150
- }
151
- }
152
70
 
153
- /**
154
- * Main
155
- */
156
- async function main() {
157
- // ALWAYS run setup - don't try to detect global vs local
158
- // Worst case: setup runs unnecessarily on local dev installs (harmless)
159
- // Best case: setup actually works for all users
160
-
161
- console.log('')
162
- console.log(' prjct-cli postinstall')
163
- console.log('')
164
-
165
- // Update statusline version first (fast, always works)
166
- if (updateStatusLineVersion()) {
167
- console.log(' ✓ Statusline version updated')
168
- }
71
+ // Default config (only if not exists)
72
+ const configSrc = path.join(STATUSLINE_SRC, 'default-config.json')
73
+ const configDest = path.join(STATUSLINE_DEST, 'config.json')
74
+ if (fs.existsSync(configSrc) && !fs.existsSync(configDest)) {
75
+ fs.copyFileSync(configSrc, configDest)
76
+ }
169
77
 
170
- // Run full setup
171
- let success = false
172
- if (hasBun()) {
173
- success = await runSetupBun()
174
- } else {
175
- success = await runSetupCompiled()
176
- }
78
+ // Symlink in ~/.claude
79
+ const symlinkPath = path.join(CLAUDE_DIR, 'prjct-statusline.sh')
80
+ const targetPath = path.join(STATUSLINE_DEST, 'statusline.sh')
81
+ try {
82
+ if (fs.existsSync(symlinkPath)) fs.unlinkSync(symlinkPath)
83
+ if (fs.existsSync(targetPath)) fs.symlinkSync(targetPath, symlinkPath)
84
+ } catch {
85
+ // Symlink failed, copy instead
86
+ if (fs.existsSync(targetPath)) {
87
+ fs.copyFileSync(targetPath, symlinkPath)
88
+ fs.chmodSync(symlinkPath, 0o755)
89
+ }
90
+ }
177
91
 
178
- if (!success) {
179
- console.log(' ⚠ Setup incomplete. Run: npx prjct-cli setup')
180
- }
92
+ // Update settings.json
93
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json')
94
+ let settings = {}
95
+ if (fs.existsSync(settingsPath)) {
96
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')) } catch {}
97
+ }
98
+ settings.statusLine = { type: 'command', command: symlinkPath }
99
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2))
181
100
 
182
- console.log('')
101
+ console.log(' \u2713 statusline installed')
102
+ }
103
+ } catch {
104
+ // Statusline is optional, don't fail
183
105
  }
184
106
 
185
- main().catch((error) => {
186
- // Log error but don't fail npm install
187
- console.error(' postinstall error:', error.message)
188
- console.log(' Run manually: npx prjct-cli setup')
189
- process.exit(0)
190
- })
107
+ console.log('\n')
@@ -5,41 +5,34 @@ allowed-tools: [Read, Write, Edit, Bash, Glob, Grep, Task, AskUserQuestion, Todo
5
5
 
6
6
  # prjct Command Router
7
7
 
8
- Route `p. <command>` to the appropriate prjct template.
8
+ **ARGUMENTS**: $ARGUMENTS
9
9
 
10
10
  ## Instructions
11
11
 
12
- **ARGUMENTS**: $ARGUMENTS
13
-
14
12
  1. Parse ARGUMENTS: first word = `command`, rest = `commandArgs`
15
- 2. Find npm global root by running:
13
+ 2. Get npm global root:
16
14
  ```bash
17
15
  npm root -g
18
16
  ```
19
- This returns a path like `/opt/homebrew/lib/node_modules` or `/usr/local/lib/node_modules`
20
- 3. Read template from the npm package location:
17
+ 3. Read template from npm package:
21
18
  ```
22
19
  {npmRoot}/prjct-cli/templates/commands/{command}.md
23
20
  ```
24
- 4. Execute that template with `commandArgs` as input
21
+ 4. Execute template with `commandArgs` as input
25
22
 
26
23
  ## Example
27
24
 
28
- If ARGUMENTS = "task fix the login bug":
25
+ ARGUMENTS = "task fix the login bug"
29
26
  - command = "task"
30
27
  - commandArgs = "fix the login bug"
31
- - Run: `npm root -g` → `/opt/homebrew/lib/node_modules`
28
+ - npm root -g → `/opt/homebrew/lib/node_modules`
32
29
  - Read: `/opt/homebrew/lib/node_modules/prjct-cli/templates/commands/task.md`
33
30
  - Execute with: "fix the login bug"
34
31
 
35
- ## Fallback
36
-
37
- If npm root fails, read from local cache: `~/.claude/commands/p/{command}.md`
38
-
39
32
  ## Available Commands
40
33
 
41
34
  `task` `done` `ship` `sync` `init` `idea` `dash` `next` `pause` `resume` `bug` `linear` `feature` `prd` `plan` `review` `merge` `git` `test` `cleanup` `design` `analyze` `history` `enrich` `update`
42
35
 
43
36
  ## Action
44
37
 
45
- NOW find npm root and read the command template.
38
+ NOW run `npm root -g` and read the command template.