prjct-cli 0.29.2 → 0.29.3
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/dist/bin/prjct.mjs +4 -0
- package/dist/core/infrastructure/command-installer.js +423 -0
- package/dist/core/infrastructure/editors-config.js +157 -0
- package/dist/core/infrastructure/setup.js +837 -0
- package/dist/core/utils/version.js +111 -0
- package/package.json +5 -1
- package/scripts/build.js +80 -17
- package/scripts/postinstall.js +111 -126
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// core/infrastructure/setup.ts
|
|
32
|
+
var setup_exports = {};
|
|
33
|
+
__export(setup_exports, {
|
|
34
|
+
default: () => setup_default,
|
|
35
|
+
run: () => run
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(setup_exports);
|
|
38
|
+
var import_child_process = require("child_process");
|
|
39
|
+
var import_fs = __toESM(require("fs"));
|
|
40
|
+
var import_path3 = __toESM(require("path"));
|
|
41
|
+
var import_os3 = __toESM(require("os"));
|
|
42
|
+
|
|
43
|
+
// core/infrastructure/command-installer.ts
|
|
44
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
45
|
+
var import_path = __toESM(require("path"));
|
|
46
|
+
var import_os = __toESM(require("os"));
|
|
47
|
+
async function installDocs() {
|
|
48
|
+
try {
|
|
49
|
+
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
|
+
await import_promises.default.mkdir(docsDir, { recursive: true });
|
|
52
|
+
const docFiles = await import_promises.default.readdir(templateDocsDir);
|
|
53
|
+
for (const file of docFiles) {
|
|
54
|
+
if (file.endsWith(".md")) {
|
|
55
|
+
const srcPath = import_path.default.join(templateDocsDir, file);
|
|
56
|
+
const destPath = import_path.default.join(docsDir, file);
|
|
57
|
+
const content = await import_promises.default.readFile(srcPath, "utf-8");
|
|
58
|
+
await import_promises.default.writeFile(destPath, content, "utf-8");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { success: true };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return { success: false, error: error.message };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
__name(installDocs, "installDocs");
|
|
67
|
+
async function installGlobalConfig(claudeConfigPath, detectClaude) {
|
|
68
|
+
const claudeDetected = await detectClaude();
|
|
69
|
+
if (!claudeDetected) {
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: "Claude not detected",
|
|
73
|
+
action: "skipped"
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const claudeDir = import_path.default.join(import_os.default.homedir(), ".claude");
|
|
78
|
+
await import_promises.default.mkdir(claudeDir, { recursive: true });
|
|
79
|
+
const globalConfigPath = import_path.default.join(claudeDir, "CLAUDE.md");
|
|
80
|
+
const templatePath = import_path.default.join(__dirname, "../../templates/global/CLAUDE.md");
|
|
81
|
+
const templateContent = await import_promises.default.readFile(templatePath, "utf-8");
|
|
82
|
+
let existingContent = "";
|
|
83
|
+
let fileExists = false;
|
|
84
|
+
try {
|
|
85
|
+
existingContent = await import_promises.default.readFile(globalConfigPath, "utf-8");
|
|
86
|
+
fileExists = true;
|
|
87
|
+
} catch {
|
|
88
|
+
fileExists = false;
|
|
89
|
+
}
|
|
90
|
+
if (!fileExists) {
|
|
91
|
+
await import_promises.default.writeFile(globalConfigPath, templateContent, "utf-8");
|
|
92
|
+
return {
|
|
93
|
+
success: true,
|
|
94
|
+
action: "created",
|
|
95
|
+
path: globalConfigPath
|
|
96
|
+
};
|
|
97
|
+
} else {
|
|
98
|
+
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
99
|
+
const endMarker = "<!-- prjct:end - DO NOT REMOVE THIS MARKER -->";
|
|
100
|
+
const hasMarkers = existingContent.includes(startMarker) && existingContent.includes(endMarker);
|
|
101
|
+
if (!hasMarkers) {
|
|
102
|
+
const updatedContent = existingContent + "\n\n" + templateContent;
|
|
103
|
+
await import_promises.default.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
104
|
+
return {
|
|
105
|
+
success: true,
|
|
106
|
+
action: "appended",
|
|
107
|
+
path: globalConfigPath
|
|
108
|
+
};
|
|
109
|
+
} else {
|
|
110
|
+
const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
|
|
111
|
+
const afterMarker = existingContent.substring(
|
|
112
|
+
existingContent.indexOf(endMarker) + endMarker.length
|
|
113
|
+
);
|
|
114
|
+
const prjctSection = templateContent.substring(
|
|
115
|
+
templateContent.indexOf(startMarker),
|
|
116
|
+
templateContent.indexOf(endMarker) + endMarker.length
|
|
117
|
+
);
|
|
118
|
+
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
119
|
+
await import_promises.default.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
120
|
+
return {
|
|
121
|
+
success: true,
|
|
122
|
+
action: "updated",
|
|
123
|
+
path: globalConfigPath
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
error: error.message,
|
|
131
|
+
action: "failed"
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
__name(installGlobalConfig, "installGlobalConfig");
|
|
136
|
+
var CommandInstaller = class {
|
|
137
|
+
static {
|
|
138
|
+
__name(this, "CommandInstaller");
|
|
139
|
+
}
|
|
140
|
+
homeDir;
|
|
141
|
+
claudeCommandsPath;
|
|
142
|
+
claudeConfigPath;
|
|
143
|
+
templatesDir;
|
|
144
|
+
constructor() {
|
|
145
|
+
this.homeDir = import_os.default.homedir();
|
|
146
|
+
this.claudeCommandsPath = import_path.default.join(this.homeDir, ".claude", "commands", "p");
|
|
147
|
+
this.claudeConfigPath = import_path.default.join(this.homeDir, ".claude");
|
|
148
|
+
this.templatesDir = import_path.default.join(__dirname, "..", "..", "templates", "commands");
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Detect if Claude is installed
|
|
152
|
+
*/
|
|
153
|
+
async detectClaude() {
|
|
154
|
+
try {
|
|
155
|
+
await import_promises.default.access(this.claudeConfigPath);
|
|
156
|
+
return true;
|
|
157
|
+
} catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get list of command files to install
|
|
163
|
+
*/
|
|
164
|
+
async getCommandFiles() {
|
|
165
|
+
try {
|
|
166
|
+
const files = await import_promises.default.readdir(this.templatesDir);
|
|
167
|
+
return files.filter((f) => f.endsWith(".md"));
|
|
168
|
+
} catch {
|
|
169
|
+
return [
|
|
170
|
+
"init.md",
|
|
171
|
+
"now.md",
|
|
172
|
+
"done.md",
|
|
173
|
+
"ship.md",
|
|
174
|
+
"next.md",
|
|
175
|
+
"idea.md",
|
|
176
|
+
"recap.md",
|
|
177
|
+
"progress.md",
|
|
178
|
+
"stuck.md",
|
|
179
|
+
"context.md",
|
|
180
|
+
"analyze.md",
|
|
181
|
+
"sync.md",
|
|
182
|
+
"roadmap.md",
|
|
183
|
+
"task.md",
|
|
184
|
+
"git.md",
|
|
185
|
+
"fix.md",
|
|
186
|
+
"test.md",
|
|
187
|
+
"cleanup.md",
|
|
188
|
+
"design.md"
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Install commands to Claude
|
|
194
|
+
*/
|
|
195
|
+
async installCommands() {
|
|
196
|
+
const claudeDetected = await this.detectClaude();
|
|
197
|
+
if (!claudeDetected) {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: "Claude not detected. Please install Claude Code or Claude Desktop first."
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
await this.installRouter();
|
|
205
|
+
await import_promises.default.mkdir(this.claudeCommandsPath, { recursive: true });
|
|
206
|
+
const commandFiles = await this.getCommandFiles();
|
|
207
|
+
const installed = [];
|
|
208
|
+
const errors = [];
|
|
209
|
+
for (const file of commandFiles) {
|
|
210
|
+
try {
|
|
211
|
+
const sourcePath = import_path.default.join(this.templatesDir, file);
|
|
212
|
+
const destPath = import_path.default.join(this.claudeCommandsPath, file);
|
|
213
|
+
const content = await import_promises.default.readFile(sourcePath, "utf-8");
|
|
214
|
+
await import_promises.default.writeFile(destPath, content, "utf-8");
|
|
215
|
+
installed.push(file.replace(".md", ""));
|
|
216
|
+
} catch (error) {
|
|
217
|
+
errors.push({ file, error: error.message });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
success: true,
|
|
222
|
+
installed,
|
|
223
|
+
errors,
|
|
224
|
+
path: this.claudeCommandsPath
|
|
225
|
+
};
|
|
226
|
+
} catch (error) {
|
|
227
|
+
return {
|
|
228
|
+
success: false,
|
|
229
|
+
error: error.message
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Uninstall commands from Claude
|
|
235
|
+
*/
|
|
236
|
+
async uninstallCommands() {
|
|
237
|
+
try {
|
|
238
|
+
const commandFiles = await this.getCommandFiles();
|
|
239
|
+
const uninstalled = [];
|
|
240
|
+
const errors = [];
|
|
241
|
+
for (const file of commandFiles) {
|
|
242
|
+
try {
|
|
243
|
+
const filePath = import_path.default.join(this.claudeCommandsPath, file);
|
|
244
|
+
await import_promises.default.unlink(filePath);
|
|
245
|
+
uninstalled.push(file.replace(".md", ""));
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (error.code !== "ENOENT") {
|
|
248
|
+
errors.push({ file, error: error.message });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
await import_promises.default.rmdir(this.claudeCommandsPath);
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
success: true,
|
|
258
|
+
uninstalled,
|
|
259
|
+
errors
|
|
260
|
+
};
|
|
261
|
+
} catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
success: false,
|
|
264
|
+
error: error.message
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Check if commands are already installed
|
|
270
|
+
*/
|
|
271
|
+
async checkInstallation() {
|
|
272
|
+
const claudeDetected = await this.detectClaude();
|
|
273
|
+
if (!claudeDetected) {
|
|
274
|
+
return {
|
|
275
|
+
installed: false,
|
|
276
|
+
claudeDetected: false
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
await import_promises.default.access(this.claudeCommandsPath);
|
|
281
|
+
const files = await import_promises.default.readdir(this.claudeCommandsPath);
|
|
282
|
+
const installedCommands = files.filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
283
|
+
return {
|
|
284
|
+
installed: installedCommands.length > 0,
|
|
285
|
+
claudeDetected: true,
|
|
286
|
+
commands: installedCommands,
|
|
287
|
+
path: this.claudeCommandsPath
|
|
288
|
+
};
|
|
289
|
+
} catch {
|
|
290
|
+
return {
|
|
291
|
+
installed: false,
|
|
292
|
+
claudeDetected: true,
|
|
293
|
+
commands: []
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Update commands (reinstall with latest templates)
|
|
299
|
+
*/
|
|
300
|
+
async updateCommands() {
|
|
301
|
+
console.log("Updating commands with latest templates...");
|
|
302
|
+
const result = await this.installCommands();
|
|
303
|
+
if (result.success && result.installed) {
|
|
304
|
+
console.log(`Updated ${result.installed.length} commands`);
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Install to all detected editors (alias for installCommands)
|
|
310
|
+
*/
|
|
311
|
+
async installToAll() {
|
|
312
|
+
return await this.installCommands();
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Get installation path for Claude commands
|
|
316
|
+
*/
|
|
317
|
+
getInstallPath() {
|
|
318
|
+
return this.claudeCommandsPath;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Verify command template exists
|
|
322
|
+
*/
|
|
323
|
+
async verifyTemplate(commandName) {
|
|
324
|
+
try {
|
|
325
|
+
const templatePath = import_path.default.join(this.templatesDir, `${commandName}.md`);
|
|
326
|
+
await import_promises.default.access(templatePath);
|
|
327
|
+
return true;
|
|
328
|
+
} catch {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Install the p.md router to ~/.claude/commands/
|
|
334
|
+
* This enables the "p. task" natural language trigger
|
|
335
|
+
* Claude Code bug #2422 prevents subdirectory slash command discovery
|
|
336
|
+
*/
|
|
337
|
+
async installRouter() {
|
|
338
|
+
try {
|
|
339
|
+
const routerSource = import_path.default.join(this.templatesDir, "p.md");
|
|
340
|
+
const routerDest = import_path.default.join(this.homeDir, ".claude", "commands", "p.md");
|
|
341
|
+
const content = await import_promises.default.readFile(routerSource, "utf-8");
|
|
342
|
+
await import_promises.default.writeFile(routerDest, content, "utf-8");
|
|
343
|
+
return true;
|
|
344
|
+
} catch {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Sync commands - intelligent update that detects and removes orphans
|
|
350
|
+
*/
|
|
351
|
+
async syncCommands() {
|
|
352
|
+
const claudeDetected = await this.detectClaude();
|
|
353
|
+
if (!claudeDetected) {
|
|
354
|
+
return {
|
|
355
|
+
success: false,
|
|
356
|
+
error: "Claude not detected",
|
|
357
|
+
added: 0,
|
|
358
|
+
updated: 0,
|
|
359
|
+
removed: 0
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
try {
|
|
363
|
+
await this.installRouter();
|
|
364
|
+
await import_promises.default.mkdir(this.claudeCommandsPath, { recursive: true });
|
|
365
|
+
const templateFiles = await this.getCommandFiles();
|
|
366
|
+
let installedFiles = [];
|
|
367
|
+
try {
|
|
368
|
+
installedFiles = await import_promises.default.readdir(this.claudeCommandsPath);
|
|
369
|
+
installedFiles = installedFiles.filter((f) => f.endsWith(".md"));
|
|
370
|
+
} catch {
|
|
371
|
+
installedFiles = [];
|
|
372
|
+
}
|
|
373
|
+
const results = {
|
|
374
|
+
success: true,
|
|
375
|
+
added: 0,
|
|
376
|
+
updated: 0,
|
|
377
|
+
removed: 0,
|
|
378
|
+
errors: []
|
|
379
|
+
};
|
|
380
|
+
for (const file of templateFiles) {
|
|
381
|
+
try {
|
|
382
|
+
const sourcePath = import_path.default.join(this.templatesDir, file);
|
|
383
|
+
const destPath = import_path.default.join(this.claudeCommandsPath, file);
|
|
384
|
+
const exists = installedFiles.includes(file);
|
|
385
|
+
const content = await import_promises.default.readFile(sourcePath, "utf-8");
|
|
386
|
+
await import_promises.default.writeFile(destPath, content, "utf-8");
|
|
387
|
+
if (!exists) {
|
|
388
|
+
results.added++;
|
|
389
|
+
} else {
|
|
390
|
+
results.updated++;
|
|
391
|
+
}
|
|
392
|
+
} catch (error) {
|
|
393
|
+
results.errors.push({ file, error: error.message });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return results;
|
|
397
|
+
} catch (error) {
|
|
398
|
+
return {
|
|
399
|
+
success: false,
|
|
400
|
+
error: error.message,
|
|
401
|
+
added: 0,
|
|
402
|
+
updated: 0,
|
|
403
|
+
removed: 0
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Install or update global CLAUDE.md configuration
|
|
409
|
+
*/
|
|
410
|
+
async installGlobalConfig() {
|
|
411
|
+
return installGlobalConfig(this.claudeConfigPath, () => this.detectClaude());
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Install documentation files to ~/.prjct-cli/docs/
|
|
415
|
+
*/
|
|
416
|
+
async installDocs() {
|
|
417
|
+
return installDocs();
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
var commandInstaller = new CommandInstaller();
|
|
421
|
+
var command_installer_default = commandInstaller;
|
|
422
|
+
|
|
423
|
+
// core/infrastructure/editors-config.ts
|
|
424
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
425
|
+
var import_path2 = __toESM(require("path"));
|
|
426
|
+
var import_os2 = __toESM(require("os"));
|
|
427
|
+
var EditorsConfig = class {
|
|
428
|
+
static {
|
|
429
|
+
__name(this, "EditorsConfig");
|
|
430
|
+
}
|
|
431
|
+
homeDir;
|
|
432
|
+
configDir;
|
|
433
|
+
configFile;
|
|
434
|
+
constructor() {
|
|
435
|
+
this.homeDir = import_os2.default.homedir();
|
|
436
|
+
this.configDir = import_path2.default.join(this.homeDir, ".prjct-cli", "config");
|
|
437
|
+
this.configFile = import_path2.default.join(this.configDir, "installed-editors.json");
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Ensure config directory exists
|
|
441
|
+
*/
|
|
442
|
+
async ensureConfigDir() {
|
|
443
|
+
try {
|
|
444
|
+
await import_promises2.default.mkdir(this.configDir, { recursive: true });
|
|
445
|
+
} catch (error) {
|
|
446
|
+
console.error("[editors-config] Error creating config directory:", error.message);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Load installation configuration
|
|
451
|
+
*/
|
|
452
|
+
async loadConfig() {
|
|
453
|
+
try {
|
|
454
|
+
const content = await import_promises2.default.readFile(this.configFile, "utf-8");
|
|
455
|
+
return JSON.parse(content);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
if (error.code === "ENOENT") {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
console.error("[editors-config] Error loading config:", error.message);
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Save installation configuration
|
|
466
|
+
*/
|
|
467
|
+
async saveConfig(version, claudePath) {
|
|
468
|
+
try {
|
|
469
|
+
await this.ensureConfigDir();
|
|
470
|
+
const config = {
|
|
471
|
+
version,
|
|
472
|
+
editor: "claude",
|
|
473
|
+
lastInstall: (/* @__PURE__ */ new Date()).toISOString(),
|
|
474
|
+
path: claudePath
|
|
475
|
+
};
|
|
476
|
+
await import_promises2.default.writeFile(this.configFile, JSON.stringify(config, null, 2), "utf-8");
|
|
477
|
+
return true;
|
|
478
|
+
} catch (error) {
|
|
479
|
+
console.error("[editors-config] Error saving config:", error.message);
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Get last installed version
|
|
485
|
+
*/
|
|
486
|
+
async getLastVersion() {
|
|
487
|
+
const config = await this.loadConfig();
|
|
488
|
+
return config ? config.version : null;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Check if version has changed since last install
|
|
492
|
+
*/
|
|
493
|
+
async hasVersionChanged(currentVersion) {
|
|
494
|
+
const lastVersion = await this.getLastVersion();
|
|
495
|
+
return lastVersion !== null && lastVersion !== currentVersion;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Update version in configuration
|
|
499
|
+
*/
|
|
500
|
+
async updateVersion(version) {
|
|
501
|
+
try {
|
|
502
|
+
const config = await this.loadConfig();
|
|
503
|
+
if (!config) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
config.version = version;
|
|
507
|
+
config.lastInstall = (/* @__PURE__ */ new Date()).toISOString();
|
|
508
|
+
await import_promises2.default.writeFile(this.configFile, JSON.stringify(config, null, 2), "utf-8");
|
|
509
|
+
return true;
|
|
510
|
+
} catch (error) {
|
|
511
|
+
console.error("[editors-config] Error updating version:", error.message);
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Check if config file exists
|
|
517
|
+
*/
|
|
518
|
+
async configExists() {
|
|
519
|
+
try {
|
|
520
|
+
await import_promises2.default.access(this.configFile);
|
|
521
|
+
return true;
|
|
522
|
+
} catch {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Delete configuration file
|
|
528
|
+
* Used during uninstallation to clean up tracking data
|
|
529
|
+
*/
|
|
530
|
+
async deleteConfig() {
|
|
531
|
+
try {
|
|
532
|
+
const exists = await this.configExists();
|
|
533
|
+
if (exists) {
|
|
534
|
+
await import_promises2.default.unlink(this.configFile);
|
|
535
|
+
}
|
|
536
|
+
return true;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
console.error("[editors-config] Error deleting config:", error.message);
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
var editorsConfig = new EditorsConfig();
|
|
544
|
+
var editors_config_default = editorsConfig;
|
|
545
|
+
|
|
546
|
+
// core/infrastructure/setup.ts
|
|
547
|
+
var import_version = require("../utils/version");
|
|
548
|
+
var GREEN = "\x1B[32m";
|
|
549
|
+
var YELLOW = "\x1B[33m";
|
|
550
|
+
var DIM = "\x1B[2m";
|
|
551
|
+
var NC = "\x1B[0m";
|
|
552
|
+
async function hasClaudeCodeCLI() {
|
|
553
|
+
try {
|
|
554
|
+
(0, import_child_process.execSync)("which claude", { stdio: "ignore" });
|
|
555
|
+
return true;
|
|
556
|
+
} catch {
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
__name(hasClaudeCodeCLI, "hasClaudeCodeCLI");
|
|
561
|
+
async function installClaudeCode() {
|
|
562
|
+
try {
|
|
563
|
+
console.log(`${YELLOW}\u{1F4E6} Claude Code not found. Installing...${NC}`);
|
|
564
|
+
console.log("");
|
|
565
|
+
(0, import_child_process.execSync)("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
566
|
+
console.log("");
|
|
567
|
+
console.log(`${GREEN}\u2713${NC} Claude Code installed successfully`);
|
|
568
|
+
console.log("");
|
|
569
|
+
return true;
|
|
570
|
+
} catch (error) {
|
|
571
|
+
console.log(`${YELLOW}\u26A0\uFE0F Failed to install Claude Code: ${error.message}${NC}`);
|
|
572
|
+
console.log(`${DIM}Please install manually: npm install -g @anthropic-ai/claude-code${NC}`);
|
|
573
|
+
console.log("");
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
__name(installClaudeCode, "installClaudeCode");
|
|
578
|
+
async function run() {
|
|
579
|
+
const results = {
|
|
580
|
+
claudeInstalled: false,
|
|
581
|
+
commandsAdded: 0,
|
|
582
|
+
commandsUpdated: 0,
|
|
583
|
+
configAction: null
|
|
584
|
+
};
|
|
585
|
+
const hasClaude = await hasClaudeCodeCLI();
|
|
586
|
+
if (!hasClaude) {
|
|
587
|
+
const installed = await installClaudeCode();
|
|
588
|
+
if (installed) {
|
|
589
|
+
results.claudeInstalled = true;
|
|
590
|
+
} else {
|
|
591
|
+
throw new Error("Claude Code installation failed");
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const claudeDetected = await command_installer_default.detectClaude();
|
|
595
|
+
if (claudeDetected) {
|
|
596
|
+
const syncResult = await command_installer_default.syncCommands();
|
|
597
|
+
if (syncResult.success) {
|
|
598
|
+
results.commandsAdded = syncResult.added;
|
|
599
|
+
results.commandsUpdated = syncResult.updated;
|
|
600
|
+
}
|
|
601
|
+
const configResult = await command_installer_default.installGlobalConfig();
|
|
602
|
+
if (configResult.success) {
|
|
603
|
+
results.configAction = configResult.action;
|
|
604
|
+
}
|
|
605
|
+
await command_installer_default.installDocs();
|
|
606
|
+
await installStatusLine();
|
|
607
|
+
}
|
|
608
|
+
await editors_config_default.saveConfig(import_version.VERSION, command_installer_default.getInstallPath());
|
|
609
|
+
await migrateProjectsCliVersion();
|
|
610
|
+
showResults(results);
|
|
611
|
+
return results;
|
|
612
|
+
}
|
|
613
|
+
__name(run, "run");
|
|
614
|
+
var setup_default = { run };
|
|
615
|
+
async function migrateProjectsCliVersion() {
|
|
616
|
+
try {
|
|
617
|
+
const projectsDir = import_path3.default.join(import_os3.default.homedir(), ".prjct-cli", "projects");
|
|
618
|
+
if (!import_fs.default.existsSync(projectsDir)) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
const projectDirs = import_fs.default.readdirSync(projectsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
622
|
+
let migrated = 0;
|
|
623
|
+
for (const projectId of projectDirs) {
|
|
624
|
+
const projectJsonPath = import_path3.default.join(projectsDir, projectId, "project.json");
|
|
625
|
+
if (!import_fs.default.existsSync(projectJsonPath)) {
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
try {
|
|
629
|
+
const content = import_fs.default.readFileSync(projectJsonPath, "utf8");
|
|
630
|
+
const project = JSON.parse(content);
|
|
631
|
+
if (project.cliVersion !== import_version.VERSION) {
|
|
632
|
+
project.cliVersion = import_version.VERSION;
|
|
633
|
+
import_fs.default.writeFileSync(projectJsonPath, JSON.stringify(project, null, 2));
|
|
634
|
+
migrated++;
|
|
635
|
+
}
|
|
636
|
+
} catch {
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (migrated > 0) {
|
|
640
|
+
console.log(` ${GREEN}\u2713${NC} Updated ${migrated} project(s) to v${import_version.VERSION}`);
|
|
641
|
+
}
|
|
642
|
+
} catch {
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
__name(migrateProjectsCliVersion, "migrateProjectsCliVersion");
|
|
646
|
+
function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
647
|
+
let settings = {};
|
|
648
|
+
if (import_fs.default.existsSync(settingsPath)) {
|
|
649
|
+
try {
|
|
650
|
+
settings = JSON.parse(import_fs.default.readFileSync(settingsPath, "utf8"));
|
|
651
|
+
} catch {
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
settings.statusLine = { type: "command", command: statusLinePath };
|
|
655
|
+
import_fs.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
656
|
+
}
|
|
657
|
+
__name(ensureStatusLineSettings, "ensureStatusLineSettings");
|
|
658
|
+
async function installStatusLine() {
|
|
659
|
+
try {
|
|
660
|
+
const claudeDir = import_path3.default.join(import_os3.default.homedir(), ".claude");
|
|
661
|
+
const settingsPath = import_path3.default.join(claudeDir, "settings.json");
|
|
662
|
+
const claudeStatusLinePath = import_path3.default.join(claudeDir, "prjct-statusline.sh");
|
|
663
|
+
const prjctStatusLineDir = import_path3.default.join(import_os3.default.homedir(), ".prjct-cli", "statusline");
|
|
664
|
+
const prjctStatusLinePath = import_path3.default.join(prjctStatusLineDir, "statusline.sh");
|
|
665
|
+
const prjctThemesDir = import_path3.default.join(prjctStatusLineDir, "themes");
|
|
666
|
+
const prjctLibDir = import_path3.default.join(prjctStatusLineDir, "lib");
|
|
667
|
+
const prjctComponentsDir = import_path3.default.join(prjctStatusLineDir, "components");
|
|
668
|
+
const prjctConfigPath = import_path3.default.join(prjctStatusLineDir, "config.json");
|
|
669
|
+
const assetsDir = import_path3.default.join(__dirname, "..", "..", "assets", "statusline");
|
|
670
|
+
const sourceScript = import_path3.default.join(assetsDir, "statusline.sh");
|
|
671
|
+
const sourceThemeDir = import_path3.default.join(assetsDir, "themes");
|
|
672
|
+
const sourceLibDir = import_path3.default.join(assetsDir, "lib");
|
|
673
|
+
const sourceComponentsDir = import_path3.default.join(assetsDir, "components");
|
|
674
|
+
const sourceConfigPath = import_path3.default.join(assetsDir, "default-config.json");
|
|
675
|
+
if (!import_fs.default.existsSync(claudeDir)) {
|
|
676
|
+
import_fs.default.mkdirSync(claudeDir, { recursive: true });
|
|
677
|
+
}
|
|
678
|
+
if (!import_fs.default.existsSync(prjctStatusLineDir)) {
|
|
679
|
+
import_fs.default.mkdirSync(prjctStatusLineDir, { recursive: true });
|
|
680
|
+
}
|
|
681
|
+
if (!import_fs.default.existsSync(prjctThemesDir)) {
|
|
682
|
+
import_fs.default.mkdirSync(prjctThemesDir, { recursive: true });
|
|
683
|
+
}
|
|
684
|
+
if (!import_fs.default.existsSync(prjctLibDir)) {
|
|
685
|
+
import_fs.default.mkdirSync(prjctLibDir, { recursive: true });
|
|
686
|
+
}
|
|
687
|
+
if (!import_fs.default.existsSync(prjctComponentsDir)) {
|
|
688
|
+
import_fs.default.mkdirSync(prjctComponentsDir, { recursive: true });
|
|
689
|
+
}
|
|
690
|
+
if (import_fs.default.existsSync(prjctStatusLinePath)) {
|
|
691
|
+
const existingContent = import_fs.default.readFileSync(prjctStatusLinePath, "utf8");
|
|
692
|
+
if (existingContent.includes("CLI_VERSION=")) {
|
|
693
|
+
const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
|
|
694
|
+
if (versionMatch && versionMatch[1] !== import_version.VERSION) {
|
|
695
|
+
const updatedContent = existingContent.replace(
|
|
696
|
+
/CLI_VERSION="[^"]*"/,
|
|
697
|
+
`CLI_VERSION="${import_version.VERSION}"`
|
|
698
|
+
);
|
|
699
|
+
import_fs.default.writeFileSync(prjctStatusLinePath, updatedContent, { mode: 493 });
|
|
700
|
+
}
|
|
701
|
+
installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
702
|
+
installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
703
|
+
ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
704
|
+
ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (import_fs.default.existsSync(sourceScript)) {
|
|
709
|
+
let scriptContent = import_fs.default.readFileSync(sourceScript, "utf8");
|
|
710
|
+
scriptContent = scriptContent.replace(
|
|
711
|
+
/CLI_VERSION="[^"]*"/,
|
|
712
|
+
`CLI_VERSION="${import_version.VERSION}"`
|
|
713
|
+
);
|
|
714
|
+
import_fs.default.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
715
|
+
installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
716
|
+
installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
717
|
+
if (import_fs.default.existsSync(sourceThemeDir)) {
|
|
718
|
+
const themes = import_fs.default.readdirSync(sourceThemeDir);
|
|
719
|
+
for (const theme of themes) {
|
|
720
|
+
const src = import_path3.default.join(sourceThemeDir, theme);
|
|
721
|
+
const dest = import_path3.default.join(prjctThemesDir, theme);
|
|
722
|
+
import_fs.default.copyFileSync(src, dest);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (!import_fs.default.existsSync(prjctConfigPath) && import_fs.default.existsSync(sourceConfigPath)) {
|
|
726
|
+
import_fs.default.copyFileSync(sourceConfigPath, prjctConfigPath);
|
|
727
|
+
}
|
|
728
|
+
} else {
|
|
729
|
+
const scriptContent = `#!/bin/bash
|
|
730
|
+
# prjct Status Line for Claude Code
|
|
731
|
+
CLI_VERSION="${import_version.VERSION}"
|
|
732
|
+
input=$(cat)
|
|
733
|
+
CWD=$(echo "$input" | jq -r '.workspace.current_dir // "~"' 2>/dev/null)
|
|
734
|
+
CONFIG="$CWD/.prjct/prjct.config.json"
|
|
735
|
+
if [ -f "$CONFIG" ]; then
|
|
736
|
+
PROJECT_ID=$(jq -r '.projectId // ""' "$CONFIG" 2>/dev/null)
|
|
737
|
+
if [ -n "$PROJECT_ID" ]; then
|
|
738
|
+
PROJECT_JSON="$HOME/.prjct-cli/projects/$PROJECT_ID/project.json"
|
|
739
|
+
if [ -f "$PROJECT_JSON" ]; then
|
|
740
|
+
PROJECT_VERSION=$(jq -r '.cliVersion // ""' "$PROJECT_JSON" 2>/dev/null)
|
|
741
|
+
if [ -z "$PROJECT_VERSION" ] || [ "$PROJECT_VERSION" != "$CLI_VERSION" ]; then
|
|
742
|
+
echo "prjct v$CLI_VERSION - run p. sync"
|
|
743
|
+
exit 0
|
|
744
|
+
fi
|
|
745
|
+
else
|
|
746
|
+
echo "prjct v$CLI_VERSION - run p. sync"
|
|
747
|
+
exit 0
|
|
748
|
+
fi
|
|
749
|
+
STATE="$HOME/.prjct-cli/projects/$PROJECT_ID/storage/state.json"
|
|
750
|
+
if [ -f "$STATE" ]; then
|
|
751
|
+
TASK=$(jq -r '.currentTask.description // ""' "$STATE" 2>/dev/null)
|
|
752
|
+
if [ -n "$TASK" ]; then
|
|
753
|
+
echo "$TASK"
|
|
754
|
+
exit 0
|
|
755
|
+
fi
|
|
756
|
+
fi
|
|
757
|
+
fi
|
|
758
|
+
fi
|
|
759
|
+
echo "prjct"
|
|
760
|
+
`;
|
|
761
|
+
import_fs.default.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
762
|
+
}
|
|
763
|
+
ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
764
|
+
ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
765
|
+
} catch {
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
__name(installStatusLine, "installStatusLine");
|
|
769
|
+
function installStatusLineModules(sourceDir, destDir) {
|
|
770
|
+
if (!import_fs.default.existsSync(sourceDir)) {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
const files = import_fs.default.readdirSync(sourceDir);
|
|
774
|
+
for (const file of files) {
|
|
775
|
+
if (file.endsWith(".sh")) {
|
|
776
|
+
const src = import_path3.default.join(sourceDir, file);
|
|
777
|
+
const dest = import_path3.default.join(destDir, file);
|
|
778
|
+
import_fs.default.copyFileSync(src, dest);
|
|
779
|
+
import_fs.default.chmodSync(dest, 493);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
__name(installStatusLineModules, "installStatusLineModules");
|
|
784
|
+
function ensureStatusLineSymlink(linkPath, targetPath) {
|
|
785
|
+
try {
|
|
786
|
+
if (import_fs.default.existsSync(linkPath)) {
|
|
787
|
+
const stats = import_fs.default.lstatSync(linkPath);
|
|
788
|
+
if (stats.isSymbolicLink()) {
|
|
789
|
+
const existingTarget = import_fs.default.readlinkSync(linkPath);
|
|
790
|
+
if (existingTarget === targetPath) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
import_fs.default.unlinkSync(linkPath);
|
|
795
|
+
}
|
|
796
|
+
import_fs.default.symlinkSync(targetPath, linkPath);
|
|
797
|
+
} catch {
|
|
798
|
+
try {
|
|
799
|
+
if (import_fs.default.existsSync(targetPath)) {
|
|
800
|
+
import_fs.default.copyFileSync(targetPath, linkPath);
|
|
801
|
+
import_fs.default.chmodSync(linkPath, 493);
|
|
802
|
+
}
|
|
803
|
+
} catch {
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
__name(ensureStatusLineSymlink, "ensureStatusLineSymlink");
|
|
808
|
+
function showResults(results) {
|
|
809
|
+
console.log("");
|
|
810
|
+
if (results.claudeInstalled) {
|
|
811
|
+
console.log(` ${GREEN}\u2713${NC} Claude Code CLI installed`);
|
|
812
|
+
} else {
|
|
813
|
+
console.log(` ${GREEN}\u2713${NC} Claude Code CLI found`);
|
|
814
|
+
}
|
|
815
|
+
const totalCommands = results.commandsAdded + results.commandsUpdated;
|
|
816
|
+
if (totalCommands > 0) {
|
|
817
|
+
const parts = [];
|
|
818
|
+
if (results.commandsAdded > 0) parts.push(`${results.commandsAdded} new`);
|
|
819
|
+
if (results.commandsUpdated > 0) parts.push(`${results.commandsUpdated} updated`);
|
|
820
|
+
console.log(` ${GREEN}\u2713${NC} Commands synced (${parts.join(", ")})`);
|
|
821
|
+
} else {
|
|
822
|
+
console.log(` ${GREEN}\u2713${NC} Commands up to date`);
|
|
823
|
+
}
|
|
824
|
+
if (results.configAction === "created") {
|
|
825
|
+
console.log(` ${GREEN}\u2713${NC} Global config created`);
|
|
826
|
+
} else if (results.configAction === "updated") {
|
|
827
|
+
console.log(` ${GREEN}\u2713${NC} Global config updated`);
|
|
828
|
+
} else if (results.configAction === "appended") {
|
|
829
|
+
console.log(` ${GREEN}\u2713${NC} Global config merged`);
|
|
830
|
+
}
|
|
831
|
+
console.log("");
|
|
832
|
+
}
|
|
833
|
+
__name(showResults, "showResults");
|
|
834
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
835
|
+
0 && (module.exports = {
|
|
836
|
+
run
|
|
837
|
+
});
|