prjct-cli 0.45.0 → 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.
Files changed (207) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/bin/prjct.ts +117 -10
  3. package/core/__tests__/agentic/memory-system.test.ts +39 -26
  4. package/core/__tests__/agentic/plan-mode.test.ts +64 -46
  5. package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
  6. package/core/__tests__/services/project-index.test.ts +353 -0
  7. package/core/__tests__/types/fs.test.ts +3 -3
  8. package/core/__tests__/utils/date-helper.test.ts +10 -10
  9. package/core/__tests__/utils/output.test.ts +9 -6
  10. package/core/__tests__/utils/project-commands.test.ts +5 -6
  11. package/core/agentic/agent-router.ts +9 -10
  12. package/core/agentic/chain-of-thought.ts +16 -4
  13. package/core/agentic/command-executor.ts +66 -40
  14. package/core/agentic/context-builder.ts +8 -5
  15. package/core/agentic/ground-truth.ts +15 -9
  16. package/core/agentic/index.ts +145 -152
  17. package/core/agentic/loop-detector.ts +40 -11
  18. package/core/agentic/memory-system.ts +98 -35
  19. package/core/agentic/orchestrator-executor.ts +135 -71
  20. package/core/agentic/plan-mode.ts +46 -16
  21. package/core/agentic/prompt-builder.ts +108 -42
  22. package/core/agentic/services.ts +10 -9
  23. package/core/agentic/skill-loader.ts +9 -15
  24. package/core/agentic/smart-context.ts +129 -79
  25. package/core/agentic/template-executor.ts +13 -12
  26. package/core/agentic/template-loader.ts +7 -4
  27. package/core/agentic/tool-registry.ts +16 -13
  28. package/core/agents/index.ts +1 -1
  29. package/core/agents/performance.ts +10 -27
  30. package/core/ai-tools/formatters.ts +8 -6
  31. package/core/ai-tools/generator.ts +4 -4
  32. package/core/ai-tools/index.ts +1 -1
  33. package/core/ai-tools/registry.ts +21 -11
  34. package/core/bus/bus.ts +23 -16
  35. package/core/bus/index.ts +2 -2
  36. package/core/cli/linear.ts +3 -5
  37. package/core/cli/start.ts +28 -25
  38. package/core/commands/analysis.ts +58 -39
  39. package/core/commands/analytics.ts +52 -44
  40. package/core/commands/base.ts +15 -13
  41. package/core/commands/cleanup.ts +6 -13
  42. package/core/commands/command-data.ts +28 -4
  43. package/core/commands/commands.ts +57 -24
  44. package/core/commands/context.ts +4 -4
  45. package/core/commands/design.ts +3 -10
  46. package/core/commands/index.ts +5 -8
  47. package/core/commands/maintenance.ts +7 -4
  48. package/core/commands/planning.ts +179 -56
  49. package/core/commands/register.ts +13 -9
  50. package/core/commands/registry.ts +15 -14
  51. package/core/commands/setup.ts +26 -14
  52. package/core/commands/shipping.ts +11 -16
  53. package/core/commands/snapshots.ts +16 -32
  54. package/core/commands/uninstall.ts +541 -0
  55. package/core/commands/workflow.ts +24 -28
  56. package/core/constants/index.ts +10 -22
  57. package/core/context/generator.ts +82 -33
  58. package/core/context-tools/files-tool.ts +18 -19
  59. package/core/context-tools/imports-tool.ts +13 -33
  60. package/core/context-tools/index.ts +29 -54
  61. package/core/context-tools/recent-tool.ts +16 -22
  62. package/core/context-tools/signatures-tool.ts +17 -26
  63. package/core/context-tools/summary-tool.ts +20 -22
  64. package/core/context-tools/token-counter.ts +25 -20
  65. package/core/context-tools/types.ts +5 -5
  66. package/core/domain/agent-generator.ts +7 -5
  67. package/core/domain/agent-loader.ts +2 -2
  68. package/core/domain/analyzer.ts +19 -16
  69. package/core/domain/architecture-generator.ts +6 -3
  70. package/core/domain/context-estimator.ts +3 -4
  71. package/core/domain/snapshot-manager.ts +25 -22
  72. package/core/domain/task-stack.ts +24 -14
  73. package/core/errors.ts +1 -1
  74. package/core/events/events.ts +2 -4
  75. package/core/events/index.ts +1 -2
  76. package/core/index.ts +28 -16
  77. package/core/infrastructure/agent-detector.ts +3 -3
  78. package/core/infrastructure/ai-provider.ts +23 -20
  79. package/core/infrastructure/author-detector.ts +16 -10
  80. package/core/infrastructure/capability-installer.ts +2 -2
  81. package/core/infrastructure/claude-agent.ts +6 -6
  82. package/core/infrastructure/command-installer.ts +22 -17
  83. package/core/infrastructure/config-manager.ts +18 -14
  84. package/core/infrastructure/editors-config.ts +8 -4
  85. package/core/infrastructure/path-manager.ts +8 -6
  86. package/core/infrastructure/permission-manager.ts +20 -17
  87. package/core/infrastructure/setup.ts +42 -38
  88. package/core/infrastructure/update-checker.ts +5 -5
  89. package/core/integrations/issue-tracker/enricher.ts +8 -19
  90. package/core/integrations/issue-tracker/index.ts +2 -2
  91. package/core/integrations/issue-tracker/manager.ts +15 -15
  92. package/core/integrations/issue-tracker/types.ts +5 -22
  93. package/core/integrations/jira/client.ts +67 -59
  94. package/core/integrations/jira/index.ts +11 -14
  95. package/core/integrations/jira/mcp-adapter.ts +5 -10
  96. package/core/integrations/jira/service.ts +10 -10
  97. package/core/integrations/linear/client.ts +27 -18
  98. package/core/integrations/linear/index.ts +9 -12
  99. package/core/integrations/linear/service.ts +11 -11
  100. package/core/integrations/linear/sync.ts +8 -8
  101. package/core/outcomes/analyzer.ts +5 -18
  102. package/core/outcomes/index.ts +2 -2
  103. package/core/outcomes/recorder.ts +3 -3
  104. package/core/plugin/builtin/webhook.ts +19 -15
  105. package/core/plugin/hooks.ts +29 -21
  106. package/core/plugin/index.ts +7 -7
  107. package/core/plugin/loader.ts +19 -19
  108. package/core/plugin/registry.ts +12 -23
  109. package/core/schemas/agents.ts +1 -1
  110. package/core/schemas/analysis.ts +1 -1
  111. package/core/schemas/enriched-task.ts +62 -49
  112. package/core/schemas/ideas.ts +13 -13
  113. package/core/schemas/index.ts +17 -27
  114. package/core/schemas/issues.ts +40 -25
  115. package/core/schemas/metrics.ts +25 -25
  116. package/core/schemas/outcomes.ts +70 -62
  117. package/core/schemas/permissions.ts +15 -12
  118. package/core/schemas/prd.ts +27 -14
  119. package/core/schemas/project.ts +3 -3
  120. package/core/schemas/roadmap.ts +47 -34
  121. package/core/schemas/schemas.ts +3 -4
  122. package/core/schemas/shipped.ts +3 -3
  123. package/core/schemas/state.ts +43 -29
  124. package/core/server/index.ts +5 -6
  125. package/core/server/routes-extended.ts +68 -72
  126. package/core/server/routes.ts +3 -3
  127. package/core/server/server.ts +31 -26
  128. package/core/services/agent-generator.ts +237 -0
  129. package/core/services/agent-service.ts +2 -2
  130. package/core/services/breakdown-service.ts +2 -4
  131. package/core/services/context-generator.ts +299 -0
  132. package/core/services/context-selector.ts +420 -0
  133. package/core/services/doctor-service.ts +426 -0
  134. package/core/services/file-categorizer.ts +448 -0
  135. package/core/services/file-scorer.ts +270 -0
  136. package/core/services/git-analyzer.ts +267 -0
  137. package/core/services/index.ts +27 -10
  138. package/core/services/memory-service.ts +3 -4
  139. package/core/services/project-index.ts +911 -0
  140. package/core/services/project-service.ts +4 -4
  141. package/core/services/skill-installer.ts +14 -17
  142. package/core/services/skill-lock.ts +3 -3
  143. package/core/services/skill-service.ts +12 -6
  144. package/core/services/stack-detector.ts +245 -0
  145. package/core/services/sync-service.ts +87 -345
  146. package/core/services/watch-service.ts +294 -0
  147. package/core/session/compaction.ts +23 -31
  148. package/core/session/index.ts +11 -5
  149. package/core/session/log-migration.ts +3 -3
  150. package/core/session/metrics.ts +19 -14
  151. package/core/session/session-log-manager.ts +12 -17
  152. package/core/session/task-session-manager.ts +25 -25
  153. package/core/session/utils.ts +1 -1
  154. package/core/storage/ideas-storage.ts +41 -57
  155. package/core/storage/index-storage.ts +514 -0
  156. package/core/storage/index.ts +41 -17
  157. package/core/storage/metrics-storage.ts +39 -34
  158. package/core/storage/queue-storage.ts +35 -45
  159. package/core/storage/shipped-storage.ts +17 -20
  160. package/core/storage/state-storage.ts +50 -30
  161. package/core/storage/storage-manager.ts +6 -6
  162. package/core/storage/storage.ts +18 -15
  163. package/core/sync/auth-config.ts +3 -3
  164. package/core/sync/index.ts +13 -19
  165. package/core/sync/oauth-handler.ts +3 -3
  166. package/core/sync/sync-client.ts +4 -9
  167. package/core/sync/sync-manager.ts +12 -14
  168. package/core/types/commands.ts +42 -7
  169. package/core/types/index.ts +284 -305
  170. package/core/types/integrations.ts +3 -3
  171. package/core/types/storage.ts +14 -14
  172. package/core/types/utils.ts +3 -3
  173. package/core/utils/agent-stream.ts +3 -1
  174. package/core/utils/animations.ts +14 -11
  175. package/core/utils/branding.ts +7 -7
  176. package/core/utils/cache.ts +1 -3
  177. package/core/utils/collection-filters.ts +3 -15
  178. package/core/utils/date-helper.ts +2 -7
  179. package/core/utils/file-helper.ts +13 -8
  180. package/core/utils/jsonl-helper.ts +13 -10
  181. package/core/utils/keychain.ts +4 -8
  182. package/core/utils/logger.ts +1 -1
  183. package/core/utils/next-steps.ts +3 -3
  184. package/core/utils/output.ts +58 -11
  185. package/core/utils/project-commands.ts +6 -6
  186. package/core/utils/project-credentials.ts +5 -12
  187. package/core/utils/runtime.ts +2 -2
  188. package/core/utils/session-helper.ts +3 -4
  189. package/core/utils/version.ts +3 -3
  190. package/core/wizard/index.ts +13 -0
  191. package/core/wizard/onboarding.ts +633 -0
  192. package/core/workflow/state-machine.ts +7 -7
  193. package/dist/bin/prjct.mjs +18755 -15574
  194. package/dist/core/infrastructure/command-installer.js +86 -79
  195. package/dist/core/infrastructure/editors-config.js +6 -6
  196. package/dist/core/infrastructure/setup.js +246 -225
  197. package/dist/core/utils/version.js +9 -9
  198. package/package.json +11 -12
  199. package/scripts/build.js +3 -3
  200. package/scripts/postinstall.js +2 -2
  201. package/templates/mcp-config.json +6 -1
  202. package/templates/permissions/permissive.jsonc +1 -1
  203. package/templates/permissions/strict.jsonc +5 -9
  204. package/templates/global/docs/agents.md +0 -88
  205. package/templates/global/docs/architecture.md +0 -103
  206. package/templates/global/docs/commands.md +0 -96
  207. package/templates/global/docs/validation.md +0 -95
@@ -3,26 +3,26 @@
3
3
  * Orchestrates multiple issue tracker providers and enrichment.
4
4
  */
5
5
 
6
- import type {
7
- IssueTrackerProvider,
8
- IssueTrackerConfig,
9
- Issue,
10
- EnrichedIssue,
11
- SyncResult,
12
- FetchOptions,
13
- CreateIssueInput,
14
- IssueProvider,
15
- } from './types'
6
+ import { jiraProvider } from '../jira/client'
7
+ import { linearProvider } from '../linear/client'
16
8
  import {
17
- generateEnrichmentPrompt,
18
9
  buildEnrichedIssue,
10
+ type EnrichmentResult,
19
11
  formatEnrichmentAsMarkdown,
12
+ generateEnrichmentPrompt,
20
13
  generateQuickEnrichment,
21
14
  type ProjectContext,
22
- type EnrichmentResult,
23
15
  } from './enricher'
24
- import { linearProvider } from '../linear/client'
25
- import { jiraProvider } from '../jira/client'
16
+ import type {
17
+ CreateIssueInput,
18
+ EnrichedIssue,
19
+ FetchOptions,
20
+ Issue,
21
+ IssueProvider,
22
+ IssueTrackerConfig,
23
+ IssueTrackerProvider,
24
+ SyncResult,
25
+ } from './types'
26
26
 
27
27
  // =============================================================================
28
28
  // Manager Class
@@ -232,7 +232,7 @@ export class IssueTrackerManager {
232
232
  for (const issue of issues) {
233
233
  try {
234
234
  // Generate prompt (actual AI execution is external)
235
- const prompt = this.getEnrichmentPrompt(issue, projectContext)
235
+ const _prompt = this.getEnrichmentPrompt(issue, projectContext)
236
236
  console.log(`[issue-tracker] Enrichment prompt ready for ${issue.externalId}`)
237
237
 
238
238
  // For now, use quick enrichment as placeholder
@@ -95,28 +95,11 @@ export interface UpdateIssueInput {
95
95
 
96
96
  export type IssueProvider = 'linear' | 'jira' | 'monday' | 'github' | 'asana' | 'none'
97
97
 
98
- export type IssueStatus =
99
- | 'backlog'
100
- | 'todo'
101
- | 'in_progress'
102
- | 'in_review'
103
- | 'done'
104
- | 'cancelled'
105
-
106
- export type IssuePriority =
107
- | 'none'
108
- | 'urgent'
109
- | 'high'
110
- | 'medium'
111
- | 'low'
112
-
113
- export type IssueType =
114
- | 'feature'
115
- | 'bug'
116
- | 'improvement'
117
- | 'task'
118
- | 'chore'
119
- | 'epic'
98
+ export type IssueStatus = 'backlog' | 'todo' | 'in_progress' | 'in_review' | 'done' | 'cancelled'
99
+
100
+ export type IssuePriority = 'none' | 'urgent' | 'high' | 'medium' | 'low'
101
+
102
+ export type IssueType = 'feature' | 'bug' | 'improvement' | 'task' | 'chore' | 'epic'
120
103
 
121
104
  // =============================================================================
122
105
  // Provider Interface
@@ -15,15 +15,15 @@
15
15
  */
16
16
 
17
17
  import type {
18
- IssueTrackerProvider,
19
- Issue,
20
18
  CreateIssueInput,
21
- UpdateIssueInput,
22
19
  FetchOptions,
23
- JiraConfig,
24
- IssueStatus,
20
+ Issue,
25
21
  IssuePriority,
22
+ IssueStatus,
23
+ IssueTrackerProvider,
26
24
  IssueType,
25
+ JiraConfig,
26
+ UpdateIssueInput,
27
27
  } from '../issue-tracker/types'
28
28
 
29
29
  // =============================================================================
@@ -36,13 +36,16 @@ interface JiraIssue {
36
36
  self: string
37
37
  fields: {
38
38
  summary: string
39
- description?: {
40
- type: string
41
- content: Array<{
42
- type: string
43
- content?: Array<{ type: string; text?: string }>
44
- }>
45
- } | string | null
39
+ description?:
40
+ | {
41
+ type: string
42
+ content: Array<{
43
+ type: string
44
+ content?: Array<{ type: string; text?: string }>
45
+ }>
46
+ }
47
+ | string
48
+ | null
46
49
  status: {
47
50
  id: string
48
51
  name: string
@@ -114,7 +117,7 @@ const JIRA_STATUS_CATEGORY_MAP: Record<string, IssueStatus> = {
114
117
  const JIRA_STATUS_NAME_MAP: Record<string, IssueStatus> = {
115
118
  // Backlog states
116
119
  backlog: 'backlog',
117
- 'open': 'backlog',
120
+ open: 'backlog',
118
121
  'to do': 'todo',
119
122
  todo: 'todo',
120
123
  new: 'todo',
@@ -124,7 +127,7 @@ const JIRA_STATUS_NAME_MAP: Record<string, IssueStatus> = {
124
127
  'in development': 'in_progress',
125
128
  'in review': 'in_review',
126
129
  'code review': 'in_review',
127
- 'review': 'in_review',
130
+ review: 'in_review',
128
131
 
129
132
  // Done states
130
133
  done: 'done',
@@ -241,13 +244,19 @@ export class JiraProvider implements IssueTrackerProvider {
241
244
 
242
245
  // Verify connection by fetching current user
243
246
  try {
244
- const response = await this.request<{ accountId: string; displayName: string; emailAddress?: string }>('/rest/api/3/myself')
247
+ const response = await this.request<{
248
+ accountId: string
249
+ displayName: string
250
+ emailAddress?: string
251
+ }>('/rest/api/3/myself')
245
252
  this.currentUser = {
246
253
  accountId: response.accountId,
247
254
  displayName: response.displayName,
248
255
  email: response.emailAddress,
249
256
  }
250
- console.log(`[jira] Connected as ${this.currentUser.displayName} (${this.currentUser.email || 'no email'})`)
257
+ console.log(
258
+ `[jira] Connected as ${this.currentUser.displayName} (${this.currentUser.email || 'no email'})`
259
+ )
251
260
  } catch (error) {
252
261
  this.baseUrl = ''
253
262
  this.auth = ''
@@ -360,7 +369,7 @@ export class JiraProvider implements IssueTrackerProvider {
360
369
 
361
370
  // Add optional fields
362
371
  if (input.description) {
363
- (payload.fields as Record<string, unknown>).description = {
372
+ ;(payload.fields as Record<string, unknown>).description = {
364
373
  type: 'doc',
365
374
  version: 1,
366
375
  content: [
@@ -373,28 +382,25 @@ export class JiraProvider implements IssueTrackerProvider {
373
382
  }
374
383
 
375
384
  if (input.priority) {
376
- (payload.fields as Record<string, unknown>).priority = {
385
+ ;(payload.fields as Record<string, unknown>).priority = {
377
386
  name: PRIORITY_TO_JIRA[input.priority],
378
387
  }
379
388
  }
380
389
 
381
390
  if (input.labels?.length) {
382
- (payload.fields as Record<string, unknown>).labels = input.labels
391
+ ;(payload.fields as Record<string, unknown>).labels = input.labels
383
392
  }
384
393
 
385
394
  if (input.assigneeId) {
386
- (payload.fields as Record<string, unknown>).assignee = {
395
+ ;(payload.fields as Record<string, unknown>).assignee = {
387
396
  accountId: input.assigneeId,
388
397
  }
389
398
  }
390
399
 
391
- const created = await this.request<{ id: string; key: string }>(
392
- '/rest/api/3/issue',
393
- {
394
- method: 'POST',
395
- body: JSON.stringify(payload),
396
- }
397
- )
400
+ const created = await this.request<{ id: string; key: string }>('/rest/api/3/issue', {
401
+ method: 'POST',
402
+ body: JSON.stringify(payload),
403
+ })
398
404
 
399
405
  // Fetch the full issue
400
406
  const issue = await this.fetchIssue(created.key)
@@ -414,7 +420,7 @@ export class JiraProvider implements IssueTrackerProvider {
414
420
  const payload: Record<string, unknown> = { fields: {} }
415
421
 
416
422
  if (input.description) {
417
- (payload.fields as Record<string, unknown>).description = {
423
+ ;(payload.fields as Record<string, unknown>).description = {
418
424
  type: 'doc',
419
425
  version: 1,
420
426
  content: this.markdownToADF(input.description),
@@ -442,9 +448,9 @@ export class JiraProvider implements IssueTrackerProvider {
442
448
  if (!this.isConfigured()) throw new Error('JIRA not initialized')
443
449
 
444
450
  // Get available transitions
445
- const transitions = await this.request<{ transitions: Array<{ id: string; name: string; to: { statusCategory: { key: string } } }> }>(
446
- `/rest/api/3/issue/${id}/transitions`
447
- )
451
+ const transitions = await this.request<{
452
+ transitions: Array<{ id: string; name: string; to: { statusCategory: { key: string } } }>
453
+ }>(`/rest/api/3/issue/${id}/transitions`)
448
454
 
449
455
  // Find transition to "in progress" state
450
456
  const inProgressTransition = transitions.transitions.find(
@@ -469,9 +475,9 @@ export class JiraProvider implements IssueTrackerProvider {
469
475
  if (!this.isConfigured()) throw new Error('JIRA not initialized')
470
476
 
471
477
  // Get available transitions
472
- const transitions = await this.request<{ transitions: Array<{ id: string; name: string; to: { statusCategory: { key: string } } }> }>(
473
- `/rest/api/3/issue/${id}/transitions`
474
- )
478
+ const transitions = await this.request<{
479
+ transitions: Array<{ id: string; name: string; to: { statusCategory: { key: string } } }>
480
+ }>(`/rest/api/3/issue/${id}/transitions`)
475
481
 
476
482
  // Find transition to "done" state
477
483
  const doneTransition = transitions.transitions.find(
@@ -556,9 +562,7 @@ export class JiraProvider implements IssueTrackerProvider {
556
562
 
557
563
  // Try exact status name match first, then category
558
564
  const status: IssueStatus =
559
- JIRA_STATUS_NAME_MAP[statusName] ||
560
- JIRA_STATUS_CATEGORY_MAP[statusCategory] ||
561
- 'backlog'
565
+ JIRA_STATUS_NAME_MAP[statusName] || JIRA_STATUS_CATEGORY_MAP[statusCategory] || 'backlog'
562
566
 
563
567
  const priorityName = jiraIssue.fields.priority?.name?.toLowerCase() || 'medium'
564
568
  const priority: IssuePriority = JIRA_PRIORITY_MAP[priorityName] || 'medium'
@@ -599,9 +603,7 @@ export class JiraProvider implements IssueTrackerProvider {
599
603
  /**
600
604
  * Extract plain text from JIRA description (ADF or string)
601
605
  */
602
- private extractDescription(
603
- description: JiraIssue['fields']['description']
604
- ): string | undefined {
606
+ private extractDescription(description: JiraIssue['fields']['description']): string | undefined {
605
607
  if (!description) return undefined
606
608
 
607
609
  // Handle string descriptions (older JIRA versions)
@@ -661,34 +663,42 @@ export class JiraProvider implements IssueTrackerProvider {
661
663
  content.push({
662
664
  type: 'taskList',
663
665
  attrs: { localId: crypto.randomUUID() },
664
- content: [{
665
- type: 'taskItem',
666
- attrs: { localId: crypto.randomUUID(), state: 'TODO' },
667
- content: [{ type: 'text', text: line.slice(6) }],
668
- }],
666
+ content: [
667
+ {
668
+ type: 'taskItem',
669
+ attrs: { localId: crypto.randomUUID(), state: 'TODO' },
670
+ content: [{ type: 'text', text: line.slice(6) }],
671
+ },
672
+ ],
669
673
  })
670
674
  } else if (line.startsWith('- [x] ')) {
671
675
  // Checkbox checked
672
676
  content.push({
673
677
  type: 'taskList',
674
678
  attrs: { localId: crypto.randomUUID() },
675
- content: [{
676
- type: 'taskItem',
677
- attrs: { localId: crypto.randomUUID(), state: 'DONE' },
678
- content: [{ type: 'text', text: line.slice(6) }],
679
- }],
679
+ content: [
680
+ {
681
+ type: 'taskItem',
682
+ attrs: { localId: crypto.randomUUID(), state: 'DONE' },
683
+ content: [{ type: 'text', text: line.slice(6) }],
684
+ },
685
+ ],
680
686
  })
681
687
  } else if (line.startsWith('- ')) {
682
688
  // Bullet point
683
689
  content.push({
684
690
  type: 'bulletList',
685
- content: [{
686
- type: 'listItem',
687
- content: [{
688
- type: 'paragraph',
689
- content: [{ type: 'text', text: line.slice(2) }],
690
- }],
691
- }],
691
+ content: [
692
+ {
693
+ type: 'listItem',
694
+ content: [
695
+ {
696
+ type: 'paragraph',
697
+ content: [{ type: 'text', text: line.slice(2) }],
698
+ },
699
+ ],
700
+ },
701
+ ],
692
702
  })
693
703
  } else if (line.trim()) {
694
704
  // Regular paragraph
@@ -741,8 +751,6 @@ export class JiraProvider implements IssueTrackerProvider {
741
751
  return 'Improvement'
742
752
  case 'epic':
743
753
  return 'Epic'
744
- case 'chore':
745
- case 'task':
746
754
  default:
747
755
  return 'Task'
748
756
  }
@@ -9,33 +9,30 @@
9
9
  * - JIRA_API_TOKEN: API token from https://id.atlassian.com/manage-profile/security/api-tokens
10
10
  */
11
11
 
12
- // REST API client
13
- export { JiraProvider, jiraProvider, type JiraAuthMode } from './client'
14
-
15
- // Service layer with caching (preferred API)
16
- export { JiraService, jiraService } from './service'
17
-
18
12
  // Cache utilities
19
13
  export {
20
- issueCache,
21
14
  assignedIssuesCache,
22
- projectsCache,
23
15
  clearJiraCache,
24
16
  getJiraCacheStats,
17
+ issueCache,
18
+ projectsCache,
25
19
  } from './cache'
26
-
20
+ // REST API client
21
+ export { type JiraAuthMode, JiraProvider, jiraProvider } from './client'
27
22
  // MCP adapter (deprecated - will be removed)
28
23
  export {
29
- JiraMCPAdapter,
30
- jiraMCPAdapter,
24
+ createCreateIssueInstruction,
25
+ createGetIssueInstruction,
31
26
  // MCP instruction generators
32
27
  createSearchInstruction,
33
- createGetIssueInstruction,
34
28
  createTransitionInstruction,
35
29
  createUpdateInstruction,
36
- createCreateIssueInstruction,
30
+ getMCPSetupInstructions,
37
31
  // Utilities
38
32
  isMCPAvailable,
39
- getMCPSetupInstructions,
33
+ JiraMCPAdapter,
34
+ jiraMCPAdapter,
40
35
  type MCPInstruction,
41
36
  } from './mcp-adapter'
37
+ // Service layer with caching (preferred API)
38
+ export { JiraService, jiraService } from './service'
@@ -19,15 +19,14 @@
19
19
  */
20
20
 
21
21
  import type {
22
- IssueTrackerProvider,
23
- Issue,
24
22
  CreateIssueInput,
25
- UpdateIssueInput,
26
23
  FetchOptions,
27
- JiraConfig,
28
- IssueStatus,
24
+ Issue,
29
25
  IssuePriority,
26
+ IssueStatus,
27
+ IssueTrackerProvider,
30
28
  IssueType,
29
+ JiraConfig,
31
30
  } from '../issue-tracker/types'
32
31
 
33
32
  // =============================================================================
@@ -323,9 +322,7 @@ export class JiraMCPAdapter implements Partial<IssueTrackerProvider> {
323
322
  const statusCategory = mcpIssue.fields.status.statusCategory?.key || ''
324
323
 
325
324
  const status: IssueStatus =
326
- JIRA_STATUS_NAME_MAP[statusName] ||
327
- JIRA_STATUS_CATEGORY_MAP[statusCategory] ||
328
- 'backlog'
325
+ JIRA_STATUS_NAME_MAP[statusName] || JIRA_STATUS_CATEGORY_MAP[statusCategory] || 'backlog'
329
326
 
330
327
  const priorityName = mcpIssue.fields.priority?.name?.toLowerCase() || 'medium'
331
328
  const priority: IssuePriority = JIRA_PRIORITY_MAP[priorityName] || 'medium'
@@ -400,8 +397,6 @@ export class JiraMCPAdapter implements Partial<IssueTrackerProvider> {
400
397
  return 'Improvement'
401
398
  case 'epic':
402
399
  return 'Epic'
403
- case 'chore':
404
- case 'task':
405
400
  default:
406
401
  return 'Task'
407
402
  }
@@ -4,21 +4,21 @@
4
4
  * All operations are cached with 5-minute TTL.
5
5
  */
6
6
 
7
- import { jiraProvider } from './client'
8
- import {
9
- issueCache,
10
- assignedIssuesCache,
11
- projectsCache,
12
- clearJiraCache,
13
- getJiraCacheStats,
14
- } from './cache'
15
7
  import type {
16
- Issue,
17
8
  CreateIssueInput,
18
- UpdateIssueInput,
19
9
  FetchOptions,
10
+ Issue,
20
11
  JiraConfig,
12
+ UpdateIssueInput,
21
13
  } from '../issue-tracker/types'
14
+ import {
15
+ assignedIssuesCache,
16
+ clearJiraCache,
17
+ getJiraCacheStats,
18
+ issueCache,
19
+ projectsCache,
20
+ } from './cache'
21
+ import { jiraProvider } from './client'
22
22
 
23
23
  export class JiraService {
24
24
  private initialized = false
@@ -6,15 +6,15 @@
6
6
  import { LinearClient as LinearSDK } from '@linear/sdk'
7
7
  import { getCredential } from '../../utils/keychain'
8
8
  import type {
9
- IssueTrackerProvider,
10
- Issue,
11
9
  CreateIssueInput,
12
- UpdateIssueInput,
13
10
  FetchOptions,
14
- LinearConfig,
15
- IssueStatus,
11
+ Issue,
16
12
  IssuePriority,
13
+ IssueStatus,
14
+ IssueTrackerProvider,
17
15
  IssueType,
16
+ LinearConfig,
17
+ UpdateIssueInput,
18
18
  } from '../issue-tracker/types'
19
19
 
20
20
  // =============================================================================
@@ -74,9 +74,7 @@ export class LinearProvider implements IssueTrackerProvider {
74
74
  // Try config first, then keychain (which falls back to env var)
75
75
  const apiKey = config.apiKey || (await getCredential('linear-api-key'))
76
76
  if (!apiKey) {
77
- throw new Error(
78
- 'LINEAR_API_KEY not configured. Run `p. linear setup` to configure.'
79
- )
77
+ throw new Error('LINEAR_API_KEY not configured. Run `p. linear setup` to configure.')
80
78
  }
81
79
 
82
80
  this.sdk = new LinearSDK({ apiKey })
@@ -118,9 +116,7 @@ export class LinearProvider implements IssueTrackerProvider {
118
116
  filter: Object.keys(filter).length > 0 ? filter : undefined,
119
117
  })
120
118
 
121
- return Promise.all(
122
- assignedIssues.nodes.map((issue) => this.mapIssue(issue))
123
- )
119
+ return Promise.all(assignedIssues.nodes.map((issue) => this.mapIssue(issue)))
124
120
  }
125
121
 
126
122
  /**
@@ -356,7 +352,10 @@ export class LinearProvider implements IssueTrackerProvider {
356
352
  description: linearIssue.description || undefined,
357
353
  status: LINEAR_STATUS_MAP[state?.type || 'backlog'] || 'backlog',
358
354
  priority: LINEAR_PRIORITY_MAP[linearIssue.priority] || 'none',
359
- type: this.inferType(linearIssue.title, labels.nodes.map((l) => l.name)),
355
+ type: this.inferType(
356
+ linearIssue.title,
357
+ labels.nodes.map((l) => l.name)
358
+ ),
360
359
  assignee: assignee
361
360
  ? {
362
361
  id: assignee.id,
@@ -395,13 +394,25 @@ export class LinearProvider implements IssueTrackerProvider {
395
394
  if (labelsLower.includes('bug') || titleLower.includes('fix') || titleLower.includes('bug')) {
396
395
  return 'bug'
397
396
  }
398
- if (labelsLower.includes('feature') || titleLower.includes('add') || titleLower.includes('implement')) {
397
+ if (
398
+ labelsLower.includes('feature') ||
399
+ titleLower.includes('add') ||
400
+ titleLower.includes('implement')
401
+ ) {
399
402
  return 'feature'
400
403
  }
401
- if (labelsLower.includes('improvement') || titleLower.includes('improve') || titleLower.includes('enhance')) {
404
+ if (
405
+ labelsLower.includes('improvement') ||
406
+ titleLower.includes('improve') ||
407
+ titleLower.includes('enhance')
408
+ ) {
402
409
  return 'improvement'
403
410
  }
404
- if (labelsLower.includes('chore') || titleLower.includes('chore') || titleLower.includes('deps')) {
411
+ if (
412
+ labelsLower.includes('chore') ||
413
+ titleLower.includes('chore') ||
414
+ titleLower.includes('deps')
415
+ ) {
405
416
  return 'chore'
406
417
  }
407
418
 
@@ -417,9 +428,7 @@ export class LinearProvider implements IssueTrackerProvider {
417
428
  const team = await this.sdk.team(teamId)
418
429
  const labels = await team.labels()
419
430
 
420
- return labels.nodes
421
- .filter((label) => labelNames.includes(label.name))
422
- .map((label) => label.id)
431
+ return labels.nodes.filter((label) => labelNames.includes(label.name)).map((label) => label.id)
423
432
  }
424
433
  }
425
434
 
@@ -3,21 +3,18 @@
3
3
  * Issue tracker provider for Linear using @linear/sdk
4
4
  */
5
5
 
6
- // Core provider
7
- export { LinearProvider, linearProvider } from './client'
8
-
9
- // Service layer with caching (preferred API)
10
- export { LinearService, linearService } from './service'
11
-
12
- // Sync layer for bidirectional sync with issues.json
13
- export { LinearSync, linearSync } from './sync'
14
-
15
6
  // Cache utilities
16
7
  export {
17
- issueCache,
18
8
  assignedIssuesCache,
19
- teamsCache,
20
- projectsCache,
21
9
  clearLinearCache,
22
10
  getLinearCacheStats,
11
+ issueCache,
12
+ projectsCache,
13
+ teamsCache,
23
14
  } from './cache'
15
+ // Core provider
16
+ export { LinearProvider, linearProvider } from './client'
17
+ // Service layer with caching (preferred API)
18
+ export { LinearService, linearService } from './service'
19
+ // Sync layer for bidirectional sync with issues.json
20
+ export { LinearSync, linearSync } from './sync'
@@ -4,22 +4,22 @@
4
4
  * All operations are cached with 5-minute TTL.
5
5
  */
6
6
 
7
- import { linearProvider } from './client'
8
- import {
9
- issueCache,
10
- assignedIssuesCache,
11
- teamsCache,
12
- projectsCache,
13
- clearLinearCache,
14
- getLinearCacheStats,
15
- } from './cache'
16
7
  import type {
17
- Issue,
18
8
  CreateIssueInput,
19
- UpdateIssueInput,
20
9
  FetchOptions,
10
+ Issue,
21
11
  LinearConfig,
12
+ UpdateIssueInput,
22
13
  } from '../issue-tracker/types'
14
+ import {
15
+ assignedIssuesCache,
16
+ clearLinearCache,
17
+ getLinearCacheStats,
18
+ issueCache,
19
+ projectsCache,
20
+ teamsCache,
21
+ } from './cache'
22
+ import { linearProvider } from './client'
23
23
 
24
24
  export class LinearService {
25
25
  private initialized = false
@@ -14,19 +14,19 @@
14
14
  * state.json.currentTask.linearId ← DIRECT LINK
15
15
  */
16
16
 
17
- import { readFile, writeFile, mkdir } from 'fs/promises'
18
- import { existsSync } from 'fs'
19
- import { join } from 'path'
20
- import { linearService } from './service'
21
- import { getProjectPath } from '../../schemas/schemas'
17
+ import { existsSync } from 'node:fs'
18
+ import { mkdir, readFile, writeFile } from 'node:fs/promises'
19
+ import { join } from 'node:path'
22
20
  import {
23
- type IssuesJson,
24
21
  type CachedIssue,
25
- type SyncResult,
26
22
  createEmptyIssues,
23
+ type IssuesJson,
27
24
  parseIssues,
25
+ type SyncResult,
28
26
  } from '../../schemas/issues'
27
+ import { getProjectPath } from '../../schemas/schemas'
29
28
  import type { Issue } from '../issue-tracker/types'
29
+ import { linearService } from './service'
30
30
 
31
31
  // Default staleness threshold: 30 minutes
32
32
  const DEFAULT_STALE_AFTER = 30 * 60 * 1000
@@ -105,7 +105,7 @@ export class LinearSync {
105
105
  const issuesJson = await this.loadIssues(projectId)
106
106
 
107
107
  // Check local cache first
108
- if (issuesJson && issuesJson.issues[identifier]) {
108
+ if (issuesJson?.issues[identifier]) {
109
109
  const cachedIssue = issuesJson.issues[identifier]
110
110
 
111
111
  // Check if cached issue is still fresh (within fetchedAt + some grace period)