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.
- package/CHANGELOG.md +75 -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
|
@@ -3,26 +3,26 @@
|
|
|
3
3
|
* Orchestrates multiple issue tracker providers and enrichment.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
|
|
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 {
|
|
25
|
-
|
|
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
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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<{
|
|
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(
|
|
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
|
-
'
|
|
393
|
-
|
|
394
|
-
|
|
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<{
|
|
446
|
-
|
|
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<{
|
|
473
|
-
|
|
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
|
-
|
|
666
|
-
|
|
667
|
-
|
|
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
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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
|
-
|
|
30
|
-
|
|
24
|
+
createCreateIssueInstruction,
|
|
25
|
+
createGetIssueInstruction,
|
|
31
26
|
// MCP instruction generators
|
|
32
27
|
createSearchInstruction,
|
|
33
|
-
createGetIssueInstruction,
|
|
34
28
|
createTransitionInstruction,
|
|
35
29
|
createUpdateInstruction,
|
|
36
|
-
|
|
30
|
+
getMCPSetupInstructions,
|
|
37
31
|
// Utilities
|
|
38
32
|
isMCPAvailable,
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 (
|
|
397
|
+
if (
|
|
398
|
+
labelsLower.includes('feature') ||
|
|
399
|
+
titleLower.includes('add') ||
|
|
400
|
+
titleLower.includes('implement')
|
|
401
|
+
) {
|
|
399
402
|
return 'feature'
|
|
400
403
|
}
|
|
401
|
-
if (
|
|
404
|
+
if (
|
|
405
|
+
labelsLower.includes('improvement') ||
|
|
406
|
+
titleLower.includes('improve') ||
|
|
407
|
+
titleLower.includes('enhance')
|
|
408
|
+
) {
|
|
402
409
|
return 'improvement'
|
|
403
410
|
}
|
|
404
|
-
if (
|
|
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 {
|
|
18
|
-
import {
|
|
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
|
|
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)
|