prjct-cli 1.6.8 → 1.6.10

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +46 -0
  3. package/core/ai-tools/registry.ts +2 -9
  4. package/core/bus/bus.ts +24 -0
  5. package/core/commands/planning.ts +3 -5
  6. package/core/infrastructure/agent-detector.ts +2 -2
  7. package/core/infrastructure/path-manager.ts +3 -17
  8. package/core/integrations/jira/client.ts +3 -77
  9. package/core/server/server.ts +2 -4
  10. package/core/server/sse.ts +115 -59
  11. package/core/services/context-generator.ts +22 -47
  12. package/core/services/diff-generator.ts +18 -43
  13. package/core/services/stack-detector.ts +4 -20
  14. package/core/services/sync-service.ts +35 -106
  15. package/core/services/sync-verifier.ts +17 -37
  16. package/core/services/watch-service.ts +20 -3
  17. package/core/types/citations.ts +22 -0
  18. package/core/types/commands.ts +10 -0
  19. package/core/types/diff.ts +41 -0
  20. package/core/types/errors.ts +111 -0
  21. package/core/types/index.ts +80 -0
  22. package/core/types/infrastructure.ts +14 -0
  23. package/core/types/jira.ts +51 -0
  24. package/core/types/logger.ts +17 -0
  25. package/core/types/output.ts +47 -0
  26. package/core/types/project-sync.ts +109 -0
  27. package/core/types/server.ts +28 -10
  28. package/core/types/services.ts +14 -0
  29. package/core/types/stack.ts +19 -0
  30. package/core/types/sync-verifier.ts +33 -0
  31. package/core/types/workflow.ts +23 -0
  32. package/core/utils/citations.ts +2 -16
  33. package/core/utils/error-messages.ts +5 -139
  34. package/core/utils/logger.ts +3 -11
  35. package/core/utils/output.ts +6 -45
  36. package/core/workflow/workflow-preferences.ts +14 -18
  37. package/dist/bin/prjct.mjs +137 -54
  38. package/package.json +1 -1
@@ -12,50 +12,25 @@
12
12
  import fs from 'node:fs/promises'
13
13
  import path from 'node:path'
14
14
  import pathManager from '../infrastructure/path-manager'
15
+ import type {
16
+ ContextGeneratorConfig,
17
+ GitData,
18
+ ProjectCommands,
19
+ ProjectStats,
20
+ SyncAgentInfo,
21
+ } from '../types'
15
22
  import { type ContextSources, cite, defaultSources } from '../utils/citations'
16
23
  import * as dateHelper from '../utils/date-helper'
17
24
  import { mergePreservedSections, validatePreserveBlocks } from '../utils/preserve-sections'
18
25
  import { NestedContextResolver } from './nested-context-resolver'
19
26
 
20
- // ============================================================================
21
- // TYPES
22
- // ============================================================================
23
-
24
- export interface GitData {
25
- branch: string
26
- commits: number
27
- }
28
-
29
- export interface ProjectStats {
30
- name: string
31
- version: string
32
- ecosystem: string
33
- projectType: string
34
- fileCount: number
35
- languages: string[]
36
- frameworks: string[]
37
- }
38
-
39
- export interface Commands {
40
- install: string
41
- dev: string
42
- test: string
43
- build: string
44
- lint: string
45
- format: string
46
- }
47
-
48
- export interface AgentInfo {
49
- name: string
50
- type: 'workflow' | 'domain'
51
- skill?: string
52
- }
53
-
54
- export interface ContextGeneratorConfig {
55
- projectId: string
56
- projectPath: string
57
- globalPath: string
58
- }
27
+ export type {
28
+ ContextGeneratorConfig,
29
+ GitData,
30
+ ProjectCommands,
31
+ ProjectStats,
32
+ SyncAgentInfo,
33
+ } from '../types'
59
34
 
60
35
  // ============================================================================
61
36
  // CONTEXT FILE GENERATOR
@@ -103,8 +78,8 @@ export class ContextFileGenerator {
103
78
  async generate(
104
79
  git: GitData,
105
80
  stats: ProjectStats,
106
- commands: Commands,
107
- agents: AgentInfo[],
81
+ commands: ProjectCommands,
82
+ agents: SyncAgentInfo[],
108
83
  sources?: ContextSources
109
84
  ): Promise<string[]> {
110
85
  const contextPath = path.join(this.config.globalPath, 'context')
@@ -138,8 +113,8 @@ export class ContextFileGenerator {
138
113
  contextPath: string,
139
114
  git: GitData,
140
115
  stats: ProjectStats,
141
- commands: Commands,
142
- agents: AgentInfo[],
116
+ commands: ProjectCommands,
117
+ agents: SyncAgentInfo[],
143
118
  sources?: ContextSources
144
119
  ): Promise<void> {
145
120
  const workflowAgents = agents.filter((a) => a.type === 'workflow').map((a) => a.name)
@@ -348,8 +323,8 @@ ${
348
323
  async generateMonorepoContexts(
349
324
  git: GitData,
350
325
  stats: ProjectStats,
351
- commands: Commands,
352
- agents: AgentInfo[]
326
+ commands: ProjectCommands,
327
+ agents: SyncAgentInfo[]
353
328
  ): Promise<string[]> {
354
329
  const monoInfo = await pathManager.detectMonorepo(this.config.projectPath)
355
330
 
@@ -394,8 +369,8 @@ ${
394
369
  resolvedCtx: { content: string; sources: string[]; overrides: string[] },
395
370
  git: GitData,
396
371
  stats: ProjectStats,
397
- commands: Commands,
398
- agents: AgentInfo[]
372
+ commands: ProjectCommands,
373
+ agents: SyncAgentInfo[]
399
374
  ): Promise<string> {
400
375
  const workflowAgents = agents.filter((a) => a.type === 'workflow').map((a) => a.name)
401
376
  const domainAgents = agents.filter((a) => a.type === 'domain').map((a) => a.name)
@@ -9,39 +9,21 @@
9
9
  */
10
10
 
11
11
  import chalk from 'chalk'
12
-
13
- // =============================================================================
14
- // Types
15
- // =============================================================================
16
-
17
- export interface DiffSection {
18
- name: string
19
- type: 'added' | 'modified' | 'removed' | 'unchanged'
20
- before?: string
21
- after?: string
22
- lineCount: number
23
- }
24
-
25
- export interface PreservedInfo {
26
- name: string
27
- lineCount: number
28
- }
29
-
30
- export interface SyncDiff {
31
- hasChanges: boolean
32
- added: DiffSection[]
33
- modified: DiffSection[]
34
- removed: DiffSection[]
35
- preserved: PreservedInfo[]
36
- tokensBefore: number
37
- tokensAfter: number
38
- tokenDelta: number
39
- }
40
-
41
- export interface DiffOptions {
42
- showFullDiff?: boolean
43
- colorize?: boolean
44
- }
12
+ import type {
13
+ DiffOptions,
14
+ DiffSection,
15
+ ParsedMarkdownSection,
16
+ PreservedInfo,
17
+ SyncDiff,
18
+ } from '../types'
19
+
20
+ export type {
21
+ DiffOptions,
22
+ DiffSection,
23
+ ParsedMarkdownSection,
24
+ PreservedInfo,
25
+ SyncDiff,
26
+ } from '../types'
45
27
 
46
28
  // =============================================================================
47
29
  // Constants
@@ -64,20 +46,13 @@ export function estimateTokens(content: string): number {
64
46
  // Section Parsing
65
47
  // =============================================================================
66
48
 
67
- interface ParsedSection {
68
- name: string
69
- content: string
70
- startLine: number
71
- endLine: number
72
- }
73
-
74
49
  /**
75
50
  * Parse markdown into sections based on headers
76
51
  */
77
- export function parseMarkdownSections(content: string): ParsedSection[] {
52
+ export function parseMarkdownSections(content: string): ParsedMarkdownSection[] {
78
53
  const lines = content.split('\n')
79
- const sections: ParsedSection[] = []
80
- let currentSection: ParsedSection | null = null
54
+ const sections: ParsedMarkdownSection[] = []
55
+ let currentSection: ParsedMarkdownSection | null = null
81
56
 
82
57
  for (let i = 0; i < lines.length; i++) {
83
58
  const line = lines[i]
@@ -11,25 +11,9 @@
11
11
 
12
12
  import fs from 'node:fs/promises'
13
13
  import path from 'node:path'
14
+ import type { StackDetection, StackPackageJson } from '../types'
14
15
 
15
- // ============================================================================
16
- // TYPES
17
- // ============================================================================
18
-
19
- export interface StackDetection {
20
- hasFrontend: boolean
21
- hasBackend: boolean
22
- hasDatabase: boolean
23
- hasDocker: boolean
24
- hasTesting: boolean
25
- frontendType: 'web' | 'mobile' | 'both' | null
26
- frameworks: string[]
27
- }
28
-
29
- interface PackageJson {
30
- dependencies?: Record<string, string>
31
- devDependencies?: Record<string, string>
32
- }
16
+ export type { StackDetection, StackPackageJson } from '../types'
33
17
 
34
18
  // ============================================================================
35
19
  // STACK DETECTOR
@@ -148,7 +132,7 @@ export class StackDetector {
148
132
  */
149
133
  private detectTesting(
150
134
  deps: Record<string, string>,
151
- pkg: PackageJson,
135
+ pkg: StackPackageJson,
152
136
  stack: StackDetection
153
137
  ): void {
154
138
  const testingFrameworks = [
@@ -219,7 +203,7 @@ export class StackDetector {
219
203
  /**
220
204
  * Read and parse package.json
221
205
  */
222
- private async readPackageJson(): Promise<PackageJson | null> {
206
+ private async readPackageJson(): Promise<StackPackageJson | null> {
223
207
  try {
224
208
  const pkgPath = path.join(this.projectPath, 'package.json')
225
209
  const content = await fs.readFile(pkgPath, 'utf-8')
@@ -32,6 +32,18 @@ import commandInstaller from '../infrastructure/command-installer'
32
32
  import configManager from '../infrastructure/config-manager'
33
33
  import pathManager from '../infrastructure/path-manager'
34
34
  import { metricsStorage } from '../storage/metrics-storage'
35
+ import type {
36
+ AIToolResult,
37
+ GitData,
38
+ ProjectCommands,
39
+ ProjectStats,
40
+ ProjectSyncResult,
41
+ StackDetection,
42
+ SyncAgentInfo,
43
+ SyncMetrics,
44
+ SyncOptions,
45
+ VerificationReport,
46
+ } from '../types'
35
47
  import { type ContextSources, defaultSources, type SourceInfo } from '../utils/citations'
36
48
  import * as dateHelper from '../utils/date-helper'
37
49
  import log from '../utils/logger'
@@ -39,95 +51,11 @@ import { ContextFileGenerator } from './context-generator'
39
51
  import type { SyncDiff } from './diff-generator'
40
52
  import { localStateGenerator } from './local-state-generator'
41
53
  import { skillInstaller } from './skill-installer'
42
- import { type StackDetection, StackDetector } from './stack-detector'
43
- import { syncVerifier, type VerificationReport } from './sync-verifier'
54
+ import { StackDetector } from './stack-detector'
55
+ import { syncVerifier } from './sync-verifier'
44
56
 
45
57
  const execAsync = promisify(exec)
46
58
 
47
- // ============================================================================
48
- // TYPES
49
- // ============================================================================
50
-
51
- interface GitData {
52
- branch: string
53
- commits: number
54
- contributors: number
55
- hasChanges: boolean
56
- stagedFiles: string[]
57
- modifiedFiles: string[]
58
- untrackedFiles: string[]
59
- recentCommits: { hash: string; message: string; date: string }[]
60
- weeklyCommits: number
61
- }
62
-
63
- interface ProjectStats {
64
- fileCount: number
65
- version: string
66
- name: string
67
- ecosystem: string
68
- projectType: string
69
- languages: string[]
70
- frameworks: string[]
71
- }
72
-
73
- interface Commands {
74
- install: string
75
- run: string
76
- test: string
77
- build: string
78
- dev: string
79
- lint: string
80
- format: string
81
- }
82
-
83
- interface AgentInfo {
84
- name: string
85
- type: 'workflow' | 'domain'
86
- skill?: string
87
- }
88
-
89
- interface AIToolResult {
90
- toolId: string
91
- outputFile: string
92
- success: boolean
93
- }
94
-
95
- interface SyncMetrics {
96
- duration: number // Sync duration in ms
97
- originalSize: number // Estimated tokens before compression
98
- filteredSize: number // Actual tokens in context files
99
- compressionRate: number // Percentage saved
100
- }
101
-
102
- interface SyncResult {
103
- success: boolean
104
- projectId: string
105
- cliVersion: string
106
- git: GitData
107
- stats: ProjectStats
108
- commands: Commands
109
- stack: StackDetection
110
- agents: AgentInfo[]
111
- skills: { agent: string; skill: string }[]
112
- skillsInstalled: { name: string; agent: string; status: 'installed' | 'skipped' | 'error' }[]
113
- contextFiles: string[]
114
- aiTools: AIToolResult[]
115
- syncMetrics?: SyncMetrics
116
- verification?: VerificationReport
117
- error?: string
118
- // Preview mode fields
119
- isPreview?: boolean
120
- previewDiff?: SyncDiff
121
- }
122
-
123
- interface SyncOptions {
124
- aiTools?: string[] // AI tools to generate context for (default: claude, cursor)
125
- preview?: boolean // If true, return diff without applying changes
126
- skipConfirmation?: boolean // If true, apply changes without confirmation (--yes flag)
127
- packagePath?: string // For monorepo: sync only this package path
128
- packageName?: string // For monorepo: package name for display
129
- }
130
-
131
59
  // ============================================================================
132
60
  // SYNC SERVICE
133
61
  // ============================================================================
@@ -145,7 +73,10 @@ class SyncService {
145
73
  /**
146
74
  * Main sync method - does everything in one call
147
75
  */
148
- async sync(projectPath: string = process.cwd(), options: SyncOptions = {}): Promise<SyncResult> {
76
+ async sync(
77
+ projectPath: string = process.cwd(),
78
+ options: SyncOptions = {}
79
+ ): Promise<ProjectSyncResult> {
149
80
  this.projectPath = projectPath
150
81
  const startTime = Date.now()
151
82
 
@@ -486,8 +417,8 @@ class SyncService {
486
417
  // COMMAND DETECTION
487
418
  // ==========================================================================
488
419
 
489
- private async detectCommands(): Promise<Commands> {
490
- const commands: Commands = {
420
+ private async detectCommands(): Promise<ProjectCommands> {
421
+ const commands: ProjectCommands = {
491
422
  install: 'npm install',
492
423
  run: 'npm run',
493
424
  test: 'npm test',
@@ -552,7 +483,7 @@ class SyncService {
552
483
  // SOURCE CITATIONS
553
484
  // ==========================================================================
554
485
 
555
- private buildSources(stats: ProjectStats, commands: Commands): ContextSources {
486
+ private buildSources(stats: ProjectStats, commands: ProjectCommands): ContextSources {
556
487
  const sources = defaultSources()
557
488
 
558
489
  // Determine ecosystem source file
@@ -609,8 +540,11 @@ class SyncService {
609
540
  // AGENT GENERATION
610
541
  // ==========================================================================
611
542
 
612
- private async generateAgents(stack: StackDetection, stats: ProjectStats): Promise<AgentInfo[]> {
613
- const agents: AgentInfo[] = []
543
+ private async generateAgents(
544
+ stack: StackDetection,
545
+ stats: ProjectStats
546
+ ): Promise<SyncAgentInfo[]> {
547
+ const agents: SyncAgentInfo[] = []
614
548
  const agentsPath = path.join(this.globalPath, 'agents')
615
549
 
616
550
  // Purge old agents
@@ -822,7 +756,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
822
756
  // SKILL CONFIGURATION
823
757
  // ==========================================================================
824
758
 
825
- private configureSkills(agents: AgentInfo[]): { agent: string; skill: string }[] {
759
+ private configureSkills(agents: SyncAgentInfo[]): { agent: string; skill: string }[] {
826
760
  const skills: { agent: string; skill: string }[] = []
827
761
 
828
762
  for (const agent of agents) {
@@ -862,7 +796,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
862
796
  * Reads the mapping, checks which packages are needed, and installs missing ones.
863
797
  */
864
798
  private async autoInstallSkills(
865
- agents: AgentInfo[]
799
+ agents: SyncAgentInfo[]
866
800
  ): Promise<{ name: string; agent: string; status: 'installed' | 'skipped' | 'error' }[]> {
867
801
  const results: { name: string; agent: string; status: 'installed' | 'skipped' | 'error' }[] = []
868
802
 
@@ -963,8 +897,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
963
897
  private async generateContextFiles(
964
898
  git: GitData,
965
899
  stats: ProjectStats,
966
- commands: Commands,
967
- agents: AgentInfo[],
900
+ commands: ProjectCommands,
901
+ agents: SyncAgentInfo[],
968
902
  sources?: ContextSources
969
903
  ): Promise<string[]> {
970
904
  const generator = new ContextFileGenerator({
@@ -973,13 +907,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
973
907
  globalPath: this.globalPath,
974
908
  })
975
909
 
976
- return generator.generate(
977
- { branch: git.branch, commits: git.commits },
978
- stats,
979
- commands,
980
- agents,
981
- sources
982
- )
910
+ return generator.generate(git, stats, commands, agents, sources)
983
911
  }
984
912
 
985
913
  // ==========================================================================
@@ -1112,7 +1040,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
1112
1040
  private async recordSyncMetrics(
1113
1041
  stats: ProjectStats,
1114
1042
  contextFiles: string[],
1115
- agents: AgentInfo[],
1043
+ agents: SyncAgentInfo[],
1116
1044
  duration: number
1117
1045
  ): Promise<SyncMetrics> {
1118
1046
  const CHARS_PER_TOKEN = 4
@@ -1229,7 +1157,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
1229
1157
  }
1230
1158
  }
1231
1159
 
1232
- private emptyCommands(): Commands {
1160
+ private emptyCommands(): ProjectCommands {
1233
1161
  return {
1234
1162
  install: 'npm install',
1235
1163
  run: 'npm run',
@@ -1255,4 +1183,5 @@ You are the ${name} expert for this project. Apply best practices for the detect
1255
1183
  }
1256
1184
 
1257
1185
  export const syncService = new SyncService()
1258
- export { SyncService, type SyncResult }
1186
+ export { SyncService }
1187
+ export type { ProjectSyncResult as SyncResult } from '../types'
@@ -11,42 +11,22 @@ import { exec } from 'node:child_process'
11
11
  import fs from 'node:fs/promises'
12
12
  import path from 'node:path'
13
13
  import { promisify } from 'node:util'
14
+ import type {
15
+ VerificationCheck,
16
+ VerificationCheckResult,
17
+ VerificationConfig,
18
+ VerificationReport,
19
+ } from '../types'
14
20
  import { getErrorMessage, isNotFoundError } from '../types/fs'
15
21
 
16
22
  const execAsync = promisify(exec)
17
23
 
18
- // =============================================================================
19
- // TYPES
20
- // =============================================================================
21
-
22
- export interface VerificationCheck {
23
- name: string
24
- command?: string
25
- script?: string
26
- enabled?: boolean
27
- }
28
-
29
- export interface VerificationConfig {
30
- checks?: VerificationCheck[]
31
- failFast?: boolean
32
- }
33
-
34
- export interface CheckResult {
35
- name: string
36
- passed: boolean
37
- output?: string
38
- error?: string
39
- durationMs: number
40
- }
41
-
42
- export interface VerificationReport {
43
- passed: boolean
44
- checks: CheckResult[]
45
- totalMs: number
46
- failedCount: number
47
- passedCount: number
48
- skippedCount: number
49
- }
24
+ export type {
25
+ VerificationCheck,
26
+ VerificationCheckResult,
27
+ VerificationConfig,
28
+ VerificationReport,
29
+ } from '../types'
50
30
 
51
31
  // =============================================================================
52
32
  // BUILT-IN CHECKS
@@ -56,7 +36,7 @@ const BUILTIN_CHECKS = {
56
36
  /**
57
37
  * Verify all expected context files exist after sync
58
38
  */
59
- async contextFilesExist(globalPath: string): Promise<CheckResult> {
39
+ async contextFilesExist(globalPath: string): Promise<VerificationCheckResult> {
60
40
  const start = Date.now()
61
41
  const expected = ['context/CLAUDE.md']
62
42
  const missing: string[] = []
@@ -82,7 +62,7 @@ const BUILTIN_CHECKS = {
82
62
  /**
83
63
  * Verify generated JSON files are valid
84
64
  */
85
- async jsonFilesValid(globalPath: string): Promise<CheckResult> {
65
+ async jsonFilesValid(globalPath: string): Promise<VerificationCheckResult> {
86
66
  const start = Date.now()
87
67
  const jsonFiles = ['storage/state.json']
88
68
  const invalid: string[] = []
@@ -111,7 +91,7 @@ const BUILTIN_CHECKS = {
111
91
  /**
112
92
  * Verify no sensitive data leaked into context files
113
93
  */
114
- async noSensitiveData(globalPath: string): Promise<CheckResult> {
94
+ async noSensitiveData(globalPath: string): Promise<VerificationCheckResult> {
115
95
  const start = Date.now()
116
96
  const contextDir = path.join(globalPath, 'context')
117
97
  const patterns = [
@@ -168,7 +148,7 @@ class SyncVerifier {
168
148
  config?: VerificationConfig
169
149
  ): Promise<VerificationReport> {
170
150
  const totalStart = Date.now()
171
- const checks: CheckResult[] = []
151
+ const checks: VerificationCheckResult[] = []
172
152
  const failFast = config?.failFast ?? false
173
153
  let skipped = 0
174
154
 
@@ -228,7 +208,7 @@ class SyncVerifier {
228
208
  private async runCustomCheck(
229
209
  check: VerificationCheck,
230
210
  projectPath: string
231
- ): Promise<CheckResult> {
211
+ ): Promise<VerificationCheckResult> {
232
212
  const start = Date.now()
233
213
  const command = check.command || (check.script ? `sh ${check.script}` : null)
234
214
 
@@ -102,6 +102,8 @@ class WatchService {
102
102
  }
103
103
  private isRunning: boolean = false
104
104
  private syncCount: number = 0
105
+ private sigintHandler: (() => void) | null = null
106
+ private sigtermHandler: (() => void) | null = null
105
107
 
106
108
  /**
107
109
  * Start watching for file changes
@@ -151,9 +153,13 @@ class WatchService {
151
153
  .on('unlink', (filePath: string) => this.handleChange('unlink', filePath))
152
154
  .on('error', (error: unknown) => this.handleError(error as Error))
153
155
 
154
- // Handle graceful shutdown
155
- process.on('SIGINT', () => this.stop())
156
- process.on('SIGTERM', () => this.stop())
156
+ // Handle graceful shutdown — store references for proper removal
157
+ if (this.sigintHandler) process.off('SIGINT', this.sigintHandler)
158
+ if (this.sigtermHandler) process.off('SIGTERM', this.sigtermHandler)
159
+ this.sigintHandler = () => this.stop()
160
+ this.sigtermHandler = () => this.stop()
161
+ process.on('SIGINT', this.sigintHandler)
162
+ process.on('SIGTERM', this.sigtermHandler)
157
163
 
158
164
  return { success: true }
159
165
  }
@@ -177,6 +183,17 @@ class WatchService {
177
183
  this.watcher = null
178
184
  }
179
185
 
186
+ // Remove signal handlers to prevent accumulation
187
+ if (this.sigintHandler) {
188
+ process.off('SIGINT', this.sigintHandler)
189
+ this.sigintHandler = null
190
+ }
191
+ if (this.sigtermHandler) {
192
+ process.off('SIGTERM', this.sigtermHandler)
193
+ this.sigtermHandler = null
194
+ }
195
+
196
+ this.pendingChanges.clear()
180
197
  this.isRunning = false
181
198
  process.exit(0)
182
199
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Citation Types
3
+ * Types for context source tracking.
4
+ */
5
+
6
+ export type SourceType = 'detected' | 'user-defined' | 'inferred'
7
+
8
+ export interface SourceInfo {
9
+ file: string
10
+ type: SourceType
11
+ }
12
+
13
+ export interface ContextSources {
14
+ name: SourceInfo
15
+ version: SourceInfo
16
+ ecosystem: SourceInfo
17
+ languages: SourceInfo
18
+ frameworks: SourceInfo
19
+ commands: SourceInfo
20
+ projectType: SourceInfo
21
+ git: SourceInfo
22
+ }
@@ -157,6 +157,16 @@ export interface AnalyzeOptions {
157
157
  [key: string]: unknown
158
158
  }
159
159
 
160
+ /**
161
+ * Options for the init (planning) command.
162
+ */
163
+ export interface InitOptions {
164
+ /** Skip interactive wizard, use defaults */
165
+ yes?: boolean
166
+ /** Initial idea for architect mode */
167
+ idea?: string | null
168
+ }
169
+
160
170
  // ============================================
161
171
  // Migration Types
162
172
  // ============================================
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Diff Types
3
+ * Types for sync diff and preserved sections.
4
+ */
5
+
6
+ export interface DiffSection {
7
+ name: string
8
+ type: 'added' | 'modified' | 'removed' | 'unchanged'
9
+ before?: string
10
+ after?: string
11
+ lineCount: number
12
+ }
13
+
14
+ export interface PreservedInfo {
15
+ name: string
16
+ lineCount: number
17
+ }
18
+
19
+ export interface SyncDiff {
20
+ hasChanges: boolean
21
+ added: DiffSection[]
22
+ modified: DiffSection[]
23
+ removed: DiffSection[]
24
+ preserved: PreservedInfo[]
25
+ tokensBefore: number
26
+ tokensAfter: number
27
+ tokenDelta: number
28
+ }
29
+
30
+ export interface DiffOptions {
31
+ showFullDiff?: boolean
32
+ colorize?: boolean
33
+ }
34
+
35
+ /** Parsed markdown section (header + content range) */
36
+ export interface ParsedMarkdownSection {
37
+ name: string
38
+ content: string
39
+ startLine: number
40
+ endLine: number
41
+ }