prjct-cli 0.44.1 → 0.45.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/CHANGELOG.md +114 -0
- package/bin/prjct.ts +131 -10
- package/core/__tests__/agentic/memory-system.test.ts +39 -26
- package/core/__tests__/agentic/plan-mode.test.ts +64 -46
- package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
- package/core/__tests__/services/project-index.test.ts +353 -0
- package/core/__tests__/types/fs.test.ts +3 -3
- package/core/__tests__/utils/date-helper.test.ts +10 -10
- package/core/__tests__/utils/output.test.ts +9 -6
- package/core/__tests__/utils/project-commands.test.ts +5 -6
- package/core/agentic/agent-router.ts +9 -10
- package/core/agentic/chain-of-thought.ts +16 -4
- package/core/agentic/command-executor.ts +66 -40
- package/core/agentic/context-builder.ts +8 -5
- package/core/agentic/ground-truth.ts +15 -9
- package/core/agentic/index.ts +145 -152
- package/core/agentic/loop-detector.ts +40 -11
- package/core/agentic/memory-system.ts +98 -35
- package/core/agentic/orchestrator-executor.ts +135 -71
- package/core/agentic/plan-mode.ts +46 -16
- package/core/agentic/prompt-builder.ts +108 -42
- package/core/agentic/services.ts +10 -9
- package/core/agentic/skill-loader.ts +9 -15
- package/core/agentic/smart-context.ts +129 -79
- package/core/agentic/template-executor.ts +13 -12
- package/core/agentic/template-loader.ts +7 -4
- package/core/agentic/tool-registry.ts +16 -13
- package/core/agents/index.ts +1 -1
- package/core/agents/performance.ts +10 -27
- package/core/ai-tools/formatters.ts +8 -6
- package/core/ai-tools/generator.ts +4 -4
- package/core/ai-tools/index.ts +1 -1
- package/core/ai-tools/registry.ts +21 -11
- package/core/bus/bus.ts +23 -16
- package/core/bus/index.ts +2 -2
- package/core/cli/linear.ts +3 -5
- package/core/cli/start.ts +28 -25
- package/core/commands/analysis.ts +287 -29
- package/core/commands/analytics.ts +52 -44
- package/core/commands/base.ts +15 -13
- package/core/commands/cleanup.ts +6 -13
- package/core/commands/command-data.ts +49 -8
- package/core/commands/commands.ts +60 -23
- package/core/commands/context.ts +4 -4
- package/core/commands/design.ts +3 -10
- package/core/commands/index.ts +5 -8
- package/core/commands/maintenance.ts +7 -4
- package/core/commands/planning.ts +179 -56
- package/core/commands/register.ts +14 -9
- package/core/commands/registry.ts +15 -14
- package/core/commands/setup.ts +26 -14
- package/core/commands/shipping.ts +11 -16
- package/core/commands/snapshots.ts +16 -32
- package/core/commands/uninstall.ts +541 -0
- package/core/commands/workflow.ts +24 -28
- package/core/constants/index.ts +10 -22
- package/core/context/generator.ts +82 -33
- package/core/context-tools/files-tool.ts +583 -0
- package/core/context-tools/imports-tool.ts +403 -0
- package/core/context-tools/index.ts +433 -0
- package/core/context-tools/recent-tool.ts +307 -0
- package/core/context-tools/signatures-tool.ts +501 -0
- package/core/context-tools/summary-tool.ts +307 -0
- package/core/context-tools/token-counter.ts +284 -0
- package/core/context-tools/types.ts +253 -0
- package/core/domain/agent-generator.ts +7 -5
- package/core/domain/agent-loader.ts +2 -2
- package/core/domain/analyzer.ts +19 -16
- package/core/domain/architecture-generator.ts +6 -3
- package/core/domain/context-estimator.ts +3 -4
- package/core/domain/snapshot-manager.ts +25 -22
- package/core/domain/task-stack.ts +24 -14
- package/core/errors.ts +1 -1
- package/core/events/events.ts +2 -4
- package/core/events/index.ts +1 -2
- package/core/index.ts +28 -12
- package/core/infrastructure/agent-detector.ts +3 -3
- package/core/infrastructure/ai-provider.ts +23 -20
- package/core/infrastructure/author-detector.ts +16 -10
- package/core/infrastructure/capability-installer.ts +2 -2
- package/core/infrastructure/claude-agent.ts +6 -6
- package/core/infrastructure/command-installer.ts +22 -17
- package/core/infrastructure/config-manager.ts +18 -14
- package/core/infrastructure/editors-config.ts +8 -4
- package/core/infrastructure/path-manager.ts +8 -6
- package/core/infrastructure/permission-manager.ts +20 -17
- package/core/infrastructure/setup.ts +42 -38
- package/core/infrastructure/update-checker.ts +5 -5
- package/core/integrations/issue-tracker/enricher.ts +8 -19
- package/core/integrations/issue-tracker/index.ts +2 -2
- package/core/integrations/issue-tracker/manager.ts +15 -15
- package/core/integrations/issue-tracker/types.ts +5 -22
- package/core/integrations/jira/client.ts +67 -59
- package/core/integrations/jira/index.ts +11 -14
- package/core/integrations/jira/mcp-adapter.ts +5 -10
- package/core/integrations/jira/service.ts +10 -10
- package/core/integrations/linear/client.ts +27 -18
- package/core/integrations/linear/index.ts +9 -12
- package/core/integrations/linear/service.ts +11 -11
- package/core/integrations/linear/sync.ts +8 -8
- package/core/outcomes/analyzer.ts +5 -18
- package/core/outcomes/index.ts +2 -2
- package/core/outcomes/recorder.ts +3 -3
- package/core/plugin/builtin/webhook.ts +19 -15
- package/core/plugin/hooks.ts +29 -21
- package/core/plugin/index.ts +7 -7
- package/core/plugin/loader.ts +19 -19
- package/core/plugin/registry.ts +12 -23
- package/core/schemas/agents.ts +1 -1
- package/core/schemas/analysis.ts +1 -1
- package/core/schemas/enriched-task.ts +62 -49
- package/core/schemas/ideas.ts +13 -13
- package/core/schemas/index.ts +17 -27
- package/core/schemas/issues.ts +40 -25
- package/core/schemas/metrics.ts +143 -0
- package/core/schemas/outcomes.ts +70 -62
- package/core/schemas/permissions.ts +15 -12
- package/core/schemas/prd.ts +27 -14
- package/core/schemas/project.ts +3 -3
- package/core/schemas/roadmap.ts +47 -34
- package/core/schemas/schemas.ts +3 -4
- package/core/schemas/shipped.ts +3 -3
- package/core/schemas/state.ts +43 -29
- package/core/server/index.ts +5 -6
- package/core/server/routes-extended.ts +68 -72
- package/core/server/routes.ts +3 -3
- package/core/server/server.ts +31 -26
- package/core/services/agent-generator.ts +237 -0
- package/core/services/agent-service.ts +2 -2
- package/core/services/breakdown-service.ts +2 -4
- package/core/services/context-generator.ts +299 -0
- package/core/services/context-selector.ts +420 -0
- package/core/services/doctor-service.ts +426 -0
- package/core/services/file-categorizer.ts +448 -0
- package/core/services/file-scorer.ts +270 -0
- package/core/services/git-analyzer.ts +267 -0
- package/core/services/index.ts +27 -10
- package/core/services/memory-service.ts +3 -4
- package/core/services/project-index.ts +911 -0
- package/core/services/project-service.ts +4 -4
- package/core/services/skill-installer.ts +14 -17
- package/core/services/skill-lock.ts +3 -3
- package/core/services/skill-service.ts +12 -6
- package/core/services/stack-detector.ts +245 -0
- package/core/services/sync-service.ts +170 -329
- package/core/services/watch-service.ts +294 -0
- package/core/session/compaction.ts +23 -31
- package/core/session/index.ts +11 -5
- package/core/session/log-migration.ts +3 -3
- package/core/session/metrics.ts +19 -14
- package/core/session/session-log-manager.ts +12 -17
- package/core/session/task-session-manager.ts +25 -25
- package/core/session/utils.ts +1 -1
- package/core/storage/ideas-storage.ts +41 -57
- package/core/storage/index-storage.ts +514 -0
- package/core/storage/index.ts +41 -13
- package/core/storage/metrics-storage.ts +320 -0
- package/core/storage/queue-storage.ts +35 -45
- package/core/storage/shipped-storage.ts +17 -20
- package/core/storage/state-storage.ts +50 -30
- package/core/storage/storage-manager.ts +6 -6
- package/core/storage/storage.ts +18 -15
- package/core/sync/auth-config.ts +3 -3
- package/core/sync/index.ts +13 -19
- package/core/sync/oauth-handler.ts +3 -3
- package/core/sync/sync-client.ts +4 -9
- package/core/sync/sync-manager.ts +12 -14
- package/core/types/commands.ts +42 -7
- package/core/types/index.ts +284 -302
- package/core/types/integrations.ts +3 -3
- package/core/types/storage.ts +49 -0
- package/core/types/utils.ts +3 -3
- package/core/utils/agent-stream.ts +3 -1
- package/core/utils/animations.ts +14 -11
- package/core/utils/branding.ts +7 -7
- package/core/utils/cache.ts +1 -3
- package/core/utils/collection-filters.ts +3 -15
- package/core/utils/date-helper.ts +2 -7
- package/core/utils/file-helper.ts +13 -8
- package/core/utils/jsonl-helper.ts +13 -10
- package/core/utils/keychain.ts +4 -8
- package/core/utils/logger.ts +1 -1
- package/core/utils/next-steps.ts +3 -3
- package/core/utils/output.ts +58 -11
- package/core/utils/project-commands.ts +6 -6
- package/core/utils/project-credentials.ts +5 -12
- package/core/utils/runtime.ts +2 -2
- package/core/utils/session-helper.ts +3 -4
- package/core/utils/version.ts +3 -3
- package/core/wizard/index.ts +13 -0
- package/core/wizard/onboarding.ts +633 -0
- package/core/workflow/state-machine.ts +7 -7
- package/dist/bin/prjct.mjs +18907 -13189
- package/dist/core/infrastructure/command-installer.js +96 -111
- package/dist/core/infrastructure/editors-config.js +6 -6
- package/dist/core/infrastructure/setup.js +256 -257
- package/dist/core/utils/version.js +9 -9
- package/package.json +11 -12
- package/scripts/build.js +3 -3
- package/scripts/postinstall.js +2 -2
- package/templates/mcp-config.json +6 -1
- package/templates/permissions/permissive.jsonc +1 -1
- package/templates/permissions/strict.jsonc +5 -9
- package/templates/global/docs/agents.md +0 -88
- package/templates/global/docs/architecture.md +0 -103
- package/templates/global/docs/commands.md +0 -96
- package/templates/global/docs/validation.md +0 -95
package/core/index.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
import { PrjctCommands } from './commands/index'
|
|
8
8
|
import { commandRegistry } from './commands/registry'
|
|
9
9
|
import './commands/register' // Ensure commands are registered
|
|
10
|
-
import
|
|
10
|
+
import fs from 'node:fs'
|
|
11
|
+
import os from 'node:os'
|
|
12
|
+
import path from 'node:path'
|
|
11
13
|
import type { CommandMeta } from './commands/registry'
|
|
12
|
-
import { detectAllProviders, detectAntigravity
|
|
13
|
-
import
|
|
14
|
-
import path from 'path'
|
|
15
|
-
import os from 'os'
|
|
14
|
+
import { detectAllProviders, detectAntigravity } from './infrastructure/ai-provider'
|
|
15
|
+
import out from './utils/output'
|
|
16
16
|
|
|
17
17
|
interface ParsedCommandArgs {
|
|
18
18
|
parsedArgs: string[]
|
|
@@ -111,6 +111,11 @@ async function main(): Promise<void> {
|
|
|
111
111
|
ship: (p) => commands.ship(p),
|
|
112
112
|
// Analytics
|
|
113
113
|
dash: (p) => commands.dash(p || 'default'),
|
|
114
|
+
stats: () =>
|
|
115
|
+
commands.stats(process.cwd(), {
|
|
116
|
+
json: options.json === true,
|
|
117
|
+
export: options.export === true,
|
|
118
|
+
}),
|
|
114
119
|
help: (p) => commands.help(p || ''),
|
|
115
120
|
// Maintenance
|
|
116
121
|
recover: () => commands.recover(),
|
|
@@ -118,9 +123,10 @@ async function main(): Promise<void> {
|
|
|
118
123
|
redo: () => commands.redo(),
|
|
119
124
|
history: () => commands.history(),
|
|
120
125
|
// Setup
|
|
121
|
-
sync: () =>
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
sync: () =>
|
|
127
|
+
commands.sync(process.cwd(), {
|
|
128
|
+
aiTools: options.agents ? String(options.agents).split(',') : undefined,
|
|
129
|
+
}),
|
|
124
130
|
start: () => commands.start(),
|
|
125
131
|
// Context (for Claude templates)
|
|
126
132
|
context: (p) => commands.context(p),
|
|
@@ -135,13 +141,13 @@ async function main(): Promise<void> {
|
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
// 7. Display result
|
|
138
|
-
if (result
|
|
144
|
+
if (result?.message) {
|
|
139
145
|
console.log(result.message)
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
// Show branding footer
|
|
143
149
|
out.end()
|
|
144
|
-
process.exit(result
|
|
150
|
+
process.exit(result?.success ? 0 : 1)
|
|
145
151
|
} catch (error) {
|
|
146
152
|
console.error('Error:', (error as Error).message)
|
|
147
153
|
if (process.env.DEBUG) {
|
|
@@ -156,7 +162,7 @@ async function main(): Promise<void> {
|
|
|
156
162
|
/**
|
|
157
163
|
* Parse command arguments dynamically
|
|
158
164
|
*/
|
|
159
|
-
function parseCommandArgs(
|
|
165
|
+
function parseCommandArgs(_cmd: CommandMeta, rawArgs: string[]): ParsedCommandArgs {
|
|
160
166
|
const parsedArgs: string[] = []
|
|
161
167
|
const options: Record<string, string | boolean> = {}
|
|
162
168
|
|
|
@@ -231,7 +237,9 @@ ${DIM}Providers:${RESET}`)
|
|
|
231
237
|
// Antigravity status (global, skills-based)
|
|
232
238
|
const antigravityDetection = detectAntigravity()
|
|
233
239
|
if (antigravityDetection.installed) {
|
|
234
|
-
const status = antigravityDetection.skillInstalled
|
|
240
|
+
const status = antigravityDetection.skillInstalled
|
|
241
|
+
? `${GREEN}✓ ready${RESET}`
|
|
242
|
+
: `${YELLOW}● detected${RESET}`
|
|
235
243
|
const hint = antigravityDetection.skillInstalled ? '' : ` ${DIM}(run prjct start)${RESET}`
|
|
236
244
|
console.log(` Antigravity ${status}${hint}`)
|
|
237
245
|
} else {
|
|
@@ -289,6 +297,8 @@ TERMINAL COMMANDS (this CLI)
|
|
|
289
297
|
prjct init Initialize project (required for Cursor)
|
|
290
298
|
prjct setup Reconfigure installations
|
|
291
299
|
prjct sync Sync project state
|
|
300
|
+
prjct watch Auto-sync on file changes (Ctrl+C to stop)
|
|
301
|
+
prjct doctor Check system health and dependencies
|
|
292
302
|
|
|
293
303
|
EXAMPLES
|
|
294
304
|
--------
|
|
@@ -303,6 +313,12 @@ EXAMPLES
|
|
|
303
313
|
> /sync
|
|
304
314
|
> /task "add user authentication"
|
|
305
315
|
|
|
316
|
+
FLAGS
|
|
317
|
+
-----
|
|
318
|
+
--quiet, -q Suppress all output (only errors to stderr)
|
|
319
|
+
--version, -v Show version
|
|
320
|
+
--help, -h Show this help
|
|
321
|
+
|
|
306
322
|
MORE INFO
|
|
307
323
|
---------
|
|
308
324
|
Documentation: https://prjct.app
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* @module infrastructure/agent-detector
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import fs from 'fs'
|
|
9
|
-
import path from 'path'
|
|
8
|
+
import fs from 'node:fs'
|
|
9
|
+
import path from 'node:path'
|
|
10
10
|
import type { DetectedAgent } from '../types'
|
|
11
11
|
|
|
12
12
|
declare const global: typeof globalThis & {
|
|
@@ -144,5 +144,5 @@ export default {
|
|
|
144
144
|
setAgent,
|
|
145
145
|
reset,
|
|
146
146
|
isClaude,
|
|
147
|
-
isTerminal
|
|
147
|
+
isTerminal,
|
|
148
148
|
}
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
* @see https://docs.windsurf.com/windsurf/cascade/memories
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { execSync } from 'child_process'
|
|
21
|
-
import fs from 'fs'
|
|
22
|
-
import
|
|
23
|
-
import
|
|
20
|
+
import { execSync } from 'node:child_process'
|
|
21
|
+
import fs from 'node:fs'
|
|
22
|
+
import os from 'node:os'
|
|
23
|
+
import path from 'node:path'
|
|
24
24
|
import type {
|
|
25
|
-
AIProviderName,
|
|
26
25
|
AIProviderConfig,
|
|
26
|
+
AIProviderName,
|
|
27
|
+
CursorProjectDetection,
|
|
28
|
+
ProviderBranding,
|
|
27
29
|
ProviderDetectionResult,
|
|
28
30
|
ProviderSelectionResult,
|
|
29
|
-
ProviderBranding,
|
|
30
|
-
CursorProjectDetection,
|
|
31
31
|
WindsurfProjectDetection,
|
|
32
32
|
} from '../types/provider'
|
|
33
33
|
|
|
@@ -110,17 +110,17 @@ export const AntigravityProvider: AIProviderConfig = {
|
|
|
110
110
|
export const CursorProvider: AIProviderConfig = {
|
|
111
111
|
name: 'cursor',
|
|
112
112
|
displayName: 'Cursor IDE',
|
|
113
|
-
cliCommand: null,
|
|
114
|
-
configDir: null,
|
|
115
|
-
contextFile: 'prjct.mdc',
|
|
116
|
-
skillsDir: null,
|
|
113
|
+
cliCommand: null, // Not a CLI - GUI app
|
|
114
|
+
configDir: null, // No global config directory
|
|
115
|
+
contextFile: 'prjct.mdc', // Uses .mdc format with frontmatter
|
|
116
|
+
skillsDir: null, // No skills directory
|
|
117
117
|
commandsDir: '.cursor/commands',
|
|
118
|
-
rulesDir: '.cursor/rules',
|
|
118
|
+
rulesDir: '.cursor/rules', // Cursor-specific: rules directory
|
|
119
119
|
commandFormat: 'md',
|
|
120
120
|
settingsFile: null,
|
|
121
121
|
projectSettingsFile: null,
|
|
122
122
|
ignoreFile: '.cursorignore',
|
|
123
|
-
isProjectLevel: true,
|
|
123
|
+
isProjectLevel: true, // Config is project-level only
|
|
124
124
|
websiteUrl: 'https://cursor.com',
|
|
125
125
|
docsUrl: 'https://cursor.com/docs',
|
|
126
126
|
}
|
|
@@ -140,17 +140,17 @@ export const CursorProvider: AIProviderConfig = {
|
|
|
140
140
|
export const WindsurfProvider: AIProviderConfig = {
|
|
141
141
|
name: 'windsurf',
|
|
142
142
|
displayName: 'Windsurf IDE',
|
|
143
|
-
cliCommand: null,
|
|
144
|
-
configDir: null,
|
|
145
|
-
contextFile: 'prjct.md',
|
|
146
|
-
skillsDir: null,
|
|
147
|
-
commandsDir: '.windsurf/workflows',
|
|
143
|
+
cliCommand: null, // Not a CLI - GUI app
|
|
144
|
+
configDir: null, // No global config directory
|
|
145
|
+
contextFile: 'prjct.md', // Uses .md format (not .mdc)
|
|
146
|
+
skillsDir: null, // No skills directory
|
|
147
|
+
commandsDir: '.windsurf/workflows', // Windsurf uses "workflows" not "commands"
|
|
148
148
|
rulesDir: '.windsurf/rules',
|
|
149
149
|
commandFormat: 'md',
|
|
150
150
|
settingsFile: null,
|
|
151
151
|
projectSettingsFile: null,
|
|
152
152
|
ignoreFile: '.windsurfignore',
|
|
153
|
-
isProjectLevel: true,
|
|
153
|
+
isProjectLevel: true, // Config is project-level only
|
|
154
154
|
websiteUrl: 'https://windsurf.com',
|
|
155
155
|
docsUrl: 'https://docs.windsurf.com',
|
|
156
156
|
}
|
|
@@ -227,7 +227,10 @@ export function detectProvider(provider: AIProviderName): ProviderDetectionResul
|
|
|
227
227
|
* Detect all available CLI-based providers
|
|
228
228
|
* Note: Cursor detection is project-level, use detectCursorProject() separately
|
|
229
229
|
*/
|
|
230
|
-
export function detectAllProviders(): {
|
|
230
|
+
export function detectAllProviders(): {
|
|
231
|
+
claude: ProviderDetectionResult
|
|
232
|
+
gemini: ProviderDetectionResult
|
|
233
|
+
} {
|
|
231
234
|
return {
|
|
232
235
|
claude: detectProvider('claude'),
|
|
233
236
|
gemini: detectProvider('gemini'),
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* @module infrastructure/author-detector
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import type {
|
|
12
|
+
import { exec as execCallback } from 'node:child_process'
|
|
13
|
+
import { promisify } from 'node:util'
|
|
14
|
+
import type { AuthorConfigStatus, DetectedAuthorInfo } from '../types'
|
|
15
15
|
|
|
16
16
|
const exec = promisify(execCallback)
|
|
17
17
|
|
|
@@ -52,13 +52,13 @@ export async function detect(): Promise<DetectedAuthorInfo> {
|
|
|
52
52
|
const [github, name, email] = await Promise.all([
|
|
53
53
|
detectGitHubUsername(),
|
|
54
54
|
detectGitName(),
|
|
55
|
-
detectGitEmail()
|
|
55
|
+
detectGitEmail(),
|
|
56
56
|
])
|
|
57
57
|
|
|
58
58
|
return {
|
|
59
59
|
github,
|
|
60
60
|
email,
|
|
61
|
-
name: name || github || 'Unknown'
|
|
61
|
+
name: name || github || 'Unknown',
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -83,7 +83,7 @@ export async function getConfigStatus(): Promise<AuthorConfigStatus> {
|
|
|
83
83
|
const [hasGitHub, hasGit, author] = await Promise.all([
|
|
84
84
|
isGitHubCLIAvailable(),
|
|
85
85
|
isGitConfigured(),
|
|
86
|
-
detect()
|
|
86
|
+
detect(),
|
|
87
87
|
])
|
|
88
88
|
|
|
89
89
|
return {
|
|
@@ -91,15 +91,21 @@ export async function getConfigStatus(): Promise<AuthorConfigStatus> {
|
|
|
91
91
|
hasGit,
|
|
92
92
|
author,
|
|
93
93
|
isComplete: !!(author.github || (author.name !== 'Unknown' && author.email)),
|
|
94
|
-
recommendations: getRecommendations(hasGitHub, hasGit, author)
|
|
94
|
+
recommendations: getRecommendations(hasGitHub, hasGit, author),
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
function getRecommendations(
|
|
98
|
+
function getRecommendations(
|
|
99
|
+
hasGitHub: boolean,
|
|
100
|
+
hasGit: boolean,
|
|
101
|
+
author: DetectedAuthorInfo
|
|
102
|
+
): string[] {
|
|
99
103
|
const recommendations: string[] = []
|
|
100
104
|
|
|
101
105
|
if (!hasGitHub && !author.github) {
|
|
102
|
-
recommendations.push(
|
|
106
|
+
recommendations.push(
|
|
107
|
+
'Install GitHub CLI (gh) for better collaboration support: https://cli.github.com/'
|
|
108
|
+
)
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
if (!hasGit) {
|
|
@@ -137,5 +143,5 @@ export default {
|
|
|
137
143
|
isGitHubCLIAvailable,
|
|
138
144
|
isGitConfigured,
|
|
139
145
|
getConfigStatus,
|
|
140
|
-
formatAuthor
|
|
146
|
+
formatAuthor,
|
|
141
147
|
}
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* Configuration should be template-driven, not code-driven.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { exec } from 'child_process'
|
|
12
|
-
import { promisify } from 'util'
|
|
11
|
+
import { exec } from 'node:child_process'
|
|
12
|
+
import { promisify } from 'node:util'
|
|
13
13
|
|
|
14
14
|
const execAsync = promisify(exec)
|
|
15
15
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Implements prjct commands for Claude Code environment
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import fs from 'fs/promises'
|
|
6
|
+
import fs from 'node:fs/promises'
|
|
7
7
|
import { isNotFoundError } from '../types/fs'
|
|
8
8
|
|
|
9
9
|
declare const global: typeof globalThis & {
|
|
@@ -71,7 +71,7 @@ class ClaudeAgent {
|
|
|
71
71
|
*/
|
|
72
72
|
async readFile(filePath: string): Promise<string> {
|
|
73
73
|
try {
|
|
74
|
-
if (global.mcp
|
|
74
|
+
if (global.mcp?.filesystem) {
|
|
75
75
|
return await global.mcp.filesystem.read(filePath)
|
|
76
76
|
}
|
|
77
77
|
} catch (_error) {
|
|
@@ -86,7 +86,7 @@ class ClaudeAgent {
|
|
|
86
86
|
*/
|
|
87
87
|
async writeFile(filePath: string, content: string): Promise<void> {
|
|
88
88
|
try {
|
|
89
|
-
if (global.mcp
|
|
89
|
+
if (global.mcp?.filesystem) {
|
|
90
90
|
return await global.mcp.filesystem.write(filePath, content)
|
|
91
91
|
}
|
|
92
92
|
} catch (_error) {
|
|
@@ -101,7 +101,7 @@ class ClaudeAgent {
|
|
|
101
101
|
*/
|
|
102
102
|
async listDirectory(dirPath: string): Promise<string[]> {
|
|
103
103
|
try {
|
|
104
|
-
if (global.mcp
|
|
104
|
+
if (global.mcp?.filesystem) {
|
|
105
105
|
return await global.mcp.filesystem.list(dirPath)
|
|
106
106
|
}
|
|
107
107
|
} catch (_error) {
|
|
@@ -148,7 +148,7 @@ class ClaudeAgent {
|
|
|
148
148
|
return '📋 No tasks queued'
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
return
|
|
151
|
+
return `📋 Queue:\n${tasks.map((t, i) => `${i + 1}. ${t}`).join('\n')}`
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
@@ -161,7 +161,7 @@ class ClaudeAgent {
|
|
|
161
161
|
🚀 Shipped: ${data.shippedCount}
|
|
162
162
|
📝 Queue: ${data.queuedCount}
|
|
163
163
|
💡 Ideas: ${data.ideasCount}
|
|
164
|
-
${data.recentActivity ?
|
|
164
|
+
${data.recentActivity ? `\n${data.recentActivity}` : ''}`
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/**
|
|
@@ -12,18 +12,18 @@
|
|
|
12
12
|
* @version 0.6.0 - Multi-provider support
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import fs from 'fs/promises'
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import { getPackageRoot } from '../utils/version'
|
|
19
|
-
import { isNotFoundError } from '../types/fs'
|
|
15
|
+
import fs from 'node:fs/promises'
|
|
16
|
+
import os from 'node:os'
|
|
17
|
+
import path from 'node:path'
|
|
20
18
|
import type {
|
|
21
|
-
InstallResult,
|
|
22
|
-
UninstallResult,
|
|
23
19
|
CheckResult,
|
|
24
|
-
SyncResult,
|
|
25
20
|
GlobalConfigResult,
|
|
21
|
+
InstallResult,
|
|
22
|
+
SyncResult,
|
|
23
|
+
UninstallResult,
|
|
26
24
|
} from '../types'
|
|
25
|
+
import { isNotFoundError } from '../types/fs'
|
|
26
|
+
import { getPackageRoot } from '../utils/version'
|
|
27
27
|
|
|
28
28
|
// =============================================================================
|
|
29
29
|
// Global Config
|
|
@@ -82,13 +82,18 @@ export async function installGlobalConfig(): Promise<GlobalConfigResult> {
|
|
|
82
82
|
await fs.mkdir(activeProvider.configDir, { recursive: true })
|
|
83
83
|
|
|
84
84
|
const globalConfigPath = path.join(activeProvider.configDir, activeProvider.contextFile)
|
|
85
|
-
const templatePath = path.join(
|
|
85
|
+
const templatePath = path.join(
|
|
86
|
+
getPackageRoot(),
|
|
87
|
+
'templates',
|
|
88
|
+
'global',
|
|
89
|
+
activeProvider.contextFile
|
|
90
|
+
)
|
|
86
91
|
|
|
87
92
|
// Read template content
|
|
88
93
|
let templateContent = ''
|
|
89
94
|
try {
|
|
90
95
|
templateContent = await fs.readFile(templatePath, 'utf-8')
|
|
91
|
-
} catch (
|
|
96
|
+
} catch (_error) {
|
|
92
97
|
// Fallback if provider-specific template not found
|
|
93
98
|
const fallbackTemplatePath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
|
|
94
99
|
templateContent = await fs.readFile(fallbackTemplatePath, 'utf-8')
|
|
@@ -133,7 +138,7 @@ export async function installGlobalConfig(): Promise<GlobalConfigResult> {
|
|
|
133
138
|
|
|
134
139
|
if (!hasMarkers) {
|
|
135
140
|
// No markers - append prjct section at the end
|
|
136
|
-
const updatedContent = existingContent
|
|
141
|
+
const updatedContent = `${existingContent}\n\n${templateContent}`
|
|
137
142
|
await fs.writeFile(globalConfigPath, updatedContent, 'utf-8')
|
|
138
143
|
return {
|
|
139
144
|
success: true,
|
|
@@ -183,10 +188,10 @@ export class CommandInstaller {
|
|
|
183
188
|
|
|
184
189
|
constructor() {
|
|
185
190
|
this.homeDir = os.homedir()
|
|
186
|
-
|
|
191
|
+
|
|
187
192
|
const aiProvider = require('./ai-provider')
|
|
188
193
|
const activeProvider = aiProvider.getActiveProvider()
|
|
189
|
-
|
|
194
|
+
|
|
190
195
|
// Command paths are provider-specific
|
|
191
196
|
if (activeProvider.name === 'gemini') {
|
|
192
197
|
this.claudeCommandsPath = path.join(activeProvider.configDir, 'commands')
|
|
@@ -194,7 +199,7 @@ export class CommandInstaller {
|
|
|
194
199
|
// Claude: Commands are in p/ subdirectory to avoid cluttering commands/
|
|
195
200
|
this.claudeCommandsPath = path.join(activeProvider.configDir, 'commands', 'p')
|
|
196
201
|
}
|
|
197
|
-
|
|
202
|
+
|
|
198
203
|
this.claudeConfigPath = activeProvider.configDir
|
|
199
204
|
this.templatesDir = path.join(getPackageRoot(), 'templates', 'commands')
|
|
200
205
|
}
|
|
@@ -228,7 +233,7 @@ export class CommandInstaller {
|
|
|
228
233
|
try {
|
|
229
234
|
const files = await fs.readdir(this.templatesDir)
|
|
230
235
|
return files.filter((f) => f.endsWith('.md'))
|
|
231
|
-
} catch (
|
|
236
|
+
} catch (_error) {
|
|
232
237
|
// Fallback to core commands if template directory not accessible (ENOENT or other)
|
|
233
238
|
return [
|
|
234
239
|
'init.md',
|
|
@@ -332,7 +337,7 @@ export class CommandInstaller {
|
|
|
332
337
|
// Try to remove the /p directory if empty
|
|
333
338
|
try {
|
|
334
339
|
await fs.rmdir(this.claudeCommandsPath)
|
|
335
|
-
} catch (
|
|
340
|
+
} catch (_error) {
|
|
336
341
|
// Directory not empty or doesn't exist - that's fine (ENOTEMPTY or ENOENT)
|
|
337
342
|
}
|
|
338
343
|
|
|
@@ -438,7 +443,7 @@ export class CommandInstaller {
|
|
|
438
443
|
const aiProvider = require('./ai-provider')
|
|
439
444
|
const activeProvider = aiProvider.getActiveProvider()
|
|
440
445
|
const routerFile = activeProvider.name === 'gemini' ? 'p.toml' : 'p.md'
|
|
441
|
-
|
|
446
|
+
|
|
442
447
|
try {
|
|
443
448
|
const routerSource = path.join(this.templatesDir, routerFile)
|
|
444
449
|
const routerDest = path.join(activeProvider.configDir, 'commands', routerFile)
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
* @version 0.3.0
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import fs from 'fs/promises'
|
|
14
|
-
import path from 'path'
|
|
13
|
+
import fs from 'node:fs/promises'
|
|
14
|
+
import path from 'node:path'
|
|
15
15
|
import * as jsonc from 'jsonc-parser'
|
|
16
|
-
import pathManager from './path-manager'
|
|
17
|
-
import authorDetector from './author-detector'
|
|
18
|
-
import { VERSION } from '../utils/version'
|
|
19
|
-
import { getTimestamp } from '../utils/date-helper'
|
|
20
16
|
import { getErrorMessage } from '../errors'
|
|
17
|
+
import type { Author, GlobalConfig, LocalConfig } from '../types'
|
|
21
18
|
import { isNotFoundError } from '../types/fs'
|
|
22
|
-
import
|
|
19
|
+
import { getTimestamp } from '../utils/date-helper'
|
|
20
|
+
import { VERSION } from '../utils/version'
|
|
21
|
+
import authorDetector from './author-detector'
|
|
22
|
+
import pathManager from './path-manager'
|
|
23
23
|
|
|
24
24
|
// Re-export types for convenience
|
|
25
|
-
export type { Author,
|
|
25
|
+
export type { Author, GlobalConfig, LocalConfig } from '../types'
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Parse JSON or JSONC content safely
|
|
@@ -36,7 +36,9 @@ function parseJsonc<T>(content: string): T {
|
|
|
36
36
|
})
|
|
37
37
|
if (errors.length > 0) {
|
|
38
38
|
const firstError = errors[0]
|
|
39
|
-
throw new SyntaxError(
|
|
39
|
+
throw new SyntaxError(
|
|
40
|
+
`JSON parse error at offset ${firstError.offset}: ${jsonc.printParseErrorCode(firstError.error)}`
|
|
41
|
+
)
|
|
40
42
|
}
|
|
41
43
|
return result
|
|
42
44
|
}
|
|
@@ -72,7 +74,7 @@ class ConfigManager {
|
|
|
72
74
|
await fs.mkdir(configDir, { recursive: true })
|
|
73
75
|
|
|
74
76
|
const content = JSON.stringify(config, null, 2)
|
|
75
|
-
await fs.writeFile(configPath, content
|
|
77
|
+
await fs.writeFile(configPath, `${content}\n`, 'utf-8')
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
/**
|
|
@@ -91,7 +93,9 @@ class ConfigManager {
|
|
|
91
93
|
return null
|
|
92
94
|
}
|
|
93
95
|
// Log other errors for debugging
|
|
94
|
-
console.warn(
|
|
96
|
+
console.warn(
|
|
97
|
+
`Warning: Could not read global config for ${projectId}: ${getErrorMessage(error)}`
|
|
98
|
+
)
|
|
95
99
|
return null
|
|
96
100
|
}
|
|
97
101
|
}
|
|
@@ -106,7 +110,7 @@ class ConfigManager {
|
|
|
106
110
|
await fs.mkdir(configDir, { recursive: true })
|
|
107
111
|
|
|
108
112
|
const content = JSON.stringify(config, null, 2)
|
|
109
|
-
await fs.writeFile(configPath, content
|
|
113
|
+
await fs.writeFile(configPath, `${content}\n`, 'utf-8')
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
/**
|
|
@@ -231,7 +235,7 @@ class ConfigManager {
|
|
|
231
235
|
*/
|
|
232
236
|
async getProjectId(projectPath: string): Promise<string> {
|
|
233
237
|
const config = await this.readConfig(projectPath)
|
|
234
|
-
if (config
|
|
238
|
+
if (config?.projectId) {
|
|
235
239
|
return config.projectId
|
|
236
240
|
}
|
|
237
241
|
return pathManager.generateProjectId(projectPath)
|
|
@@ -300,7 +304,7 @@ class ConfigManager {
|
|
|
300
304
|
await this.addAuthor(projectId, {
|
|
301
305
|
name: author.name ?? undefined,
|
|
302
306
|
email: author.email ?? undefined,
|
|
303
|
-
github: author.github ?? undefined
|
|
307
|
+
github: author.github ?? undefined,
|
|
304
308
|
})
|
|
305
309
|
|
|
306
310
|
return author.github || author.name || 'Unknown'
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* @version 0.6.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import fs from 'fs/promises'
|
|
13
|
-
import
|
|
14
|
-
import
|
|
12
|
+
import fs from 'node:fs/promises'
|
|
13
|
+
import os from 'node:os'
|
|
14
|
+
import path from 'node:path'
|
|
15
15
|
import type { AIProviderName } from '../types/provider'
|
|
16
16
|
|
|
17
17
|
interface EditorConfig {
|
|
@@ -65,7 +65,11 @@ class EditorsConfig {
|
|
|
65
65
|
/**
|
|
66
66
|
* Save installation configuration
|
|
67
67
|
*/
|
|
68
|
-
async saveConfig(
|
|
68
|
+
async saveConfig(
|
|
69
|
+
version: string,
|
|
70
|
+
installPath: string,
|
|
71
|
+
provider: AIProviderName = 'claude'
|
|
72
|
+
): Promise<boolean> {
|
|
69
73
|
try {
|
|
70
74
|
await this.ensureConfigDir()
|
|
71
75
|
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
* @version 0.2.1
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
12
|
+
import crypto from 'node:crypto'
|
|
13
|
+
import fs from 'node:fs/promises'
|
|
14
|
+
import os from 'node:os'
|
|
15
|
+
import path from 'node:path'
|
|
16
|
+
import type { SessionInfo } from '../types'
|
|
16
17
|
import * as dateHelper from '../utils/date-helper'
|
|
17
18
|
import * as fileHelper from '../utils/file-helper'
|
|
18
|
-
import type { SessionInfo } from '../types'
|
|
19
19
|
|
|
20
20
|
class PathManager {
|
|
21
21
|
globalBaseDir: string
|
|
@@ -24,7 +24,9 @@ class PathManager {
|
|
|
24
24
|
|
|
25
25
|
constructor() {
|
|
26
26
|
const envOverride = process.env.PRJCT_CLI_HOME?.trim()
|
|
27
|
-
this.globalBaseDir = envOverride
|
|
27
|
+
this.globalBaseDir = envOverride
|
|
28
|
+
? path.resolve(envOverride)
|
|
29
|
+
: path.join(os.homedir(), '.prjct-cli')
|
|
28
30
|
this.globalProjectsDir = path.join(this.globalBaseDir, 'projects')
|
|
29
31
|
this.globalConfigDir = path.join(this.globalBaseDir, 'config')
|
|
30
32
|
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
-
type PermissionsConfig,
|
|
13
|
-
type PermissionLevel,
|
|
14
12
|
buildDefaultPermissions,
|
|
13
|
+
type PermissionLevel,
|
|
14
|
+
type PermissionsConfig,
|
|
15
15
|
} from '../schemas/permissions'
|
|
16
16
|
import type { PermissionCheckResult } from '../types'
|
|
17
17
|
|
|
@@ -114,11 +114,12 @@ class PermissionManager {
|
|
|
114
114
|
allowed: match.level === 'allow',
|
|
115
115
|
level: match.level,
|
|
116
116
|
matchedPattern: match.pattern,
|
|
117
|
-
reason:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
reason:
|
|
118
|
+
match.level === 'deny'
|
|
119
|
+
? `Command denied by pattern: ${match.pattern}`
|
|
120
|
+
: match.level === 'ask'
|
|
121
|
+
? `Command requires approval: ${match.pattern}`
|
|
122
|
+
: undefined,
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
|
|
@@ -145,11 +146,12 @@ class PermissionManager {
|
|
|
145
146
|
allowed: match.level === 'allow',
|
|
146
147
|
level: match.level,
|
|
147
148
|
matchedPattern: match.pattern,
|
|
148
|
-
reason:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
reason:
|
|
150
|
+
match.level === 'deny'
|
|
151
|
+
? `File operation denied: ${operation} on ${match.pattern}`
|
|
152
|
+
: match.level === 'ask'
|
|
153
|
+
? `File operation requires approval: ${operation}`
|
|
154
|
+
: undefined,
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
157
|
|
|
@@ -239,11 +241,12 @@ class PermissionManager {
|
|
|
239
241
|
return {
|
|
240
242
|
allowed: level === 'allow',
|
|
241
243
|
level,
|
|
242
|
-
reason:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
244
|
+
reason:
|
|
245
|
+
level === 'deny'
|
|
246
|
+
? 'External directory access denied'
|
|
247
|
+
: level === 'ask'
|
|
248
|
+
? 'External directory access requires approval'
|
|
249
|
+
: undefined,
|
|
247
250
|
}
|
|
248
251
|
}
|
|
249
252
|
|