prjct-cli 0.45.0 → 0.45.4
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 +82 -0
- package/bin/prjct.ts +117 -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 +58 -39
- 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 +28 -4
- package/core/commands/commands.ts +57 -24
- 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 +13 -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 +18 -19
- package/core/context-tools/imports-tool.ts +13 -33
- package/core/context-tools/index.ts +29 -54
- package/core/context-tools/recent-tool.ts +16 -22
- package/core/context-tools/signatures-tool.ts +17 -26
- package/core/context-tools/summary-tool.ts +20 -22
- package/core/context-tools/token-counter.ts +25 -20
- package/core/context-tools/types.ts +5 -5
- 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 -16
- 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 +25 -25
- 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 +87 -345
- 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 -17
- package/core/storage/metrics-storage.ts +39 -34
- 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 -305
- package/core/types/integrations.ts +3 -3
- package/core/types/storage.ts +14 -14
- 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 +18755 -15574
- package/dist/core/infrastructure/command-installer.js +86 -79
- package/dist/core/infrastructure/editors-config.js +6 -6
- package/dist/core/infrastructure/setup.js +246 -225
- 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/domain/analyzer.ts
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* @version 0.6.0 - Fully agentic refactor
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
13
|
+
import { exec as execCallback } from 'node:child_process'
|
|
14
|
+
import fs from 'node:fs/promises'
|
|
15
|
+
import path from 'node:path'
|
|
16
|
+
import { promisify } from 'node:util'
|
|
17
17
|
import { isNotFoundError } from '../types/fs'
|
|
18
18
|
|
|
19
19
|
const exec = promisify(execCallback)
|
|
@@ -209,11 +209,11 @@ class CodebaseAnalyzer {
|
|
|
209
209
|
.forEach((line) => {
|
|
210
210
|
const match = line.trim().match(/^\s*(\d+)\s+(\.\w+)$/)
|
|
211
211
|
if (match) {
|
|
212
|
-
extensions[match[2]] = parseInt(match[1])
|
|
212
|
+
extensions[match[2]] = parseInt(match[1], 10)
|
|
213
213
|
}
|
|
214
214
|
})
|
|
215
215
|
return extensions
|
|
216
|
-
} catch (
|
|
216
|
+
} catch (_error) {
|
|
217
217
|
// exec errors (find command not available, etc.) - return empty
|
|
218
218
|
return {}
|
|
219
219
|
}
|
|
@@ -278,7 +278,7 @@ class CodebaseAnalyzer {
|
|
|
278
278
|
cwd: this.projectPath!,
|
|
279
279
|
})
|
|
280
280
|
return stdout
|
|
281
|
-
} catch (
|
|
281
|
+
} catch (_error) {
|
|
282
282
|
// Git errors (not a repo, git not installed) - return empty
|
|
283
283
|
return ''
|
|
284
284
|
}
|
|
@@ -297,16 +297,19 @@ class CodebaseAnalyzer {
|
|
|
297
297
|
cwd: this.projectPath!,
|
|
298
298
|
})
|
|
299
299
|
|
|
300
|
-
const { stdout: firstCommit } = await exec(
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
const { stdout: firstCommit } = await exec(
|
|
301
|
+
'git log --reverse --pretty=format:"%ar" | head -1',
|
|
302
|
+
{
|
|
303
|
+
cwd: this.projectPath!,
|
|
304
|
+
}
|
|
305
|
+
)
|
|
303
306
|
|
|
304
307
|
return {
|
|
305
|
-
totalCommits: parseInt(totalCommits.trim()) || 0,
|
|
306
|
-
contributors: parseInt(contributors.trim()) || 0,
|
|
308
|
+
totalCommits: parseInt(totalCommits.trim(), 10) || 0,
|
|
309
|
+
contributors: parseInt(contributors.trim(), 10) || 0,
|
|
307
310
|
age: firstCommit.trim() || 'unknown',
|
|
308
311
|
}
|
|
309
|
-
} catch (
|
|
312
|
+
} catch (_error) {
|
|
310
313
|
// Git errors (not a repo, git not installed) - return defaults
|
|
311
314
|
return {
|
|
312
315
|
totalCommits: 0,
|
|
@@ -325,8 +328,8 @@ class CodebaseAnalyzer {
|
|
|
325
328
|
'find . -type f ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/dist/*" | wc -l',
|
|
326
329
|
{ cwd: this.projectPath! }
|
|
327
330
|
)
|
|
328
|
-
return parseInt(stdout.trim()) || 0
|
|
329
|
-
} catch (
|
|
331
|
+
return parseInt(stdout.trim(), 10) || 0
|
|
332
|
+
} catch (_error) {
|
|
330
333
|
// exec errors (find command not available, etc.) - return 0
|
|
331
334
|
return 0
|
|
332
335
|
}
|
|
@@ -372,7 +375,7 @@ class CodebaseAnalyzer {
|
|
|
372
375
|
{ cwd: this.projectPath! }
|
|
373
376
|
)
|
|
374
377
|
return stdout.trim().split('\n').filter(Boolean)
|
|
375
|
-
} catch (
|
|
378
|
+
} catch (_error) {
|
|
376
379
|
// exec errors (find command not available, etc.) - return empty
|
|
377
380
|
return []
|
|
378
381
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* This file only provides structure - real content from Claude
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import fs from 'node:fs/promises'
|
|
8
|
+
import path from 'node:path'
|
|
9
9
|
|
|
10
10
|
interface ArchitectureContext {
|
|
11
11
|
[key: string]: unknown
|
|
@@ -40,7 +40,10 @@ class ArchitectureGenerator {
|
|
|
40
40
|
* Generate architecture skeleton
|
|
41
41
|
* AGENTIC: Claude fills in content using templates
|
|
42
42
|
*/
|
|
43
|
-
async generateArchitecture(
|
|
43
|
+
async generateArchitecture(
|
|
44
|
+
idea: string,
|
|
45
|
+
_context: ArchitectureContext = {}
|
|
46
|
+
): Promise<Architecture> {
|
|
44
47
|
// Return skeleton - Claude generates actual content via templates
|
|
45
48
|
return {
|
|
46
49
|
id: `arch-${Date.now()}`,
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* @version 1.0.0
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import path from 'path'
|
|
11
10
|
import { glob } from 'glob'
|
|
12
11
|
import log from '../utils/logger'
|
|
13
12
|
|
|
@@ -79,7 +78,7 @@ class ContextEstimator {
|
|
|
79
78
|
* 100% AGENTIC: Uses REAL project data, not hardcoded patterns.
|
|
80
79
|
* No domain-specific assumptions or language→extension mapping.
|
|
81
80
|
*/
|
|
82
|
-
getPatternsForDomain(
|
|
81
|
+
getPatternsForDomain(_domain: string, projectData: ProjectTech): FilePatterns {
|
|
83
82
|
const patterns: FilePatterns = {
|
|
84
83
|
include: [],
|
|
85
84
|
extensions: [],
|
|
@@ -87,7 +86,7 @@ class ContextEstimator {
|
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
// Use REAL extensions from project (if provided in projectData)
|
|
90
|
-
if (projectData
|
|
89
|
+
if (projectData?.extensions) {
|
|
91
90
|
// projectData.extensions is {'.js': 45, '.ts': 23, ...}
|
|
92
91
|
patterns.extensions = Object.keys(projectData.extensions)
|
|
93
92
|
.filter((ext) => ext.startsWith('.'))
|
|
@@ -95,7 +94,7 @@ class ContextEstimator {
|
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
// Use REAL directories from project (if provided in projectData)
|
|
98
|
-
if (projectData
|
|
97
|
+
if (projectData?.directories) {
|
|
99
98
|
patterns.include = projectData.directories.filter((dir) => !patterns.exclude.includes(dir))
|
|
100
99
|
}
|
|
101
100
|
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
* @version 1.0.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import { promisify } from 'util'
|
|
16
|
-
import pathManager from '../infrastructure/path-manager'
|
|
17
|
-
import configManager from '../infrastructure/config-manager'
|
|
12
|
+
import { exec } from 'node:child_process'
|
|
13
|
+
import fs from 'node:fs/promises'
|
|
14
|
+
import path from 'node:path'
|
|
15
|
+
import { promisify } from 'node:util'
|
|
18
16
|
import { emit } from '../bus'
|
|
17
|
+
import configManager from '../infrastructure/config-manager'
|
|
18
|
+
import pathManager from '../infrastructure/path-manager'
|
|
19
19
|
import { isNotFoundError } from '../types/fs'
|
|
20
20
|
|
|
21
21
|
const execAsync = promisify(exec)
|
|
@@ -100,7 +100,9 @@ class SnapshotManager {
|
|
|
100
100
|
await execAsync(`git config user.name "prjct-snapshots"`, { cwd: this.snapshotDir! })
|
|
101
101
|
|
|
102
102
|
// Create initial empty commit
|
|
103
|
-
await execAsync(`git commit --allow-empty -m "init: snapshot system"`, {
|
|
103
|
+
await execAsync(`git commit --allow-empty -m "init: snapshot system"`, {
|
|
104
|
+
cwd: this.snapshotDir!,
|
|
105
|
+
})
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
/**
|
|
@@ -236,9 +238,12 @@ class SnapshotManager {
|
|
|
236
238
|
if (!this.initialized) await this.initialize()
|
|
237
239
|
|
|
238
240
|
// Get files changed in that commit
|
|
239
|
-
const { stdout: filesOutput } = await execAsync(
|
|
240
|
-
|
|
241
|
-
|
|
241
|
+
const { stdout: filesOutput } = await execAsync(
|
|
242
|
+
`git diff-tree --no-commit-id --name-only -r ${hash}`,
|
|
243
|
+
{
|
|
244
|
+
cwd: this.snapshotDir!,
|
|
245
|
+
}
|
|
246
|
+
)
|
|
242
247
|
|
|
243
248
|
const files = filesOutput.split('\n').filter(Boolean)
|
|
244
249
|
|
|
@@ -337,11 +342,10 @@ class SnapshotManager {
|
|
|
337
342
|
*/
|
|
338
343
|
async logSnapshot(snapshot: SnapshotInfo): Promise<void> {
|
|
339
344
|
const manifestPath = path.join(this.snapshotDir!, 'manifest.jsonl')
|
|
340
|
-
const entry =
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}) + '\n'
|
|
345
|
+
const entry = `${JSON.stringify({
|
|
346
|
+
type: 'snapshot',
|
|
347
|
+
...snapshot,
|
|
348
|
+
})}\n`
|
|
345
349
|
|
|
346
350
|
await fs.appendFile(manifestPath, entry)
|
|
347
351
|
}
|
|
@@ -351,13 +355,12 @@ class SnapshotManager {
|
|
|
351
355
|
*/
|
|
352
356
|
async logRestore(hash: string, files: string[]): Promise<void> {
|
|
353
357
|
const manifestPath = path.join(this.snapshotDir!, 'manifest.jsonl')
|
|
354
|
-
const entry =
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}) + '\n'
|
|
358
|
+
const entry = `${JSON.stringify({
|
|
359
|
+
type: 'restore',
|
|
360
|
+
hash,
|
|
361
|
+
files,
|
|
362
|
+
timestamp: new Date().toISOString(),
|
|
363
|
+
})}\n`
|
|
361
364
|
|
|
362
365
|
await fs.appendFile(manifestPath, entry)
|
|
363
366
|
}
|
|
@@ -3,23 +3,22 @@
|
|
|
3
3
|
* Manages task breakdown and hierarchical task tracking.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import fs from 'fs/promises'
|
|
8
|
-
import
|
|
9
|
-
import { promisify } from 'util'
|
|
10
|
-
import log from '../utils/logger'
|
|
11
|
-
import { isNotFoundError } from '../types/fs'
|
|
6
|
+
import { exec } from 'node:child_process'
|
|
7
|
+
import fs from 'node:fs/promises'
|
|
8
|
+
import path from 'node:path'
|
|
9
|
+
import { promisify } from 'node:util'
|
|
12
10
|
import type {
|
|
13
|
-
TaskStackEntry,
|
|
14
11
|
ParsedNowFile,
|
|
12
|
+
TaskStackEntry,
|
|
15
13
|
TaskStackMigrationResult,
|
|
16
|
-
TaskSwitchResult,
|
|
17
14
|
TaskStackSummary,
|
|
15
|
+
TaskSwitchResult,
|
|
18
16
|
} from '../types'
|
|
17
|
+
import { isNotFoundError } from '../types/fs'
|
|
18
|
+
import log from '../utils/logger'
|
|
19
19
|
|
|
20
20
|
const execAsync = promisify(exec)
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
// =============================================================================
|
|
24
23
|
// Parser
|
|
25
24
|
// =============================================================================
|
|
@@ -129,7 +128,7 @@ export async function ensureStackFile(stackPath: string): Promise<void> {
|
|
|
129
128
|
*/
|
|
130
129
|
export async function appendToStack(stackPath: string, entry: TaskStackEntry): Promise<void> {
|
|
131
130
|
await ensureStackFile(stackPath)
|
|
132
|
-
const line = JSON.stringify(entry)
|
|
131
|
+
const line = `${JSON.stringify(entry)}\n`
|
|
133
132
|
await fs.appendFile(stackPath, line)
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -162,14 +161,18 @@ export async function readStack(stackPath: string): Promise<TaskStackEntry[]> {
|
|
|
162
161
|
* Write full stack to file
|
|
163
162
|
*/
|
|
164
163
|
export async function writeStack(stackPath: string, stack: TaskStackEntry[]): Promise<void> {
|
|
165
|
-
const content = stack.map((task) => JSON.stringify(task)).join('\n')
|
|
164
|
+
const content = `${stack.map((task) => JSON.stringify(task)).join('\n')}\n`
|
|
166
165
|
await fs.writeFile(stackPath, content)
|
|
167
166
|
}
|
|
168
167
|
|
|
169
168
|
/**
|
|
170
169
|
* Generate now.md content for a task
|
|
171
170
|
*/
|
|
172
|
-
export function generateNowContent(
|
|
171
|
+
export function generateNowContent(
|
|
172
|
+
task: TaskStackEntry | null,
|
|
173
|
+
customContent: string | null,
|
|
174
|
+
formatDurationFn: (ms: number) => string
|
|
175
|
+
): string {
|
|
173
176
|
if (customContent !== undefined && customContent !== null) {
|
|
174
177
|
return customContent
|
|
175
178
|
}
|
|
@@ -340,7 +343,11 @@ export class TaskStack {
|
|
|
340
343
|
/**
|
|
341
344
|
* Start a new task
|
|
342
345
|
*/
|
|
343
|
-
async startTask(
|
|
346
|
+
async startTask(
|
|
347
|
+
description: string,
|
|
348
|
+
agent: string = 'general',
|
|
349
|
+
complexity: string = 'moderate'
|
|
350
|
+
): Promise<TaskStackEntry> {
|
|
344
351
|
// Check if there's already an active task
|
|
345
352
|
const active = await this.getActiveTask()
|
|
346
353
|
if (active) {
|
|
@@ -524,7 +531,10 @@ export class TaskStack {
|
|
|
524
531
|
/**
|
|
525
532
|
* Update now.md to reflect current state
|
|
526
533
|
*/
|
|
527
|
-
async updateNowFile(
|
|
534
|
+
async updateNowFile(
|
|
535
|
+
task: TaskStackEntry | null,
|
|
536
|
+
customContent: string | null = null
|
|
537
|
+
): Promise<void> {
|
|
528
538
|
await updateNowFile(this.nowPath, task, customContent, formatDuration)
|
|
529
539
|
}
|
|
530
540
|
|
package/core/errors.ts
CHANGED
package/core/events/events.ts
CHANGED
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import pathManager from '../infrastructure/path-manager'
|
|
9
|
-
import
|
|
9
|
+
import type { SyncEvent, SyncEventType } from '../types'
|
|
10
10
|
import { getTimestamp } from '../utils/date-helper'
|
|
11
|
-
|
|
12
|
-
import type { SyncEventType, SyncEvent } from '../types'
|
|
11
|
+
import * as fileHelper from '../utils/file-helper'
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Infer event type from path and action
|
|
@@ -84,4 +83,3 @@ class EventBus {
|
|
|
84
83
|
|
|
85
84
|
export const eventBus = new EventBus()
|
|
86
85
|
export default eventBus
|
|
87
|
-
|
package/core/events/index.ts
CHANGED
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,10 +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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
stats: () =>
|
|
115
|
+
commands.stats(process.cwd(), {
|
|
116
|
+
json: options.json === true,
|
|
117
|
+
export: options.export === true,
|
|
118
|
+
}),
|
|
118
119
|
help: (p) => commands.help(p || ''),
|
|
119
120
|
// Maintenance
|
|
120
121
|
recover: () => commands.recover(),
|
|
@@ -122,9 +123,10 @@ async function main(): Promise<void> {
|
|
|
122
123
|
redo: () => commands.redo(),
|
|
123
124
|
history: () => commands.history(),
|
|
124
125
|
// Setup
|
|
125
|
-
sync: () =>
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
sync: () =>
|
|
127
|
+
commands.sync(process.cwd(), {
|
|
128
|
+
aiTools: options.agents ? String(options.agents).split(',') : undefined,
|
|
129
|
+
}),
|
|
128
130
|
start: () => commands.start(),
|
|
129
131
|
// Context (for Claude templates)
|
|
130
132
|
context: (p) => commands.context(p),
|
|
@@ -139,13 +141,13 @@ async function main(): Promise<void> {
|
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
// 7. Display result
|
|
142
|
-
if (result
|
|
144
|
+
if (result?.message) {
|
|
143
145
|
console.log(result.message)
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
// Show branding footer
|
|
147
149
|
out.end()
|
|
148
|
-
process.exit(result
|
|
150
|
+
process.exit(result?.success ? 0 : 1)
|
|
149
151
|
} catch (error) {
|
|
150
152
|
console.error('Error:', (error as Error).message)
|
|
151
153
|
if (process.env.DEBUG) {
|
|
@@ -160,7 +162,7 @@ async function main(): Promise<void> {
|
|
|
160
162
|
/**
|
|
161
163
|
* Parse command arguments dynamically
|
|
162
164
|
*/
|
|
163
|
-
function parseCommandArgs(
|
|
165
|
+
function parseCommandArgs(_cmd: CommandMeta, rawArgs: string[]): ParsedCommandArgs {
|
|
164
166
|
const parsedArgs: string[] = []
|
|
165
167
|
const options: Record<string, string | boolean> = {}
|
|
166
168
|
|
|
@@ -235,7 +237,9 @@ ${DIM}Providers:${RESET}`)
|
|
|
235
237
|
// Antigravity status (global, skills-based)
|
|
236
238
|
const antigravityDetection = detectAntigravity()
|
|
237
239
|
if (antigravityDetection.installed) {
|
|
238
|
-
const status = antigravityDetection.skillInstalled
|
|
240
|
+
const status = antigravityDetection.skillInstalled
|
|
241
|
+
? `${GREEN}✓ ready${RESET}`
|
|
242
|
+
: `${YELLOW}● detected${RESET}`
|
|
239
243
|
const hint = antigravityDetection.skillInstalled ? '' : ` ${DIM}(run prjct start)${RESET}`
|
|
240
244
|
console.log(` Antigravity ${status}${hint}`)
|
|
241
245
|
} else {
|
|
@@ -293,6 +297,8 @@ TERMINAL COMMANDS (this CLI)
|
|
|
293
297
|
prjct init Initialize project (required for Cursor)
|
|
294
298
|
prjct setup Reconfigure installations
|
|
295
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
|
|
296
302
|
|
|
297
303
|
EXAMPLES
|
|
298
304
|
--------
|
|
@@ -307,6 +313,12 @@ EXAMPLES
|
|
|
307
313
|
> /sync
|
|
308
314
|
> /task "add user authentication"
|
|
309
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
|
+
|
|
310
322
|
MORE INFO
|
|
311
323
|
---------
|
|
312
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
|
|