prjct-cli 0.29.4 → 0.29.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.
@@ -12,6 +12,7 @@
12
12
  import fs from 'fs/promises'
13
13
  import path from 'path'
14
14
  import os from 'os'
15
+ import { getPackageRoot } from '../utils/version'
15
16
  import type {
16
17
  InstallResult,
17
18
  UninstallResult,
@@ -30,7 +31,7 @@ import type {
30
31
  export async function installDocs(): Promise<{ success: boolean; error?: string }> {
31
32
  try {
32
33
  const docsDir = path.join(os.homedir(), '.prjct-cli', 'docs')
33
- const templateDocsDir = path.join(__dirname, '../../templates/global/docs')
34
+ const templateDocsDir = path.join(getPackageRoot(), 'templates/global/docs')
34
35
 
35
36
  // Ensure docs directory exists
36
37
  await fs.mkdir(docsDir, { recursive: true })
@@ -77,7 +78,7 @@ export async function installGlobalConfig(
77
78
  await fs.mkdir(claudeDir, { recursive: true })
78
79
 
79
80
  const globalConfigPath = path.join(claudeDir, 'CLAUDE.md')
80
- const templatePath = path.join(__dirname, '../../templates/global/CLAUDE.md')
81
+ const templatePath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
81
82
 
82
83
  // Read template content
83
84
  const templateContent = await fs.readFile(templatePath, 'utf-8')
@@ -168,7 +169,8 @@ export class CommandInstaller {
168
169
  // We use the p.md router in commands/ root instead
169
170
  this.claudeCommandsPath = path.join(this.homeDir, '.claude', 'commands', 'p')
170
171
  this.claudeConfigPath = path.join(this.homeDir, '.claude')
171
- this.templatesDir = path.join(__dirname, '..', '..', 'templates', 'commands')
172
+ // Use getPackageRoot() to find templates - works from both source and compiled
173
+ this.templatesDir = path.join(getPackageRoot(), 'templates', 'commands')
172
174
  }
173
175
 
174
176
  /**
@@ -18,7 +18,7 @@ import path from 'path'
18
18
  import os from 'os'
19
19
  import installer from './command-installer'
20
20
  import editorsConfig from './editors-config'
21
- import { VERSION } from '../utils/version'
21
+ import { VERSION, getPackageRoot } from '../utils/version'
22
22
 
23
23
  // Colors
24
24
  const GREEN = '\x1b[32m'
@@ -215,7 +215,7 @@ async function installStatusLine(): Promise<void> {
215
215
  const prjctConfigPath = path.join(prjctStatusLineDir, 'config.json')
216
216
 
217
217
  // Source assets (from the package)
218
- const assetsDir = path.join(__dirname, '..', '..', 'assets', 'statusline')
218
+ const assetsDir = path.join(getPackageRoot(), 'assets', 'statusline')
219
219
  const sourceScript = path.join(assetsDir, 'statusline.sh')
220
220
  const sourceThemeDir = path.join(assetsDir, 'themes')
221
221
  const sourceLibDir = path.join(assetsDir, 'lib')
@@ -17,6 +17,40 @@ interface PackageJson {
17
17
 
18
18
  let cachedVersion: string | null = null
19
19
  let cachedPackageJson: PackageJson | null = null
20
+ let cachedPackageRoot: string | null = null
21
+
22
+ /**
23
+ * Find the package root by searching up from __dirname for package.json
24
+ * Works whether running from source (core/utils/) or compiled (dist/core/utils/)
25
+ */
26
+ export function getPackageRoot(): string {
27
+ if (cachedPackageRoot) {
28
+ return cachedPackageRoot
29
+ }
30
+
31
+ let currentDir = __dirname
32
+
33
+ // Search up to 5 levels up for package.json with name "prjct-cli"
34
+ for (let i = 0; i < 5; i++) {
35
+ const packageJsonPath = path.join(currentDir, 'package.json')
36
+ if (fs.existsSync(packageJsonPath)) {
37
+ try {
38
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
39
+ if (pkg.name === 'prjct-cli') {
40
+ cachedPackageRoot = currentDir
41
+ return currentDir
42
+ }
43
+ } catch {
44
+ // Continue searching
45
+ }
46
+ }
47
+ currentDir = path.dirname(currentDir)
48
+ }
49
+
50
+ // Fallback: assume 3 levels up from __dirname (works for dist/core/utils/)
51
+ cachedPackageRoot = path.join(__dirname, '..', '..', '..')
52
+ return cachedPackageRoot
53
+ }
20
54
 
21
55
  /**
22
56
  * Get the current application version from package.json
@@ -27,7 +61,7 @@ export function getVersion(): string {
27
61
  }
28
62
 
29
63
  try {
30
- const packageJsonPath = path.join(__dirname, '..', '..', 'package.json')
64
+ const packageJsonPath = path.join(getPackageRoot(), 'package.json')
31
65
  const packageJson: PackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
32
66
  cachedVersion = packageJson.version
33
67
  cachedPackageJson = packageJson
@@ -87,13 +121,16 @@ export function needsMigration(fromVersion: string, toVersion: string | null = n
87
121
  }
88
122
 
89
123
  export const VERSION = getVersion()
124
+ export const PACKAGE_ROOT = getPackageRoot()
90
125
 
91
126
  // Default export for CommonJS compatibility
92
127
  export default {
93
128
  getVersion,
129
+ getPackageRoot,
94
130
  getPackageInfo,
95
131
  compareVersions,
96
132
  isCompatible,
97
133
  needsMigration,
98
- VERSION
134
+ VERSION,
135
+ PACKAGE_ROOT
99
136
  }
@@ -45,12 +45,34 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
45
45
  // core/utils/version.ts
46
46
  import fs from "fs";
47
47
  import path from "path";
48
+ function getPackageRoot() {
49
+ if (cachedPackageRoot) {
50
+ return cachedPackageRoot;
51
+ }
52
+ let currentDir = __dirname;
53
+ for (let i = 0; i < 5; i++) {
54
+ const packageJsonPath = path.join(currentDir, "package.json");
55
+ if (fs.existsSync(packageJsonPath)) {
56
+ try {
57
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
58
+ if (pkg.name === "prjct-cli") {
59
+ cachedPackageRoot = currentDir;
60
+ return currentDir;
61
+ }
62
+ } catch {
63
+ }
64
+ }
65
+ currentDir = path.dirname(currentDir);
66
+ }
67
+ cachedPackageRoot = path.join(__dirname, "..", "..", "..");
68
+ return cachedPackageRoot;
69
+ }
48
70
  function getVersion() {
49
71
  if (cachedVersion) {
50
72
  return cachedVersion;
51
73
  }
52
74
  try {
53
- const packageJsonPath = path.join(__dirname, "..", "..", "package.json");
75
+ const packageJsonPath = path.join(getPackageRoot(), "package.json");
54
76
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
55
77
  cachedVersion = packageJson.version;
56
78
  cachedPackageJson = packageJson;
@@ -60,14 +82,17 @@ function getVersion() {
60
82
  return "0.0.0";
61
83
  }
62
84
  }
63
- var cachedVersion, cachedPackageJson, VERSION;
85
+ var cachedVersion, cachedPackageJson, cachedPackageRoot, VERSION, PACKAGE_ROOT;
64
86
  var init_version = __esm({
65
87
  "core/utils/version.ts"() {
66
88
  "use strict";
67
89
  cachedVersion = null;
68
90
  cachedPackageJson = null;
91
+ cachedPackageRoot = null;
92
+ __name(getPackageRoot, "getPackageRoot");
69
93
  __name(getVersion, "getVersion");
70
94
  VERSION = getVersion();
95
+ PACKAGE_ROOT = getPackageRoot();
71
96
  }
72
97
  });
73
98
 
@@ -1409,7 +1434,7 @@ import os4 from "os";
1409
1434
  async function installDocs() {
1410
1435
  try {
1411
1436
  const docsDir = path8.join(os4.homedir(), ".prjct-cli", "docs");
1412
- const templateDocsDir = path8.join(__dirname, "../../templates/global/docs");
1437
+ const templateDocsDir = path8.join(getPackageRoot(), "templates/global/docs");
1413
1438
  await fs8.mkdir(docsDir, { recursive: true });
1414
1439
  const docFiles = await fs8.readdir(templateDocsDir);
1415
1440
  for (const file of docFiles) {
@@ -1438,7 +1463,7 @@ async function installGlobalConfig(claudeConfigPath, detectClaude) {
1438
1463
  const claudeDir = path8.join(os4.homedir(), ".claude");
1439
1464
  await fs8.mkdir(claudeDir, { recursive: true });
1440
1465
  const globalConfigPath = path8.join(claudeDir, "CLAUDE.md");
1441
- const templatePath = path8.join(__dirname, "../../templates/global/CLAUDE.md");
1466
+ const templatePath = path8.join(getPackageRoot(), "templates/global/CLAUDE.md");
1442
1467
  const templateContent = await fs8.readFile(templatePath, "utf-8");
1443
1468
  let existingContent = "";
1444
1469
  let fileExists2 = false;
@@ -1497,6 +1522,7 @@ var CommandInstaller, commandInstaller, command_installer_default;
1497
1522
  var init_command_installer = __esm({
1498
1523
  "core/infrastructure/command-installer.ts"() {
1499
1524
  "use strict";
1525
+ init_version();
1500
1526
  __name(installDocs, "installDocs");
1501
1527
  __name(installGlobalConfig, "installGlobalConfig");
1502
1528
  CommandInstaller = class {
@@ -1511,7 +1537,7 @@ var init_command_installer = __esm({
1511
1537
  this.homeDir = os4.homedir();
1512
1538
  this.claudeCommandsPath = path8.join(this.homeDir, ".claude", "commands", "p");
1513
1539
  this.claudeConfigPath = path8.join(this.homeDir, ".claude");
1514
- this.templatesDir = path8.join(__dirname, "..", "..", "templates", "commands");
1540
+ this.templatesDir = path8.join(getPackageRoot(), "templates", "commands");
1515
1541
  }
1516
1542
  /**
1517
1543
  * Detect if Claude is installed
@@ -1909,7 +1935,7 @@ async function installStatusLine() {
1909
1935
  const prjctLibDir = path9.join(prjctStatusLineDir, "lib");
1910
1936
  const prjctComponentsDir = path9.join(prjctStatusLineDir, "components");
1911
1937
  const prjctConfigPath = path9.join(prjctStatusLineDir, "config.json");
1912
- const assetsDir = path9.join(__dirname, "..", "..", "assets", "statusline");
1938
+ const assetsDir = path9.join(getPackageRoot(), "assets", "statusline");
1913
1939
  const sourceScript = path9.join(assetsDir, "statusline.sh");
1914
1940
  const sourceThemeDir = path9.join(assetsDir, "themes");
1915
1941
  const sourceLibDir = path9.join(assetsDir, "lib");
@@ -12508,7 +12534,7 @@ var require_package = __commonJS({
12508
12534
  "package.json"(exports, module) {
12509
12535
  module.exports = {
12510
12536
  name: "prjct-cli",
12511
- version: "0.29.3",
12537
+ version: "0.29.5",
12512
12538
  description: "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
12513
12539
  main: "core/index.ts",
12514
12540
  bin: {
@@ -38,18 +38,68 @@ __export(command_installer_exports, {
38
38
  });
39
39
  module.exports = __toCommonJS(command_installer_exports);
40
40
  var import_promises = __toESM(require("fs/promises"));
41
- var import_path = __toESM(require("path"));
41
+ var import_path2 = __toESM(require("path"));
42
42
  var import_os = __toESM(require("os"));
43
+
44
+ // core/utils/version.ts
45
+ var import_fs = __toESM(require("fs"));
46
+ var import_path = __toESM(require("path"));
47
+ var cachedVersion = null;
48
+ var cachedPackageJson = null;
49
+ var cachedPackageRoot = null;
50
+ function getPackageRoot() {
51
+ if (cachedPackageRoot) {
52
+ return cachedPackageRoot;
53
+ }
54
+ let currentDir = __dirname;
55
+ for (let i = 0; i < 5; i++) {
56
+ const packageJsonPath = import_path.default.join(currentDir, "package.json");
57
+ if (import_fs.default.existsSync(packageJsonPath)) {
58
+ try {
59
+ const pkg = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
60
+ if (pkg.name === "prjct-cli") {
61
+ cachedPackageRoot = currentDir;
62
+ return currentDir;
63
+ }
64
+ } catch {
65
+ }
66
+ }
67
+ currentDir = import_path.default.dirname(currentDir);
68
+ }
69
+ cachedPackageRoot = import_path.default.join(__dirname, "..", "..", "..");
70
+ return cachedPackageRoot;
71
+ }
72
+ __name(getPackageRoot, "getPackageRoot");
73
+ function getVersion() {
74
+ if (cachedVersion) {
75
+ return cachedVersion;
76
+ }
77
+ try {
78
+ const packageJsonPath = import_path.default.join(getPackageRoot(), "package.json");
79
+ const packageJson = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
80
+ cachedVersion = packageJson.version;
81
+ cachedPackageJson = packageJson;
82
+ return cachedVersion;
83
+ } catch (error) {
84
+ console.error("Failed to read version from package.json:", error.message);
85
+ return "0.0.0";
86
+ }
87
+ }
88
+ __name(getVersion, "getVersion");
89
+ var VERSION = getVersion();
90
+ var PACKAGE_ROOT = getPackageRoot();
91
+
92
+ // core/infrastructure/command-installer.ts
43
93
  async function installDocs() {
44
94
  try {
45
- const docsDir = import_path.default.join(import_os.default.homedir(), ".prjct-cli", "docs");
46
- const templateDocsDir = import_path.default.join(__dirname, "../../templates/global/docs");
95
+ const docsDir = import_path2.default.join(import_os.default.homedir(), ".prjct-cli", "docs");
96
+ const templateDocsDir = import_path2.default.join(getPackageRoot(), "templates/global/docs");
47
97
  await import_promises.default.mkdir(docsDir, { recursive: true });
48
98
  const docFiles = await import_promises.default.readdir(templateDocsDir);
49
99
  for (const file of docFiles) {
50
100
  if (file.endsWith(".md")) {
51
- const srcPath = import_path.default.join(templateDocsDir, file);
52
- const destPath = import_path.default.join(docsDir, file);
101
+ const srcPath = import_path2.default.join(templateDocsDir, file);
102
+ const destPath = import_path2.default.join(docsDir, file);
53
103
  const content = await import_promises.default.readFile(srcPath, "utf-8");
54
104
  await import_promises.default.writeFile(destPath, content, "utf-8");
55
105
  }
@@ -70,10 +120,10 @@ async function installGlobalConfig(claudeConfigPath, detectClaude) {
70
120
  };
71
121
  }
72
122
  try {
73
- const claudeDir = import_path.default.join(import_os.default.homedir(), ".claude");
123
+ const claudeDir = import_path2.default.join(import_os.default.homedir(), ".claude");
74
124
  await import_promises.default.mkdir(claudeDir, { recursive: true });
75
- const globalConfigPath = import_path.default.join(claudeDir, "CLAUDE.md");
76
- const templatePath = import_path.default.join(__dirname, "../../templates/global/CLAUDE.md");
125
+ const globalConfigPath = import_path2.default.join(claudeDir, "CLAUDE.md");
126
+ const templatePath = import_path2.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
77
127
  const templateContent = await import_promises.default.readFile(templatePath, "utf-8");
78
128
  let existingContent = "";
79
129
  let fileExists = false;
@@ -139,9 +189,9 @@ var CommandInstaller = class {
139
189
  templatesDir;
140
190
  constructor() {
141
191
  this.homeDir = import_os.default.homedir();
142
- this.claudeCommandsPath = import_path.default.join(this.homeDir, ".claude", "commands", "p");
143
- this.claudeConfigPath = import_path.default.join(this.homeDir, ".claude");
144
- this.templatesDir = import_path.default.join(__dirname, "..", "..", "templates", "commands");
192
+ this.claudeCommandsPath = import_path2.default.join(this.homeDir, ".claude", "commands", "p");
193
+ this.claudeConfigPath = import_path2.default.join(this.homeDir, ".claude");
194
+ this.templatesDir = import_path2.default.join(getPackageRoot(), "templates", "commands");
145
195
  }
146
196
  /**
147
197
  * Detect if Claude is installed
@@ -204,8 +254,8 @@ var CommandInstaller = class {
204
254
  const errors = [];
205
255
  for (const file of commandFiles) {
206
256
  try {
207
- const sourcePath = import_path.default.join(this.templatesDir, file);
208
- const destPath = import_path.default.join(this.claudeCommandsPath, file);
257
+ const sourcePath = import_path2.default.join(this.templatesDir, file);
258
+ const destPath = import_path2.default.join(this.claudeCommandsPath, file);
209
259
  const content = await import_promises.default.readFile(sourcePath, "utf-8");
210
260
  await import_promises.default.writeFile(destPath, content, "utf-8");
211
261
  installed.push(file.replace(".md", ""));
@@ -236,7 +286,7 @@ var CommandInstaller = class {
236
286
  const errors = [];
237
287
  for (const file of commandFiles) {
238
288
  try {
239
- const filePath = import_path.default.join(this.claudeCommandsPath, file);
289
+ const filePath = import_path2.default.join(this.claudeCommandsPath, file);
240
290
  await import_promises.default.unlink(filePath);
241
291
  uninstalled.push(file.replace(".md", ""));
242
292
  } catch (error) {
@@ -318,7 +368,7 @@ var CommandInstaller = class {
318
368
  */
319
369
  async verifyTemplate(commandName) {
320
370
  try {
321
- const templatePath = import_path.default.join(this.templatesDir, `${commandName}.md`);
371
+ const templatePath = import_path2.default.join(this.templatesDir, `${commandName}.md`);
322
372
  await import_promises.default.access(templatePath);
323
373
  return true;
324
374
  } catch {
@@ -332,8 +382,8 @@ var CommandInstaller = class {
332
382
  */
333
383
  async installRouter() {
334
384
  try {
335
- const routerSource = import_path.default.join(this.templatesDir, "p.md");
336
- const routerDest = import_path.default.join(this.homeDir, ".claude", "commands", "p.md");
385
+ const routerSource = import_path2.default.join(this.templatesDir, "p.md");
386
+ const routerDest = import_path2.default.join(this.homeDir, ".claude", "commands", "p.md");
337
387
  const content = await import_promises.default.readFile(routerSource, "utf-8");
338
388
  await import_promises.default.writeFile(routerDest, content, "utf-8");
339
389
  return true;
@@ -375,8 +425,8 @@ var CommandInstaller = class {
375
425
  };
376
426
  for (const file of templateFiles) {
377
427
  try {
378
- const sourcePath = import_path.default.join(this.templatesDir, file);
379
- const destPath = import_path.default.join(this.claudeCommandsPath, file);
428
+ const sourcePath = import_path2.default.join(this.templatesDir, file);
429
+ const destPath = import_path2.default.join(this.claudeCommandsPath, file);
380
430
  const exists = installedFiles.includes(file);
381
431
  const content = await import_promises.default.readFile(sourcePath, "utf-8");
382
432
  await import_promises.default.writeFile(destPath, content, "utf-8");
@@ -44,10 +44,11 @@ var import_os3 = __toESM(require("os"));
44
44
  var import_promises = __toESM(require("fs/promises"));
45
45
  var import_path = __toESM(require("path"));
46
46
  var import_os = __toESM(require("os"));
47
+ var import_version = require("../utils/version");
47
48
  async function installDocs() {
48
49
  try {
49
50
  const docsDir = import_path.default.join(import_os.default.homedir(), ".prjct-cli", "docs");
50
- const templateDocsDir = import_path.default.join(__dirname, "../../templates/global/docs");
51
+ const templateDocsDir = import_path.default.join((0, import_version.getPackageRoot)(), "templates/global/docs");
51
52
  await import_promises.default.mkdir(docsDir, { recursive: true });
52
53
  const docFiles = await import_promises.default.readdir(templateDocsDir);
53
54
  for (const file of docFiles) {
@@ -77,7 +78,7 @@ async function installGlobalConfig(claudeConfigPath, detectClaude) {
77
78
  const claudeDir = import_path.default.join(import_os.default.homedir(), ".claude");
78
79
  await import_promises.default.mkdir(claudeDir, { recursive: true });
79
80
  const globalConfigPath = import_path.default.join(claudeDir, "CLAUDE.md");
80
- const templatePath = import_path.default.join(__dirname, "../../templates/global/CLAUDE.md");
81
+ const templatePath = import_path.default.join((0, import_version.getPackageRoot)(), "templates/global/CLAUDE.md");
81
82
  const templateContent = await import_promises.default.readFile(templatePath, "utf-8");
82
83
  let existingContent = "";
83
84
  let fileExists = false;
@@ -145,7 +146,7 @@ var CommandInstaller = class {
145
146
  this.homeDir = import_os.default.homedir();
146
147
  this.claudeCommandsPath = import_path.default.join(this.homeDir, ".claude", "commands", "p");
147
148
  this.claudeConfigPath = import_path.default.join(this.homeDir, ".claude");
148
- this.templatesDir = import_path.default.join(__dirname, "..", "..", "templates", "commands");
149
+ this.templatesDir = import_path.default.join((0, import_version.getPackageRoot)(), "templates", "commands");
149
150
  }
150
151
  /**
151
152
  * Detect if Claude is installed
@@ -544,7 +545,7 @@ var editorsConfig = new EditorsConfig();
544
545
  var editors_config_default = editorsConfig;
545
546
 
546
547
  // core/infrastructure/setup.ts
547
- var import_version = require("../utils/version");
548
+ var import_version2 = require("../utils/version");
548
549
  var GREEN = "\x1B[32m";
549
550
  var YELLOW = "\x1B[33m";
550
551
  var DIM = "\x1B[2m";
@@ -605,7 +606,7 @@ async function run() {
605
606
  await command_installer_default.installDocs();
606
607
  await installStatusLine();
607
608
  }
608
- await editors_config_default.saveConfig(import_version.VERSION, command_installer_default.getInstallPath());
609
+ await editors_config_default.saveConfig(import_version2.VERSION, command_installer_default.getInstallPath());
609
610
  await migrateProjectsCliVersion();
610
611
  showResults(results);
611
612
  return results;
@@ -628,8 +629,8 @@ async function migrateProjectsCliVersion() {
628
629
  try {
629
630
  const content = import_fs.default.readFileSync(projectJsonPath, "utf8");
630
631
  const project = JSON.parse(content);
631
- if (project.cliVersion !== import_version.VERSION) {
632
- project.cliVersion = import_version.VERSION;
632
+ if (project.cliVersion !== import_version2.VERSION) {
633
+ project.cliVersion = import_version2.VERSION;
633
634
  import_fs.default.writeFileSync(projectJsonPath, JSON.stringify(project, null, 2));
634
635
  migrated++;
635
636
  }
@@ -637,7 +638,7 @@ async function migrateProjectsCliVersion() {
637
638
  }
638
639
  }
639
640
  if (migrated > 0) {
640
- console.log(` ${GREEN}\u2713${NC} Updated ${migrated} project(s) to v${import_version.VERSION}`);
641
+ console.log(` ${GREEN}\u2713${NC} Updated ${migrated} project(s) to v${import_version2.VERSION}`);
641
642
  }
642
643
  } catch {
643
644
  }
@@ -666,7 +667,7 @@ async function installStatusLine() {
666
667
  const prjctLibDir = import_path3.default.join(prjctStatusLineDir, "lib");
667
668
  const prjctComponentsDir = import_path3.default.join(prjctStatusLineDir, "components");
668
669
  const prjctConfigPath = import_path3.default.join(prjctStatusLineDir, "config.json");
669
- const assetsDir = import_path3.default.join(__dirname, "..", "..", "assets", "statusline");
670
+ const assetsDir = import_path3.default.join((0, import_version2.getPackageRoot)(), "assets", "statusline");
670
671
  const sourceScript = import_path3.default.join(assetsDir, "statusline.sh");
671
672
  const sourceThemeDir = import_path3.default.join(assetsDir, "themes");
672
673
  const sourceLibDir = import_path3.default.join(assetsDir, "lib");
@@ -691,10 +692,10 @@ async function installStatusLine() {
691
692
  const existingContent = import_fs.default.readFileSync(prjctStatusLinePath, "utf8");
692
693
  if (existingContent.includes("CLI_VERSION=")) {
693
694
  const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
694
- if (versionMatch && versionMatch[1] !== import_version.VERSION) {
695
+ if (versionMatch && versionMatch[1] !== import_version2.VERSION) {
695
696
  const updatedContent = existingContent.replace(
696
697
  /CLI_VERSION="[^"]*"/,
697
- `CLI_VERSION="${import_version.VERSION}"`
698
+ `CLI_VERSION="${import_version2.VERSION}"`
698
699
  );
699
700
  import_fs.default.writeFileSync(prjctStatusLinePath, updatedContent, { mode: 493 });
700
701
  }
@@ -709,7 +710,7 @@ async function installStatusLine() {
709
710
  let scriptContent = import_fs.default.readFileSync(sourceScript, "utf8");
710
711
  scriptContent = scriptContent.replace(
711
712
  /CLI_VERSION="[^"]*"/,
712
- `CLI_VERSION="${import_version.VERSION}"`
713
+ `CLI_VERSION="${import_version2.VERSION}"`
713
714
  );
714
715
  import_fs.default.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
715
716
  installStatusLineModules(sourceLibDir, prjctLibDir);
@@ -728,7 +729,7 @@ async function installStatusLine() {
728
729
  } else {
729
730
  const scriptContent = `#!/bin/bash
730
731
  # prjct Status Line for Claude Code
731
- CLI_VERSION="${import_version.VERSION}"
732
+ CLI_VERSION="${import_version2.VERSION}"
732
733
  input=$(cat)
733
734
  CWD=$(echo "$input" | jq -r '.workspace.current_dir // "~"' 2>/dev/null)
734
735
  CONFIG="$CWD/.prjct/prjct.config.json"
@@ -31,10 +31,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // core/utils/version.ts
32
32
  var version_exports = {};
33
33
  __export(version_exports, {
34
+ PACKAGE_ROOT: () => PACKAGE_ROOT,
34
35
  VERSION: () => VERSION,
35
36
  compareVersions: () => compareVersions,
36
37
  default: () => version_default,
37
38
  getPackageInfo: () => getPackageInfo,
39
+ getPackageRoot: () => getPackageRoot,
38
40
  getVersion: () => getVersion,
39
41
  isCompatible: () => isCompatible,
40
42
  needsMigration: () => needsMigration
@@ -44,12 +46,36 @@ var import_fs = __toESM(require("fs"));
44
46
  var import_path = __toESM(require("path"));
45
47
  var cachedVersion = null;
46
48
  var cachedPackageJson = null;
49
+ var cachedPackageRoot = null;
50
+ function getPackageRoot() {
51
+ if (cachedPackageRoot) {
52
+ return cachedPackageRoot;
53
+ }
54
+ let currentDir = __dirname;
55
+ for (let i = 0; i < 5; i++) {
56
+ const packageJsonPath = import_path.default.join(currentDir, "package.json");
57
+ if (import_fs.default.existsSync(packageJsonPath)) {
58
+ try {
59
+ const pkg = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
60
+ if (pkg.name === "prjct-cli") {
61
+ cachedPackageRoot = currentDir;
62
+ return currentDir;
63
+ }
64
+ } catch {
65
+ }
66
+ }
67
+ currentDir = import_path.default.dirname(currentDir);
68
+ }
69
+ cachedPackageRoot = import_path.default.join(__dirname, "..", "..", "..");
70
+ return cachedPackageRoot;
71
+ }
72
+ __name(getPackageRoot, "getPackageRoot");
47
73
  function getVersion() {
48
74
  if (cachedVersion) {
49
75
  return cachedVersion;
50
76
  }
51
77
  try {
52
- const packageJsonPath = import_path.default.join(__dirname, "..", "..", "package.json");
78
+ const packageJsonPath = import_path.default.join(getPackageRoot(), "package.json");
53
79
  const packageJson = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
54
80
  cachedVersion = packageJson.version;
55
81
  cachedPackageJson = packageJson;
@@ -92,19 +118,24 @@ function needsMigration(fromVersion, toVersion = null) {
92
118
  }
93
119
  __name(needsMigration, "needsMigration");
94
120
  var VERSION = getVersion();
121
+ var PACKAGE_ROOT = getPackageRoot();
95
122
  var version_default = {
96
123
  getVersion,
124
+ getPackageRoot,
97
125
  getPackageInfo,
98
126
  compareVersions,
99
127
  isCompatible,
100
128
  needsMigration,
101
- VERSION
129
+ VERSION,
130
+ PACKAGE_ROOT
102
131
  };
103
132
  // Annotate the CommonJS export names for ESM import in node:
104
133
  0 && (module.exports = {
134
+ PACKAGE_ROOT,
105
135
  VERSION,
106
136
  compareVersions,
107
137
  getPackageInfo,
138
+ getPackageRoot,
108
139
  getVersion,
109
140
  isCompatible,
110
141
  needsMigration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.29.4",
3
+ "version": "0.29.6",
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": {
@@ -154,10 +154,9 @@ function updateStatusLineVersion() {
154
154
  * Main
155
155
  */
156
156
  async function main() {
157
- // Only run for global installs
158
- if (!isGlobalInstall()) {
159
- return
160
- }
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
161
160
 
162
161
  console.log('')
163
162
  console.log(' prjct-cli postinstall')
@@ -169,17 +168,23 @@ async function main() {
169
168
  }
170
169
 
171
170
  // Run full setup
171
+ let success = false
172
172
  if (hasBun()) {
173
- await runSetupBun()
173
+ success = await runSetupBun()
174
174
  } else {
175
- await runSetupCompiled()
175
+ success = await runSetupCompiled()
176
+ }
177
+
178
+ if (!success) {
179
+ console.log(' ⚠ Setup incomplete. Run: npx prjct-cli setup')
176
180
  }
177
181
 
178
182
  console.log('')
179
183
  }
180
184
 
181
185
  main().catch((error) => {
182
- // Never fail npm install due to postinstall issues
183
- console.warn(' postinstall warning:', error.message)
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')
184
189
  process.exit(0)
185
190
  })
@@ -5,28 +5,41 @@ 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 command.
8
+ Route `p. <command>` to the appropriate prjct template.
9
9
 
10
10
  ## Instructions
11
11
 
12
12
  **ARGUMENTS**: $ARGUMENTS
13
13
 
14
14
  1. Parse ARGUMENTS: first word = `command`, rest = `commandArgs`
15
- 2. Read the template file: `~/.claude/commands/p/{command}.md`
16
- 3. Execute that template with `commandArgs` as the task description
15
+ 2. Find npm global root by running:
16
+ ```bash
17
+ npm root -g
18
+ ```
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:
21
+ ```
22
+ {npmRoot}/prjct-cli/templates/commands/{command}.md
23
+ ```
24
+ 4. Execute that template with `commandArgs` as input
17
25
 
18
26
  ## Example
19
27
 
20
28
  If ARGUMENTS = "task fix the login bug":
21
29
  - command = "task"
22
30
  - commandArgs = "fix the login bug"
23
- - Read: `~/.claude/commands/p/task.md`
31
+ - Run: `npm root -g` → `/opt/homebrew/lib/node_modules`
32
+ - Read: `/opt/homebrew/lib/node_modules/prjct-cli/templates/commands/task.md`
24
33
  - Execute with: "fix the login bug"
25
34
 
35
+ ## Fallback
36
+
37
+ If npm root fails, read from local cache: `~/.claude/commands/p/{command}.md`
38
+
26
39
  ## Available Commands
27
40
 
28
- `task` `done` `ship` `sync` `init` `idea` `dash` `next` `pause` `resume` `bug` `linear` `feature` `prd` `plan` `review` `merge` `git` `test` `cleanup` `design` `analyze` `history` `enrich`
41
+ `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`
29
42
 
30
43
  ## Action
31
44
 
32
- NOW read the command template and execute it.
45
+ NOW find npm root and read the command template.
@@ -0,0 +1,39 @@
1
+ ---
2
+ allowed-tools: [Bash, Read, Write]
3
+ description: 'Update prjct-cli installation - sync commands, statusline, config'
4
+ ---
5
+
6
+ # p. update - Update prjct-cli Installation
7
+
8
+ Run this after `npm update -g prjct-cli` to sync all components.
9
+
10
+ ## What It Does
11
+
12
+ 1. Syncs commands to `~/.claude/commands/p/`
13
+ 2. Updates statusline in `~/.prjct-cli/statusline/`
14
+ 3. Updates global CLAUDE.md config
15
+ 4. Updates project versions
16
+
17
+ ## Execute
18
+
19
+ Run the setup script directly:
20
+
21
+ ```bash
22
+ node "$(npm root -g)/prjct-cli/dist/core/infrastructure/setup.js"
23
+ ```
24
+
25
+ If that fails, try with bun:
26
+
27
+ ```bash
28
+ bun "$(npm root -g)/prjct-cli/core/infrastructure/setup.ts"
29
+ ```
30
+
31
+ ## Output
32
+
33
+ ```
34
+ ✓ prjct-cli updated to v{version}
35
+
36
+ Commands: {n} synced
37
+ Statusline: updated
38
+ Config: updated
39
+ ```