prjct-cli 0.50.0 → 0.52.0
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 +39 -0
- package/core/agentic/memory-system.ts +96 -18
- package/core/commands/analysis.ts +199 -83
- package/core/services/diff-generator.ts +356 -0
- package/core/services/sync-service.ts +6 -0
- package/core/types/memory.ts +41 -2
- package/dist/bin/prjct.mjs +694 -333
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.52.0] - 2026-01-30
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add confidence scores to all stored preferences - PRJ-104 (#78)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.52.0] - 2026-01-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Confidence scores for stored preferences** (PRJ-104)
|
|
15
|
+
- All preferences, decisions, and workflows now track confidence level
|
|
16
|
+
- Confidence: `low` (1-2 obs), `medium` (3-5 obs), `high` (6+ or confirmed)
|
|
17
|
+
- Added `confirmPreference()`, `confirmDecision()`, `confirmWorkflow()` methods
|
|
18
|
+
- User confirmation immediately sets confidence to `high`
|
|
19
|
+
- Added `calculateConfidence()` utility function
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [0.51.0] - 2026-01-30
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
- Context diff preview before sync applies - PRJ-125 (#77)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## [0.51.0] - 2026-01-30
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Context Diff Preview** (PRJ-125)
|
|
34
|
+
- See what changes sync will make before they're applied
|
|
35
|
+
- Interactive confirmation: apply, cancel, or show full diff
|
|
36
|
+
- Preserved sections clearly marked in preview
|
|
37
|
+
- Token count delta displayed
|
|
38
|
+
- `--preview` flag for dry-run only
|
|
39
|
+
- `--yes` flag to skip confirmation
|
|
40
|
+
|
|
41
|
+
|
|
3
42
|
## [0.50.0] - 2026-01-30
|
|
4
43
|
|
|
5
44
|
### Features
|
|
@@ -22,6 +22,7 @@ import { appendJsonLine, getLastJsonLines } from '../utils/jsonl-helper'
|
|
|
22
22
|
|
|
23
23
|
// Re-export types from canonical location
|
|
24
24
|
export type {
|
|
25
|
+
ConfidenceLevel,
|
|
25
26
|
Decision,
|
|
26
27
|
HistoryEntry,
|
|
27
28
|
HistoryEventType,
|
|
@@ -35,7 +36,7 @@ export type {
|
|
|
35
36
|
Workflow,
|
|
36
37
|
} from '../types/memory'
|
|
37
38
|
|
|
38
|
-
export { MEMORY_TAGS } from '../types/memory'
|
|
39
|
+
export { calculateConfidence, MEMORY_TAGS } from '../types/memory'
|
|
39
40
|
|
|
40
41
|
import type {
|
|
41
42
|
HistoryEntry,
|
|
@@ -49,7 +50,7 @@ import type {
|
|
|
49
50
|
Workflow,
|
|
50
51
|
} from '../types/memory'
|
|
51
52
|
|
|
52
|
-
import { MEMORY_TAGS } from '../types/memory'
|
|
53
|
+
import { calculateConfidence, MEMORY_TAGS } from '../types/memory'
|
|
53
54
|
|
|
54
55
|
// =============================================================================
|
|
55
56
|
// Base Store
|
|
@@ -306,7 +307,8 @@ export class PatternStore extends CachedStore<Patterns> {
|
|
|
306
307
|
projectId: string,
|
|
307
308
|
key: string,
|
|
308
309
|
value: string,
|
|
309
|
-
context: string = ''
|
|
310
|
+
context: string = '',
|
|
311
|
+
options: { userConfirmed?: boolean } = {}
|
|
310
312
|
): Promise<void> {
|
|
311
313
|
const patterns = await this.load(projectId)
|
|
312
314
|
const now = getTimestamp()
|
|
@@ -317,11 +319,14 @@ export class PatternStore extends CachedStore<Patterns> {
|
|
|
317
319
|
count: 1,
|
|
318
320
|
firstSeen: now,
|
|
319
321
|
lastSeen: now,
|
|
320
|
-
confidence: 'low',
|
|
322
|
+
confidence: options.userConfirmed ? 'high' : 'low',
|
|
321
323
|
contexts: [context].filter(Boolean),
|
|
322
|
-
|
|
324
|
+
userConfirmed: options.userConfirmed || false,
|
|
325
|
+
} as Patterns['decisions'][string]
|
|
323
326
|
} else {
|
|
324
|
-
const decision = patterns.decisions[key]
|
|
327
|
+
const decision = patterns.decisions[key] as Patterns['decisions'][string] & {
|
|
328
|
+
userConfirmed?: boolean
|
|
329
|
+
}
|
|
325
330
|
|
|
326
331
|
if (decision.value === value) {
|
|
327
332
|
decision.count++
|
|
@@ -329,23 +334,36 @@ export class PatternStore extends CachedStore<Patterns> {
|
|
|
329
334
|
if (context && !decision.contexts.includes(context)) {
|
|
330
335
|
decision.contexts.push(context)
|
|
331
336
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
decision.confidence = 'high'
|
|
335
|
-
} else if (decision.count >= 3) {
|
|
336
|
-
decision.confidence = 'medium'
|
|
337
|
+
if (options.userConfirmed) {
|
|
338
|
+
decision.userConfirmed = true
|
|
337
339
|
}
|
|
340
|
+
decision.confidence = calculateConfidence(decision.count, decision.userConfirmed)
|
|
338
341
|
} else {
|
|
339
342
|
decision.value = value
|
|
340
343
|
decision.count = 1
|
|
341
344
|
decision.lastSeen = now
|
|
342
|
-
decision.
|
|
345
|
+
decision.userConfirmed = options.userConfirmed || false
|
|
346
|
+
decision.confidence = options.userConfirmed ? 'high' : 'low'
|
|
343
347
|
}
|
|
344
348
|
}
|
|
345
349
|
|
|
346
350
|
await this.save(projectId)
|
|
347
351
|
}
|
|
348
352
|
|
|
353
|
+
async confirmDecision(projectId: string, key: string): Promise<boolean> {
|
|
354
|
+
const patterns = await this.load(projectId)
|
|
355
|
+
const decision = patterns.decisions[key] as
|
|
356
|
+
| (Patterns['decisions'][string] & { userConfirmed?: boolean })
|
|
357
|
+
| undefined
|
|
358
|
+
if (!decision) return false
|
|
359
|
+
|
|
360
|
+
decision.userConfirmed = true
|
|
361
|
+
decision.confidence = 'high'
|
|
362
|
+
decision.lastSeen = getTimestamp()
|
|
363
|
+
await this.save(projectId)
|
|
364
|
+
return true
|
|
365
|
+
}
|
|
366
|
+
|
|
349
367
|
async getDecision(
|
|
350
368
|
projectId: string,
|
|
351
369
|
key: string
|
|
@@ -378,15 +396,31 @@ export class PatternStore extends CachedStore<Patterns> {
|
|
|
378
396
|
count: 1,
|
|
379
397
|
firstSeen: now,
|
|
380
398
|
lastSeen: now,
|
|
399
|
+
confidence: 'low',
|
|
400
|
+
userConfirmed: false,
|
|
381
401
|
}
|
|
382
402
|
} else {
|
|
383
|
-
patterns.workflows[workflowName]
|
|
384
|
-
|
|
403
|
+
const workflow = patterns.workflows[workflowName]
|
|
404
|
+
workflow.count++
|
|
405
|
+
workflow.lastSeen = now
|
|
406
|
+
workflow.confidence = calculateConfidence(workflow.count, workflow.userConfirmed)
|
|
385
407
|
}
|
|
386
408
|
|
|
387
409
|
await this.save(projectId)
|
|
388
410
|
}
|
|
389
411
|
|
|
412
|
+
async confirmWorkflow(projectId: string, workflowName: string): Promise<boolean> {
|
|
413
|
+
const patterns = await this.load(projectId)
|
|
414
|
+
const workflow = patterns.workflows[workflowName]
|
|
415
|
+
if (!workflow) return false
|
|
416
|
+
|
|
417
|
+
workflow.userConfirmed = true
|
|
418
|
+
workflow.confidence = 'high'
|
|
419
|
+
workflow.lastSeen = getTimestamp()
|
|
420
|
+
await this.save(projectId)
|
|
421
|
+
return true
|
|
422
|
+
}
|
|
423
|
+
|
|
390
424
|
async getWorkflow(projectId: string, workflowName: string): Promise<Workflow | null> {
|
|
391
425
|
const patterns = await this.load(projectId)
|
|
392
426
|
const workflow = patterns.workflows[workflowName]
|
|
@@ -395,12 +429,39 @@ export class PatternStore extends CachedStore<Patterns> {
|
|
|
395
429
|
return workflow
|
|
396
430
|
}
|
|
397
431
|
|
|
398
|
-
async setPreference(
|
|
432
|
+
async setPreference(
|
|
433
|
+
projectId: string,
|
|
434
|
+
key: string,
|
|
435
|
+
value: Preference['value'],
|
|
436
|
+
options: { userConfirmed?: boolean } = {}
|
|
437
|
+
): Promise<void> {
|
|
399
438
|
const patterns = await this.load(projectId)
|
|
400
|
-
patterns.preferences[key]
|
|
439
|
+
const existing = patterns.preferences[key]
|
|
440
|
+
const observationCount = existing ? existing.observationCount + 1 : 1
|
|
441
|
+
const userConfirmed = options.userConfirmed || existing?.userConfirmed || false
|
|
442
|
+
|
|
443
|
+
patterns.preferences[key] = {
|
|
444
|
+
value,
|
|
445
|
+
updatedAt: getTimestamp(),
|
|
446
|
+
confidence: calculateConfidence(observationCount, userConfirmed),
|
|
447
|
+
observationCount,
|
|
448
|
+
userConfirmed,
|
|
449
|
+
}
|
|
401
450
|
await this.save(projectId)
|
|
402
451
|
}
|
|
403
452
|
|
|
453
|
+
async confirmPreference(projectId: string, key: string): Promise<boolean> {
|
|
454
|
+
const patterns = await this.load(projectId)
|
|
455
|
+
const pref = patterns.preferences[key]
|
|
456
|
+
if (!pref) return false
|
|
457
|
+
|
|
458
|
+
pref.userConfirmed = true
|
|
459
|
+
pref.confidence = 'high'
|
|
460
|
+
pref.updatedAt = getTimestamp()
|
|
461
|
+
await this.save(projectId)
|
|
462
|
+
return true
|
|
463
|
+
}
|
|
464
|
+
|
|
404
465
|
async getPreference(
|
|
405
466
|
projectId: string,
|
|
406
467
|
key: string,
|
|
@@ -857,14 +918,31 @@ export class MemorySystem {
|
|
|
857
918
|
return this._patternStore.getWorkflow(projectId, workflowName)
|
|
858
919
|
}
|
|
859
920
|
|
|
860
|
-
setPreference(
|
|
861
|
-
|
|
921
|
+
setPreference(
|
|
922
|
+
projectId: string,
|
|
923
|
+
key: string,
|
|
924
|
+
value: Preference['value'],
|
|
925
|
+
options?: { userConfirmed?: boolean }
|
|
926
|
+
): Promise<void> {
|
|
927
|
+
return this._patternStore.setPreference(projectId, key, value, options)
|
|
862
928
|
}
|
|
863
929
|
|
|
864
930
|
getPreference(projectId: string, key: string, defaultValue?: unknown): Promise<unknown> {
|
|
865
931
|
return this._patternStore.getPreference(projectId, key, defaultValue)
|
|
866
932
|
}
|
|
867
933
|
|
|
934
|
+
confirmPreference(projectId: string, key: string): Promise<boolean> {
|
|
935
|
+
return this._patternStore.confirmPreference(projectId, key)
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
confirmDecision(projectId: string, key: string): Promise<boolean> {
|
|
939
|
+
return this._patternStore.confirmDecision(projectId, key)
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
confirmWorkflow(projectId: string, workflowName: string): Promise<boolean> {
|
|
943
|
+
return this._patternStore.confirmWorkflow(projectId, workflowName)
|
|
944
|
+
}
|
|
945
|
+
|
|
868
946
|
getPatternsSummary(projectId: string) {
|
|
869
947
|
return this._patternStore.getPatternsSummary(projectId)
|
|
870
948
|
}
|
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
* Analysis Commands: analyze, sync, and related helpers
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import fs from 'node:fs/promises'
|
|
5
6
|
import path from 'node:path'
|
|
7
|
+
import prompts from 'prompts'
|
|
6
8
|
import { generateContext } from '../context/generator'
|
|
7
9
|
import analyzer from '../domain/analyzer'
|
|
8
10
|
import commandInstaller from '../infrastructure/command-installer'
|
|
9
11
|
import { formatCost } from '../schemas/metrics'
|
|
10
12
|
import { syncService } from '../services'
|
|
13
|
+
import { formatDiffPreview, formatFullDiff, generateSyncDiff } from '../services/diff-generator'
|
|
11
14
|
import { metricsStorage } from '../storage/metrics-storage'
|
|
12
15
|
import type { AnalyzeOptions, CommandResult, ProjectContext } from '../types'
|
|
13
16
|
import { showNextSteps } from '../utils/next-steps'
|
|
17
|
+
import out from '../utils/output'
|
|
14
18
|
import {
|
|
15
19
|
configManager,
|
|
16
20
|
contextBuilder,
|
|
@@ -195,7 +199,7 @@ export class AnalysisCommands extends PrjctCommandsBase {
|
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
/**
|
|
198
|
-
* /p:sync - Comprehensive project sync
|
|
202
|
+
* /p:sync - Comprehensive project sync with diff preview
|
|
199
203
|
*
|
|
200
204
|
* Uses syncService to do ALL operations in one TypeScript execution:
|
|
201
205
|
* - Git analysis
|
|
@@ -205,120 +209,232 @@ export class AnalysisCommands extends PrjctCommandsBase {
|
|
|
205
209
|
* - Skill configuration
|
|
206
210
|
* - State updates
|
|
207
211
|
*
|
|
212
|
+
* Options:
|
|
213
|
+
* - --preview: Show what would change without applying
|
|
214
|
+
* - --yes: Skip confirmation prompt
|
|
215
|
+
*
|
|
208
216
|
* This eliminates the need for Claude to make 50+ individual tool calls.
|
|
217
|
+
*
|
|
218
|
+
* @see PRJ-125
|
|
209
219
|
*/
|
|
210
220
|
async sync(
|
|
211
221
|
projectPath: string = process.cwd(),
|
|
212
|
-
options: { aiTools?: string[] } = {}
|
|
222
|
+
options: { aiTools?: string[]; preview?: boolean; yes?: boolean } = {}
|
|
213
223
|
): Promise<CommandResult> {
|
|
214
224
|
try {
|
|
215
225
|
const initResult = await this.ensureProjectInit(projectPath)
|
|
216
226
|
if (!initResult.success) return initResult
|
|
217
227
|
|
|
218
|
-
const
|
|
219
|
-
|
|
228
|
+
const projectId = await configManager.getProjectId(projectPath)
|
|
229
|
+
if (!projectId) {
|
|
230
|
+
out.failWithHint('NO_PROJECT_ID')
|
|
231
|
+
return { success: false, error: 'No project ID found' }
|
|
232
|
+
}
|
|
220
233
|
|
|
221
|
-
|
|
222
|
-
const
|
|
234
|
+
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
235
|
+
const startTime = Date.now()
|
|
223
236
|
|
|
224
|
-
if
|
|
225
|
-
|
|
226
|
-
|
|
237
|
+
// Generate diff preview if we have existing context
|
|
238
|
+
const claudeMdPath = path.join(globalPath, 'context', 'CLAUDE.md')
|
|
239
|
+
let existingContent: string | null = null
|
|
240
|
+
try {
|
|
241
|
+
existingContent = await fs.readFile(claudeMdPath, 'utf-8')
|
|
242
|
+
} catch {
|
|
243
|
+
// No existing file - first sync
|
|
227
244
|
}
|
|
228
245
|
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
console.log(`📝 Updated ${pathManager.getDisplayPath(globalConfigResult.path!)}`)
|
|
233
|
-
}
|
|
246
|
+
// For preview mode or when we have existing content, show diff first
|
|
247
|
+
if (existingContent && !options.yes) {
|
|
248
|
+
out.spin('Analyzing changes...')
|
|
234
249
|
|
|
235
|
-
|
|
236
|
-
|
|
250
|
+
// Do a dry-run sync to see what would change
|
|
251
|
+
const result = await syncService.sync(projectPath, { aiTools: options.aiTools })
|
|
237
252
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
console.log(`└── Stack: ${result.stats.ecosystem}\n`)
|
|
253
|
+
if (!result.success) {
|
|
254
|
+
out.fail(result.error || 'Sync failed')
|
|
255
|
+
return { success: false, error: result.error }
|
|
256
|
+
}
|
|
243
257
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
// Read the newly generated CLAUDE.md
|
|
259
|
+
let newContent: string
|
|
260
|
+
try {
|
|
261
|
+
newContent = await fs.readFile(claudeMdPath, 'utf-8')
|
|
262
|
+
} catch {
|
|
263
|
+
newContent = ''
|
|
264
|
+
}
|
|
248
265
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
console.log('')
|
|
266
|
+
// Generate diff
|
|
267
|
+
const diff = generateSyncDiff(existingContent, newContent)
|
|
268
|
+
|
|
269
|
+
out.stop()
|
|
254
270
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
console.log(`🤖 AI Tools Context (${successTools.length})`)
|
|
259
|
-
for (const tool of result.aiTools) {
|
|
260
|
-
const status = tool.success ? '✓' : '✗'
|
|
261
|
-
console.log(`├── ${status} ${tool.outputFile} (${tool.toolId})`)
|
|
271
|
+
if (!diff.hasChanges) {
|
|
272
|
+
out.done('No changes detected (context is up to date)')
|
|
273
|
+
return { success: true, message: 'No changes' }
|
|
262
274
|
}
|
|
263
|
-
console.log('')
|
|
264
|
-
}
|
|
265
275
|
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
// Show diff preview
|
|
277
|
+
console.log(formatDiffPreview(diff))
|
|
278
|
+
|
|
279
|
+
// Preview-only mode - don't apply
|
|
280
|
+
if (options.preview) {
|
|
281
|
+
return {
|
|
282
|
+
success: true,
|
|
283
|
+
isPreview: true,
|
|
284
|
+
diff,
|
|
285
|
+
message: 'Preview complete (no changes applied)',
|
|
286
|
+
}
|
|
287
|
+
}
|
|
268
288
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
289
|
+
// Interactive confirmation
|
|
290
|
+
const response = await prompts({
|
|
291
|
+
type: 'select',
|
|
292
|
+
name: 'action',
|
|
293
|
+
message: 'Apply these changes?',
|
|
294
|
+
choices: [
|
|
295
|
+
{ title: 'Yes, apply changes', value: 'apply' },
|
|
296
|
+
{ title: 'No, cancel', value: 'cancel' },
|
|
297
|
+
{ title: 'Show full diff', value: 'diff' },
|
|
298
|
+
],
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
if (response.action === 'cancel' || !response.action) {
|
|
302
|
+
out.warn('Sync cancelled')
|
|
303
|
+
return { success: false, message: 'Cancelled by user' }
|
|
304
|
+
}
|
|
272
305
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
306
|
+
if (response.action === 'diff') {
|
|
307
|
+
console.log(`\n${formatFullDiff(diff)}`)
|
|
308
|
+
const confirm = await prompts({
|
|
309
|
+
type: 'confirm',
|
|
310
|
+
name: 'apply',
|
|
311
|
+
message: 'Apply these changes?',
|
|
312
|
+
initial: true,
|
|
313
|
+
})
|
|
314
|
+
if (!confirm.apply) {
|
|
315
|
+
out.warn('Sync cancelled')
|
|
316
|
+
return { success: false, message: 'Cancelled by user' }
|
|
317
|
+
}
|
|
277
318
|
}
|
|
278
|
-
|
|
319
|
+
|
|
320
|
+
// Changes already applied from dry-run, just show success
|
|
321
|
+
out.done('Changes applied')
|
|
322
|
+
return this.showSyncResult(result, startTime)
|
|
279
323
|
}
|
|
280
324
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
325
|
+
// First sync or --yes flag - proceed directly
|
|
326
|
+
out.spin('Syncing project...')
|
|
327
|
+
|
|
328
|
+
// Use syncService to do EVERYTHING in one call
|
|
329
|
+
const result = await syncService.sync(projectPath, { aiTools: options.aiTools })
|
|
330
|
+
|
|
331
|
+
if (!result.success) {
|
|
332
|
+
out.fail(result.error || 'Sync failed')
|
|
333
|
+
return { success: false, error: result.error }
|
|
285
334
|
}
|
|
286
335
|
|
|
287
|
-
|
|
336
|
+
out.stop()
|
|
337
|
+
return this.showSyncResult(result, startTime)
|
|
338
|
+
} catch (error) {
|
|
339
|
+
out.fail((error as Error).message)
|
|
340
|
+
return { success: false, error: (error as Error).message }
|
|
341
|
+
}
|
|
342
|
+
}
|
|
288
343
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Display sync results (extracted to avoid duplication)
|
|
346
|
+
*/
|
|
347
|
+
private async showSyncResult(
|
|
348
|
+
result: Awaited<ReturnType<typeof syncService.sync>>,
|
|
349
|
+
startTime: number
|
|
350
|
+
): Promise<CommandResult> {
|
|
351
|
+
// Update global config
|
|
352
|
+
const globalConfigResult = await commandInstaller.installGlobalConfig()
|
|
353
|
+
if (globalConfigResult.success) {
|
|
354
|
+
console.log(`📝 Updated ${pathManager.getDisplayPath(globalConfigResult.path!)}`)
|
|
355
|
+
}
|
|
294
356
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
357
|
+
// Format output
|
|
358
|
+
console.log(`🔄 Project synced to prjct v${result.cliVersion}\n`)
|
|
359
|
+
|
|
360
|
+
console.log('📊 Project Stats')
|
|
361
|
+
console.log(`├── Files: ~${result.stats.fileCount}`)
|
|
362
|
+
console.log(`├── Commits: ${result.git.commits}`)
|
|
363
|
+
console.log(`├── Version: ${result.stats.version}`)
|
|
364
|
+
console.log(`└── Stack: ${result.stats.ecosystem}\n`)
|
|
365
|
+
|
|
366
|
+
console.log('🌿 Git Status')
|
|
367
|
+
console.log(`├── Branch: ${result.git.branch}`)
|
|
368
|
+
console.log(`├── Uncommitted: ${result.git.hasChanges ? 'Yes' : 'Clean'}`)
|
|
369
|
+
console.log(`└── Recent: ${result.git.weeklyCommits} commits this week\n`)
|
|
370
|
+
|
|
371
|
+
console.log('📁 Context Updated')
|
|
372
|
+
for (const file of result.contextFiles) {
|
|
373
|
+
console.log(`├── ${file}`)
|
|
374
|
+
}
|
|
375
|
+
console.log('')
|
|
376
|
+
|
|
377
|
+
// Show AI Tools generated (multi-agent output)
|
|
378
|
+
if (result.aiTools && result.aiTools.length > 0) {
|
|
379
|
+
const successTools = result.aiTools.filter((t) => t.success)
|
|
380
|
+
console.log(`🤖 AI Tools Context (${successTools.length})`)
|
|
381
|
+
for (const tool of result.aiTools) {
|
|
382
|
+
const status = tool.success ? '✓' : '✗'
|
|
383
|
+
console.log(`├── ${status} ${tool.outputFile} (${tool.toolId})`)
|
|
384
|
+
}
|
|
307
385
|
console.log('')
|
|
386
|
+
}
|
|
308
387
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
388
|
+
const workflowAgents = result.agents.filter((a) => a.type === 'workflow').map((a) => a.name)
|
|
389
|
+
const domainAgents = result.agents.filter((a) => a.type === 'domain').map((a) => a.name)
|
|
390
|
+
|
|
391
|
+
console.log(`🤖 Agents Regenerated (${result.agents.length})`)
|
|
392
|
+
console.log(`├── Workflow: ${workflowAgents.join(', ')}`)
|
|
393
|
+
console.log(`└── Domain: ${domainAgents.join(', ') || 'none'}\n`)
|
|
394
|
+
|
|
395
|
+
if (result.skills.length > 0) {
|
|
396
|
+
console.log('📦 Skills Configured')
|
|
397
|
+
for (const skill of result.skills) {
|
|
398
|
+
console.log(`├── ${skill.agent}.md → ${skill.skill}`)
|
|
318
399
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
400
|
+
console.log('')
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (result.git.hasChanges) {
|
|
404
|
+
console.log('⚠️ You have uncommitted changes\n')
|
|
405
|
+
} else {
|
|
406
|
+
console.log('✨ Repository is clean!\n')
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
showNextSteps('sync')
|
|
410
|
+
|
|
411
|
+
// Summary metrics
|
|
412
|
+
const elapsed = Date.now() - startTime
|
|
413
|
+
const contextFilesCount =
|
|
414
|
+
result.contextFiles.length + (result.aiTools?.filter((t) => t.success).length || 0)
|
|
415
|
+
const agentCount = result.agents.length
|
|
416
|
+
|
|
417
|
+
console.log('─'.repeat(45))
|
|
418
|
+
console.log('📊 Sync Summary')
|
|
419
|
+
console.log(
|
|
420
|
+
` Stack: ${result.stats.ecosystem} (${result.stats.frameworks.join(', ') || 'no frameworks'})`
|
|
421
|
+
)
|
|
422
|
+
console.log(` Files: ${result.stats.fileCount} analyzed → ${contextFilesCount} context files`)
|
|
423
|
+
console.log(
|
|
424
|
+
` Agents: ${agentCount} (${result.agents.filter((a) => a.type === 'domain').length} domain)`
|
|
425
|
+
)
|
|
426
|
+
console.log(` Time: ${(elapsed / 1000).toFixed(1)}s`)
|
|
427
|
+
console.log('')
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
success: true,
|
|
431
|
+
data: result,
|
|
432
|
+
metrics: {
|
|
433
|
+
elapsed,
|
|
434
|
+
contextFilesCount,
|
|
435
|
+
agentCount,
|
|
436
|
+
fileCount: result.stats.fileCount,
|
|
437
|
+
},
|
|
322
438
|
}
|
|
323
439
|
}
|
|
324
440
|
|