prjct-cli 1.2.0 → 1.2.2
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 +81 -0
- package/bin/prjct.ts +25 -31
- package/core/agentic/ground-truth.ts +5 -3
- package/core/cli/start.ts +45 -59
- package/core/index.ts +20 -24
- package/core/infrastructure/setup.ts +29 -32
- package/core/schemas/ideas.ts +1 -1
- package/core/services/hooks-service.ts +3 -4
- package/core/utils/help.ts +42 -45
- package/core/utils/subtask-table.ts +27 -34
- package/core/workflow/workflow-preferences.ts +11 -17
- package/dist/bin/prjct.mjs +408 -439
- package/dist/core/infrastructure/setup.js +29 -30
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.2.2] - 2026-02-06
|
|
4
|
+
|
|
5
|
+
### Performance
|
|
6
|
+
|
|
7
|
+
- convert execSync to async in ground-truth.ts (PRJ-92) (#113)
|
|
8
|
+
- convert execSync to async in ground-truth.ts (PRJ-92)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## [1.2.1] - 2026-02-06
|
|
12
|
+
|
|
13
|
+
### Performance
|
|
14
|
+
|
|
15
|
+
- **Convert execSync to async in ground-truth.ts (PRJ-92)**: Replaced blocking execSync with promisify(exec) in verifyShip
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
- replace raw ANSI codes with chalk library (PRJ-132) (#111)
|
|
20
|
+
|
|
21
|
+
### Implementation Details
|
|
22
|
+
|
|
23
|
+
Replaced the single `execSync('git status --porcelain')` call in `verifyShip()` with `await execAsync()` using `promisify(exec)` from `node:util`. The rest of `ground-truth.ts` already used async `fs.promises` — this was the last synchronous call blocking the event loop.
|
|
24
|
+
|
|
25
|
+
### Learnings
|
|
26
|
+
|
|
27
|
+
- `exec` returns `{stdout, stderr}` object vs `execSync` returning a string directly — must destructure
|
|
28
|
+
- `promisify(exec)` is simpler than `spawn` for short-lived commands that return stdout
|
|
29
|
+
- Terminal control sequences (cursor movement) are separate from color/formatting — chalk doesn't handle them
|
|
30
|
+
|
|
31
|
+
### Test Plan
|
|
32
|
+
|
|
33
|
+
#### For QA
|
|
34
|
+
1. Run `bun run build && bun run typecheck` — zero errors
|
|
35
|
+
2. Trigger `verifyShip` path — verify async git status check works
|
|
36
|
+
3. Test with uncommitted changes — verify warning still appears
|
|
37
|
+
4. Test in non-git directory — verify graceful fallback (`gitAvailable = false`)
|
|
38
|
+
|
|
39
|
+
#### For Users
|
|
40
|
+
**What changed:** Internal performance improvement — git status check in ground-truth verifier is now async
|
|
41
|
+
**How to use:** No change needed — improvement is internal
|
|
42
|
+
**Breaking changes:** None
|
|
43
|
+
|
|
3
44
|
## [1.2.0] - 2026-02-06
|
|
4
45
|
|
|
5
46
|
### Features
|
|
@@ -56,6 +97,46 @@ Hook configuration saved to `project.json` for persistence across sessions.
|
|
|
56
97
|
**How to use:** Run `prjct hooks install` in any prjct project
|
|
57
98
|
**Breaking changes:** None
|
|
58
99
|
|
|
100
|
+
## [1.1.2] - 2026-02-05
|
|
101
|
+
|
|
102
|
+
### Fixed
|
|
103
|
+
|
|
104
|
+
- **Replace raw ANSI codes with chalk library (PRJ-132)**: Replaced ~60 raw ANSI escape codes across 7 files with chalk library calls
|
|
105
|
+
|
|
106
|
+
### Implementation Details
|
|
107
|
+
|
|
108
|
+
Replaced all raw ANSI color/formatting constants (`\x1b[32m`, `\x1b[1m`, etc.) with chalk equivalents (`chalk.green()`, `chalk.bold()`, etc.) in:
|
|
109
|
+
- `bin/prjct.ts` — version display, provider status, welcome message
|
|
110
|
+
- `core/index.ts` — version display, provider status
|
|
111
|
+
- `core/cli/start.ts` — gradient banner using `chalk.rgb()`, setup UI
|
|
112
|
+
- `core/utils/subtask-table.ts` — color palette as chalk functions, progress display
|
|
113
|
+
- `core/utils/help.ts` — all help formatting
|
|
114
|
+
- `core/workflow/workflow-preferences.ts` — hook status display
|
|
115
|
+
- `core/infrastructure/setup.ts` — installation messages
|
|
116
|
+
|
|
117
|
+
Terminal control sequences (cursor movement, hide/show) kept as raw ANSI since chalk only handles colors/formatting.
|
|
118
|
+
|
|
119
|
+
### Learnings
|
|
120
|
+
|
|
121
|
+
- `chalk.rgb(R,G,B)` replaces `\x1b[38;2;R;G;Bm` for true-color support
|
|
122
|
+
- Chalk functions can be stored as array values and called dynamically (useful for color palettes)
|
|
123
|
+
- `chalk.bold.white()` chains work for compound styling
|
|
124
|
+
- Terminal control sequences (`\x1b[?25l`, cursor movement) must stay raw — chalk doesn't handle them
|
|
125
|
+
|
|
126
|
+
### Test Plan
|
|
127
|
+
|
|
128
|
+
#### For QA
|
|
129
|
+
1. Run `prjct --version` — verify colored output with provider status
|
|
130
|
+
2. Run `prjct help` — verify formatted help with colors
|
|
131
|
+
3. Run `prjct start --force` — verify gradient banner and colored UI
|
|
132
|
+
4. Set `NO_COLOR=1` and repeat above — verify all color is suppressed
|
|
133
|
+
5. Run `bun run build && bun run typecheck` — verify zero errors
|
|
134
|
+
|
|
135
|
+
#### For Users
|
|
136
|
+
**What changed:** Terminal colors now use the chalk library instead of raw ANSI codes
|
|
137
|
+
**How to use:** No change — colors appear the same but now respect `NO_COLOR` env variable
|
|
138
|
+
**Breaking changes:** None
|
|
139
|
+
|
|
59
140
|
## [1.1.1] - 2026-02-06
|
|
60
141
|
|
|
61
142
|
### Bug Fixes
|
package/bin/prjct.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import fs from 'node:fs'
|
|
12
12
|
import os from 'node:os'
|
|
13
13
|
import path from 'node:path'
|
|
14
|
+
import chalk from 'chalk'
|
|
14
15
|
import { detectAllProviders } from '../core/infrastructure/ai-provider'
|
|
15
16
|
import configManager from '../core/infrastructure/config-manager'
|
|
16
17
|
import editorsConfig from '../core/infrastructure/editors-config'
|
|
@@ -61,12 +62,7 @@ if (isQuietMode) {
|
|
|
61
62
|
setQuietMode(true)
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
// Colors for output
|
|
65
|
-
const CYAN = '\x1b[36m'
|
|
66
|
-
const YELLOW = '\x1b[33m'
|
|
67
|
-
const DIM = '\x1b[2m'
|
|
68
|
-
const BOLD = '\x1b[1m'
|
|
69
|
-
const RESET = '\x1b[0m'
|
|
65
|
+
// Colors for output (chalk respects NO_COLOR env)
|
|
70
66
|
|
|
71
67
|
if (args[0] === 'start' || args[0] === 'setup') {
|
|
72
68
|
// Interactive setup with beautiful UI
|
|
@@ -206,52 +202,50 @@ if (args[0] === 'start' || args[0] === 'setup') {
|
|
|
206
202
|
const windsurfDetected = fs.existsSync(path.join(cwd, '.windsurf'))
|
|
207
203
|
const windsurfConfigured = fs.existsSync(path.join(cwd, '.windsurf', 'rules', 'prjct.md'))
|
|
208
204
|
|
|
209
|
-
const GREEN = '\x1b[32m'
|
|
210
|
-
|
|
211
205
|
console.log(`
|
|
212
|
-
${
|
|
213
|
-
${
|
|
206
|
+
${chalk.cyan('p/')} prjct v${VERSION}
|
|
207
|
+
${chalk.dim('Context layer for AI coding agents')}
|
|
214
208
|
|
|
215
|
-
${
|
|
209
|
+
${chalk.dim('Providers:')}`)
|
|
216
210
|
|
|
217
211
|
// Claude status
|
|
218
212
|
if (detection.claude.installed) {
|
|
219
|
-
const status = claudeConfigured ?
|
|
213
|
+
const status = claudeConfigured ? chalk.green('✓ ready') : chalk.yellow('● installed')
|
|
220
214
|
const ver = detection.claude.version ? ` (v${detection.claude.version})` : ''
|
|
221
|
-
console.log(` Claude Code ${status}${
|
|
215
|
+
console.log(` Claude Code ${status}${chalk.dim(ver)}`)
|
|
222
216
|
} else {
|
|
223
|
-
console.log(` Claude Code ${
|
|
217
|
+
console.log(` Claude Code ${chalk.dim('○ not installed')}`)
|
|
224
218
|
}
|
|
225
219
|
|
|
226
220
|
// Gemini status
|
|
227
221
|
if (detection.gemini.installed) {
|
|
228
|
-
const status = geminiConfigured ?
|
|
222
|
+
const status = geminiConfigured ? chalk.green('✓ ready') : chalk.yellow('● installed')
|
|
229
223
|
const ver = detection.gemini.version ? ` (v${detection.gemini.version})` : ''
|
|
230
|
-
console.log(` Gemini CLI ${status}${
|
|
224
|
+
console.log(` Gemini CLI ${status}${chalk.dim(ver)}`)
|
|
231
225
|
} else {
|
|
232
|
-
console.log(` Gemini CLI ${
|
|
226
|
+
console.log(` Gemini CLI ${chalk.dim('○ not installed')}`)
|
|
233
227
|
}
|
|
234
228
|
|
|
235
229
|
// Cursor status (project-level)
|
|
236
230
|
if (cursorDetected) {
|
|
237
|
-
const status = cursorConfigured ?
|
|
238
|
-
console.log(` Cursor IDE ${status}${
|
|
231
|
+
const status = cursorConfigured ? chalk.green('✓ ready') : chalk.yellow('● detected')
|
|
232
|
+
console.log(` Cursor IDE ${status}${chalk.dim(' (project)')}`)
|
|
239
233
|
} else {
|
|
240
|
-
console.log(` Cursor IDE ${
|
|
234
|
+
console.log(` Cursor IDE ${chalk.dim('○ not detected')}`)
|
|
241
235
|
}
|
|
242
236
|
|
|
243
237
|
// Windsurf status (project-level)
|
|
244
238
|
if (windsurfDetected) {
|
|
245
|
-
const status = windsurfConfigured ?
|
|
246
|
-
console.log(` Windsurf IDE ${status}${
|
|
239
|
+
const status = windsurfConfigured ? chalk.green('✓ ready') : chalk.yellow('● detected')
|
|
240
|
+
console.log(` Windsurf IDE ${status}${chalk.dim(' (project)')}`)
|
|
247
241
|
} else {
|
|
248
|
-
console.log(` Windsurf IDE ${
|
|
242
|
+
console.log(` Windsurf IDE ${chalk.dim('○ not detected')}`)
|
|
249
243
|
}
|
|
250
244
|
|
|
251
245
|
console.log(`
|
|
252
|
-
${
|
|
253
|
-
${
|
|
254
|
-
${
|
|
246
|
+
${chalk.dim("Run 'prjct start' to configure (CLI providers)")}
|
|
247
|
+
${chalk.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
|
|
248
|
+
${chalk.cyan('https://prjct.app')}
|
|
255
249
|
`)
|
|
256
250
|
} else {
|
|
257
251
|
// Check if setup has been done
|
|
@@ -261,12 +255,12 @@ ${CYAN}https://prjct.app${RESET}
|
|
|
261
255
|
if (!fs.existsSync(configPath) || !routersInstalled) {
|
|
262
256
|
// First time - prompt to run start
|
|
263
257
|
console.log(`
|
|
264
|
-
${
|
|
258
|
+
${chalk.cyan.bold(' Welcome to prjct!')}
|
|
265
259
|
|
|
266
|
-
Run ${
|
|
260
|
+
Run ${chalk.bold('prjct start')} to configure your AI providers.
|
|
267
261
|
|
|
268
|
-
${
|
|
269
|
-
Claude Code, Gemini CLI, or both
|
|
262
|
+
${chalk.dim(`This is a one-time setup that lets you choose between
|
|
263
|
+
Claude Code, Gemini CLI, or both.`)}
|
|
270
264
|
`)
|
|
271
265
|
process.exitCode = 0
|
|
272
266
|
} else {
|
|
@@ -275,7 +269,7 @@ ${CYAN}${BOLD} Welcome to prjct!${RESET}
|
|
|
275
269
|
const lastVersion = await editorsConfig.getLastVersion()
|
|
276
270
|
|
|
277
271
|
if (lastVersion && lastVersion !== VERSION) {
|
|
278
|
-
console.log(`\n${
|
|
272
|
+
console.log(`\n${chalk.yellow('ℹ')} Updating prjct v${lastVersion} → v${VERSION}...\n`)
|
|
279
273
|
|
|
280
274
|
const { default: setup } = await import('../core/infrastructure/setup')
|
|
281
275
|
await setup.run()
|
|
@@ -11,14 +11,17 @@
|
|
|
11
11
|
* Source: Devin, Cursor, Augment Code patterns
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { exec } from 'node:child_process'
|
|
15
15
|
import fs from 'node:fs/promises'
|
|
16
16
|
import os from 'node:os'
|
|
17
17
|
import path from 'node:path'
|
|
18
|
+
import { promisify } from 'node:util'
|
|
18
19
|
|
|
19
20
|
import type { GroundTruthContext, VerificationResult, Verifier } from '../types'
|
|
20
21
|
import { isNotFoundError } from '../types/fs'
|
|
21
22
|
|
|
23
|
+
const execAsync = promisify(exec)
|
|
24
|
+
|
|
22
25
|
// =============================================================================
|
|
23
26
|
// Utilities
|
|
24
27
|
// =============================================================================
|
|
@@ -163,9 +166,8 @@ export async function verifyShip(context: GroundTruthContext): Promise<Verificat
|
|
|
163
166
|
|
|
164
167
|
// 1. Check for uncommitted changes
|
|
165
168
|
try {
|
|
166
|
-
const gitStatus =
|
|
169
|
+
const { stdout: gitStatus } = await execAsync('git status --porcelain', {
|
|
167
170
|
cwd: context.projectPath,
|
|
168
|
-
encoding: 'utf-8',
|
|
169
171
|
})
|
|
170
172
|
actual.hasUncommittedChanges = gitStatus.trim().length > 0
|
|
171
173
|
actual.uncommittedFiles = gitStatus.trim().split('\n').filter(Boolean).length
|
package/core/cli/start.ts
CHANGED
|
@@ -12,46 +12,35 @@ import fs from 'node:fs'
|
|
|
12
12
|
import os from 'node:os'
|
|
13
13
|
import path from 'node:path'
|
|
14
14
|
import readline from 'node:readline'
|
|
15
|
+
import chalk from 'chalk'
|
|
15
16
|
import { detectAllProviders, Providers } from '../infrastructure/ai-provider'
|
|
16
17
|
import type { AIProviderName } from '../types/provider'
|
|
17
18
|
import { VERSION } from '../utils/version'
|
|
18
19
|
|
|
19
|
-
// Colors
|
|
20
|
-
const RESET = '\x1b[0m'
|
|
21
|
-
const BOLD = '\x1b[1m'
|
|
22
|
-
const DIM = '\x1b[2m'
|
|
23
|
-
const GREEN = '\x1b[32m'
|
|
24
|
-
const YELLOW = '\x1b[33m'
|
|
25
|
-
const _BLUE = '\x1b[34m'
|
|
26
|
-
const _MAGENTA = '\x1b[35m'
|
|
27
|
-
const CYAN = '\x1b[36m'
|
|
28
|
-
const WHITE = '\x1b[37m'
|
|
29
|
-
const _BG_BLUE = '\x1b[44m'
|
|
30
|
-
|
|
31
20
|
// True color gradient (cyan -> blue -> purple -> pink)
|
|
32
|
-
const G1 =
|
|
33
|
-
const G2 =
|
|
34
|
-
const G3 =
|
|
35
|
-
const G4 =
|
|
36
|
-
const G5 =
|
|
21
|
+
const G1 = chalk.rgb(0, 255, 255)
|
|
22
|
+
const G2 = chalk.rgb(80, 180, 255)
|
|
23
|
+
const G3 = chalk.rgb(140, 120, 255)
|
|
24
|
+
const G4 = chalk.rgb(200, 80, 220)
|
|
25
|
+
const G5 = chalk.rgb(255, 80, 180)
|
|
37
26
|
|
|
38
27
|
// Large block letters - PRJCT (7 lines tall)
|
|
39
28
|
const BANNER = `
|
|
40
29
|
|
|
41
|
-
${G1
|
|
42
|
-
${G1}
|
|
43
|
-
${G1}
|
|
44
|
-
${G1
|
|
45
|
-
${G1
|
|
46
|
-
${G1
|
|
30
|
+
${G1(' ██████╗ ')}${G2(' ██████╗ ')}${G3(' ██╗')}${G4(' ██████╗')}${G5('████████╗')}
|
|
31
|
+
${G1(' ██╔══██╗')}${G2(' ██╔══██╗')}${G3(' ██║')}${G4('██╔════╝')}${G5('╚══██╔══╝')}
|
|
32
|
+
${G1(' ██████╔╝')}${G2(' ██████╔╝')}${G3(' ██║')}${G4('██║ ')}${G5(' ██║ ')}
|
|
33
|
+
${G1(' ██╔═══╝ ')}${G2(' ██╔══██╗')}${G3('██ ██║')}${G4('██║ ')}${G5(' ██║ ')}
|
|
34
|
+
${G1(' ██║ ')}${G2(' ██║ ██║')}${G3('╚█████╔╝')}${G4('╚██████╗')}${G5(' ██║ ')}
|
|
35
|
+
${G1(' ╚═╝ ')}${G2(' ╚═╝ ╚═╝')}${G3(' ╚════╝ ')}${G4(' ╚═════╝')}${G5(' ╚═╝ ')}
|
|
47
36
|
|
|
48
37
|
`
|
|
49
38
|
|
|
50
|
-
const WELCOME_BOX = ` ${
|
|
39
|
+
const WELCOME_BOX = ` ${chalk.white('Context Layer for AI Agents')} ${chalk.dim(`v${VERSION}`)}
|
|
51
40
|
|
|
52
|
-
${
|
|
53
|
-
Works with Claude Code, Gemini CLI, and more
|
|
54
|
-
${
|
|
41
|
+
${chalk.dim(`Project context layer for AI coding agents.
|
|
42
|
+
Works with Claude Code, Gemini CLI, and more.`)}
|
|
43
|
+
${chalk.cyan('https://prjct.app')}
|
|
55
44
|
`
|
|
56
45
|
|
|
57
46
|
interface ProviderOption {
|
|
@@ -85,17 +74,14 @@ function showBanner(): void {
|
|
|
85
74
|
* Show provider selection UI
|
|
86
75
|
*/
|
|
87
76
|
function showProviderSelection(options: ProviderOption[], currentIndex: number): void {
|
|
88
|
-
console.log(`\n${
|
|
89
|
-
console.log(` ${
|
|
77
|
+
console.log(`\n${chalk.bold(' Select AI providers to configure:')}\n`)
|
|
78
|
+
console.log(` ${chalk.dim('(Use arrow keys to navigate, space to toggle, enter to confirm)')}\n`)
|
|
90
79
|
|
|
91
80
|
options.forEach((option, index) => {
|
|
92
|
-
const cursor = index === currentIndex ?
|
|
93
|
-
const checkbox = option.selected ?
|
|
94
|
-
const status = option.installed
|
|
95
|
-
|
|
96
|
-
: `${YELLOW}(will install)${RESET}`
|
|
97
|
-
const name =
|
|
98
|
-
index === currentIndex ? `${BOLD}${option.displayName}${RESET}` : option.displayName
|
|
81
|
+
const cursor = index === currentIndex ? chalk.cyan('❯') : ' '
|
|
82
|
+
const checkbox = option.selected ? chalk.green('[✓]') : chalk.dim('[ ]')
|
|
83
|
+
const status = option.installed ? chalk.green('(installed)') : chalk.yellow('(will install)')
|
|
84
|
+
const name = index === currentIndex ? chalk.bold(option.displayName) : option.displayName
|
|
99
85
|
|
|
100
86
|
console.log(` ${cursor} ${checkbox} ${name} ${status}`)
|
|
101
87
|
})
|
|
@@ -131,10 +117,10 @@ async function selectProviders(): Promise<AIProviderName[]> {
|
|
|
131
117
|
|
|
132
118
|
// Non-interactive mode: auto-select detected providers
|
|
133
119
|
if (!process.stdin.isTTY) {
|
|
134
|
-
console.log(`\n${
|
|
120
|
+
console.log(`\n${chalk.bold(' Detected providers:')}\n`)
|
|
135
121
|
options.forEach((option) => {
|
|
136
122
|
if (option.installed) {
|
|
137
|
-
console.log(` ${
|
|
123
|
+
console.log(` ${chalk.green('✓')} ${option.displayName}`)
|
|
138
124
|
}
|
|
139
125
|
})
|
|
140
126
|
console.log('')
|
|
@@ -230,7 +216,7 @@ async function installRouter(provider: AIProviderName): Promise<boolean> {
|
|
|
230
216
|
return false
|
|
231
217
|
} catch (error) {
|
|
232
218
|
console.error(
|
|
233
|
-
` ${
|
|
219
|
+
` ${chalk.yellow('⚠')} Failed to install ${provider} router: ${(error as Error).message}`
|
|
234
220
|
)
|
|
235
221
|
return false
|
|
236
222
|
}
|
|
@@ -294,7 +280,7 @@ async function installGlobalConfig(provider: AIProviderName): Promise<boolean> {
|
|
|
294
280
|
return false
|
|
295
281
|
} catch (error) {
|
|
296
282
|
console.error(
|
|
297
|
-
` ${
|
|
283
|
+
` ${chalk.yellow('⚠')} Failed to install ${provider} config: ${(error as Error).message}`
|
|
298
284
|
)
|
|
299
285
|
return false
|
|
300
286
|
}
|
|
@@ -324,27 +310,27 @@ async function saveSetupConfig(providers: AIProviderName[]): Promise<void> {
|
|
|
324
310
|
* Show completion message
|
|
325
311
|
*/
|
|
326
312
|
function showCompletion(providers: AIProviderName[]): void {
|
|
327
|
-
console.log(`\n${
|
|
313
|
+
console.log(`\n${chalk.green.bold(' ✓ Setup complete!')}\n`)
|
|
328
314
|
|
|
329
|
-
console.log(` ${
|
|
315
|
+
console.log(` ${chalk.dim('Configured providers:')}`)
|
|
330
316
|
providers.forEach((p) => {
|
|
331
317
|
const config = Providers[p]
|
|
332
|
-
console.log(` ${
|
|
318
|
+
console.log(` ${chalk.green('✓')} ${config.displayName}`)
|
|
333
319
|
})
|
|
334
320
|
|
|
335
321
|
console.log(`
|
|
336
|
-
${
|
|
322
|
+
${chalk.bold('Next steps:')}
|
|
337
323
|
|
|
338
|
-
${
|
|
339
|
-
${
|
|
340
|
-
${
|
|
324
|
+
${chalk.cyan('1.')} Navigate to your project directory
|
|
325
|
+
${chalk.cyan('2.')} Run ${chalk.bold('p. init')} to initialize prjct for that project
|
|
326
|
+
${chalk.cyan('3.')} Start tracking with ${chalk.bold('p. task "your task"')}
|
|
341
327
|
|
|
342
|
-
${
|
|
343
|
-
${
|
|
344
|
-
${
|
|
345
|
-
${
|
|
328
|
+
${chalk.dim('Tips:')}
|
|
329
|
+
${chalk.dim('•')} Use ${chalk.bold('p. sync')} to analyze your codebase
|
|
330
|
+
${chalk.dim('•')} Use ${chalk.bold('p. done')} to complete tasks
|
|
331
|
+
${chalk.dim('•')} Use ${chalk.bold('p. ship')} to create PRs
|
|
346
332
|
|
|
347
|
-
${
|
|
333
|
+
${chalk.dim('Learn more: https://prjct.app/docs')}
|
|
348
334
|
`)
|
|
349
335
|
}
|
|
350
336
|
|
|
@@ -359,8 +345,8 @@ export async function runStart(): Promise<void> {
|
|
|
359
345
|
if (fs.existsSync(configPath)) {
|
|
360
346
|
const existing = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
|
361
347
|
if (existing.version === VERSION) {
|
|
362
|
-
console.log(` ${
|
|
363
|
-
console.log(` ${
|
|
348
|
+
console.log(` ${chalk.yellow('ℹ')} Already configured for v${VERSION}`)
|
|
349
|
+
console.log(` ${chalk.dim('Run with --force to reconfigure')}\n`)
|
|
364
350
|
|
|
365
351
|
if (!process.argv.includes('--force')) {
|
|
366
352
|
return
|
|
@@ -371,22 +357,22 @@ export async function runStart(): Promise<void> {
|
|
|
371
357
|
// Select providers
|
|
372
358
|
const selectedProviders = await selectProviders()
|
|
373
359
|
|
|
374
|
-
console.log(`\n ${
|
|
360
|
+
console.log(`\n ${chalk.cyan('Setting up...')}\n`)
|
|
375
361
|
|
|
376
362
|
// Install for each selected provider
|
|
377
363
|
for (const provider of selectedProviders) {
|
|
378
364
|
const config = Providers[provider]
|
|
379
|
-
process.stdout.write(` ${
|
|
365
|
+
process.stdout.write(` ${chalk.dim('•')} ${config.displayName}... `)
|
|
380
366
|
|
|
381
367
|
const routerOk = await installRouter(provider)
|
|
382
368
|
const configOk = await installGlobalConfig(provider)
|
|
383
369
|
|
|
384
370
|
if (routerOk && configOk) {
|
|
385
|
-
console.log(
|
|
371
|
+
console.log(chalk.green('✓'))
|
|
386
372
|
} else if (routerOk || configOk) {
|
|
387
|
-
console.log(
|
|
373
|
+
console.log(chalk.yellow('partial'))
|
|
388
374
|
} else {
|
|
389
|
-
console.log(
|
|
375
|
+
console.log(chalk.yellow('skipped'))
|
|
390
376
|
}
|
|
391
377
|
}
|
|
392
378
|
|
package/core/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import './commands/register' // Ensure commands are registered
|
|
|
10
10
|
import fs from 'node:fs'
|
|
11
11
|
import os from 'node:os'
|
|
12
12
|
import path from 'node:path'
|
|
13
|
+
import chalk from 'chalk'
|
|
13
14
|
import type { CommandMeta } from './commands/registry'
|
|
14
15
|
import { detectAllProviders, detectAntigravity } from './infrastructure/ai-provider'
|
|
15
16
|
import out from './utils/output'
|
|
@@ -195,12 +196,7 @@ function parseCommandArgs(_cmd: CommandMeta, rawArgs: string[]): ParsedCommandAr
|
|
|
195
196
|
return { parsedArgs, options }
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
// Colors
|
|
199
|
-
const CYAN = '\x1b[36m'
|
|
200
|
-
const GREEN = '\x1b[32m'
|
|
201
|
-
const YELLOW = '\x1b[33m'
|
|
202
|
-
const DIM = '\x1b[2m'
|
|
203
|
-
const RESET = '\x1b[0m'
|
|
199
|
+
// Colors via chalk (respects NO_COLOR env)
|
|
204
200
|
|
|
205
201
|
/**
|
|
206
202
|
* Display version with provider status
|
|
@@ -219,53 +215,53 @@ function displayVersion(version: string): void {
|
|
|
219
215
|
const cursorExists = fs.existsSync(path.join(process.cwd(), '.cursor'))
|
|
220
216
|
|
|
221
217
|
console.log(`
|
|
222
|
-
${
|
|
223
|
-
${
|
|
218
|
+
${chalk.cyan('p/')} prjct v${version}
|
|
219
|
+
${chalk.dim('Context layer for AI coding agents')}
|
|
224
220
|
|
|
225
|
-
${
|
|
221
|
+
${chalk.dim('Providers:')}`)
|
|
226
222
|
|
|
227
223
|
// Claude status
|
|
228
224
|
if (detection.claude.installed) {
|
|
229
|
-
const status = claudeConfigured ?
|
|
225
|
+
const status = claudeConfigured ? chalk.green('✓ ready') : chalk.yellow('● installed')
|
|
230
226
|
const ver = detection.claude.version ? ` (v${detection.claude.version})` : ''
|
|
231
|
-
console.log(` Claude Code ${status}${
|
|
227
|
+
console.log(` Claude Code ${status}${chalk.dim(ver)}`)
|
|
232
228
|
} else {
|
|
233
|
-
console.log(` Claude Code ${
|
|
229
|
+
console.log(` Claude Code ${chalk.dim('○ not installed')}`)
|
|
234
230
|
}
|
|
235
231
|
|
|
236
232
|
// Gemini status
|
|
237
233
|
if (detection.gemini.installed) {
|
|
238
|
-
const status = geminiConfigured ?
|
|
234
|
+
const status = geminiConfigured ? chalk.green('✓ ready') : chalk.yellow('● installed')
|
|
239
235
|
const ver = detection.gemini.version ? ` (v${detection.gemini.version})` : ''
|
|
240
|
-
console.log(` Gemini CLI ${status}${
|
|
236
|
+
console.log(` Gemini CLI ${status}${chalk.dim(ver)}`)
|
|
241
237
|
} else {
|
|
242
|
-
console.log(` Gemini CLI ${
|
|
238
|
+
console.log(` Gemini CLI ${chalk.dim('○ not installed')}`)
|
|
243
239
|
}
|
|
244
240
|
|
|
245
241
|
// Antigravity status (global, skills-based)
|
|
246
242
|
const antigravityDetection = detectAntigravity()
|
|
247
243
|
if (antigravityDetection.installed) {
|
|
248
244
|
const status = antigravityDetection.skillInstalled
|
|
249
|
-
?
|
|
250
|
-
:
|
|
251
|
-
const hint = antigravityDetection.skillInstalled ? '' : ` ${
|
|
245
|
+
? chalk.green('✓ ready')
|
|
246
|
+
: chalk.yellow('● detected')
|
|
247
|
+
const hint = antigravityDetection.skillInstalled ? '' : ` ${chalk.dim('(run prjct start)')}`
|
|
252
248
|
console.log(` Antigravity ${status}${hint}`)
|
|
253
249
|
} else {
|
|
254
|
-
console.log(` Antigravity ${
|
|
250
|
+
console.log(` Antigravity ${chalk.dim('○ not installed')}`)
|
|
255
251
|
}
|
|
256
252
|
|
|
257
253
|
// Cursor status (project-level, but shown in same format)
|
|
258
254
|
if (cursorConfigured) {
|
|
259
|
-
console.log(` Cursor IDE ${
|
|
255
|
+
console.log(` Cursor IDE ${chalk.green('✓ ready')} ${chalk.dim('(use /sync, /task)')}`)
|
|
260
256
|
} else if (cursorExists) {
|
|
261
|
-
console.log(` Cursor IDE ${
|
|
257
|
+
console.log(` Cursor IDE ${chalk.yellow('● detected')} ${chalk.dim('(run prjct init)')}`)
|
|
262
258
|
} else {
|
|
263
|
-
console.log(` Cursor IDE ${
|
|
259
|
+
console.log(` Cursor IDE ${chalk.dim('○ no .cursor/ folder')}`)
|
|
264
260
|
}
|
|
265
261
|
|
|
266
262
|
console.log(`
|
|
267
|
-
${
|
|
268
|
-
${
|
|
263
|
+
${chalk.dim("Run 'prjct start' for Claude/Gemini, 'prjct init' for Cursor")}
|
|
264
|
+
${chalk.cyan('https://prjct.app')}
|
|
269
265
|
`)
|
|
270
266
|
}
|
|
271
267
|
|