@andypai/agent-kanban 0.6.0 → 0.6.2
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/README.md +42 -19
- package/package.json +3 -2
- package/src/__tests__/activity.test.ts +12 -0
- package/src/__tests__/api.test.ts +4 -2
- package/src/__tests__/board-utils.test.ts +16 -3
- package/src/__tests__/column-roles.test.ts +34 -0
- package/src/__tests__/commands/board.test.ts +7 -0
- package/src/__tests__/conflict.test.ts +11 -1
- package/src/__tests__/db.test.ts +70 -0
- package/src/__tests__/index.test.ts +55 -0
- package/src/__tests__/jira-cache.test.ts +56 -0
- package/src/__tests__/jira-jql.test.ts +51 -0
- package/src/__tests__/jira-provider-read.test.ts +50 -0
- package/src/__tests__/mcp-server.test.ts +2 -2
- package/src/__tests__/metrics.test.ts +37 -1
- package/src/__tests__/postgres-local-provider.test.ts +90 -1
- package/src/__tests__/server.test.ts +126 -0
- package/src/__tests__/use-cases.test.ts +77 -0
- package/src/__tests__/webhooks.test.ts +91 -22
- package/src/api.ts +58 -36
- package/src/column-roles.ts +52 -0
- package/src/commands/board.ts +4 -4
- package/src/db.ts +145 -114
- package/src/errors.ts +1 -0
- package/src/index.ts +84 -33
- package/src/mcp/core.ts +8 -7
- package/src/metrics.ts +48 -23
- package/src/provider-runtime.ts +9 -2
- package/src/providers/index.ts +4 -1
- package/src/providers/jira-cache.ts +23 -6
- package/src/providers/jira-core.ts +926 -0
- package/src/providers/jira-jql.ts +48 -0
- package/src/providers/jira.ts +111 -759
- package/src/providers/linear-cache.ts +5 -3
- package/src/providers/linear-core.ts +693 -0
- package/src/providers/linear.ts +70 -554
- package/src/providers/postgres-jira-cache.ts +597 -0
- package/src/providers/postgres-jira.ts +15 -1312
- package/src/providers/postgres-linear-cache.ts +500 -0
- package/src/providers/postgres-linear.ts +22 -1088
- package/src/providers/postgres-local.ts +181 -74
- package/src/providers/types.ts +71 -2
- package/src/server.ts +118 -32
- package/src/use-cases.ts +139 -0
- package/src/webhooks.ts +19 -0
- package/ui/dist/assets/index-65LcV0R7.js +40 -0
- package/ui/dist/index.html +1 -1
- package/ui/dist/assets/index-CFhtfqCn.js +0 -40
package/src/use-cases.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { normalizeLabels } from './labels'
|
|
2
|
+
import type {
|
|
3
|
+
CreateTaskInput,
|
|
4
|
+
KanbanProvider,
|
|
5
|
+
ProviderContext,
|
|
6
|
+
TaskListFilters,
|
|
7
|
+
UpdateTaskInput,
|
|
8
|
+
} from './providers/types'
|
|
9
|
+
import type {
|
|
10
|
+
ActivityEntry,
|
|
11
|
+
BoardBootstrap,
|
|
12
|
+
BoardConfig,
|
|
13
|
+
BoardMetrics,
|
|
14
|
+
BoardView,
|
|
15
|
+
Column,
|
|
16
|
+
Task,
|
|
17
|
+
TaskComment,
|
|
18
|
+
} from './types'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Typed use-case layer shared by every transport (CLI, HTTP, MCP).
|
|
22
|
+
*
|
|
23
|
+
* Each function is the single, typed seam between a transport and the
|
|
24
|
+
* provider: transports own their own concerns — argument parsing and
|
|
25
|
+
* transport-specific error messages, HTTP routing and WebSocket events, MCP
|
|
26
|
+
* authorization policy and hooks — then delegate the actual provider call
|
|
27
|
+
* here. Keeping that call in one place means cross-cutting concerns (label
|
|
28
|
+
* normalization today; future auditing/validation) have a single insertion
|
|
29
|
+
* point instead of being re-derived in three transports.
|
|
30
|
+
*
|
|
31
|
+
* These functions intentionally do NOT perform required-argument validation:
|
|
32
|
+
* the transports raise their own (differently worded) errors before calling
|
|
33
|
+
* in, so the contract each surface already advertises is preserved.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create-task input as a transport supplies it. Identical to CreateTaskInput
|
|
38
|
+
* except `labels` is accepted in any raw form (CLI flag arrays, a JSON array,
|
|
39
|
+
* a comma-separated string) and normalized here so no transport re-implements
|
|
40
|
+
* the normalization.
|
|
41
|
+
*/
|
|
42
|
+
export type CreateTaskCommand = Omit<CreateTaskInput, 'labels'> & { labels?: unknown }
|
|
43
|
+
|
|
44
|
+
export function createTask(provider: KanbanProvider, input: CreateTaskCommand): Promise<Task> {
|
|
45
|
+
const { labels, ...rest } = input
|
|
46
|
+
return provider.createTask({ ...rest, labels: normalizeLabels(labels) })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function listTasks(provider: KanbanProvider, filters?: TaskListFilters): Promise<Task[]> {
|
|
50
|
+
return provider.listTasks(filters)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getTask(provider: KanbanProvider, idOrRef: string): Promise<Task> {
|
|
54
|
+
return provider.getTask(idOrRef)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function updateTask(
|
|
58
|
+
provider: KanbanProvider,
|
|
59
|
+
idOrRef: string,
|
|
60
|
+
input: UpdateTaskInput,
|
|
61
|
+
): Promise<Task> {
|
|
62
|
+
return provider.updateTask(idOrRef, input)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function moveTask(provider: KanbanProvider, idOrRef: string, column: string): Promise<Task> {
|
|
66
|
+
return provider.moveTask(idOrRef, column)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function deleteTask(provider: KanbanProvider, idOrRef: string): Promise<Task> {
|
|
70
|
+
return provider.deleteTask(idOrRef)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function listComments(provider: KanbanProvider, idOrRef: string): Promise<TaskComment[]> {
|
|
74
|
+
return provider.listComments(idOrRef)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getComment(
|
|
78
|
+
provider: KanbanProvider,
|
|
79
|
+
idOrRef: string,
|
|
80
|
+
commentId: string,
|
|
81
|
+
): Promise<TaskComment> {
|
|
82
|
+
return provider.getComment(idOrRef, commentId)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function addComment(
|
|
86
|
+
provider: KanbanProvider,
|
|
87
|
+
idOrRef: string,
|
|
88
|
+
body: string,
|
|
89
|
+
): Promise<TaskComment> {
|
|
90
|
+
return provider.comment(idOrRef, body)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function updateComment(
|
|
94
|
+
provider: KanbanProvider,
|
|
95
|
+
idOrRef: string,
|
|
96
|
+
commentId: string,
|
|
97
|
+
body: string,
|
|
98
|
+
): Promise<TaskComment> {
|
|
99
|
+
return provider.updateComment(idOrRef, commentId, body)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function getBoard(provider: KanbanProvider): Promise<BoardView> {
|
|
103
|
+
return provider.getBoard()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function getBootstrap(provider: KanbanProvider): Promise<BoardBootstrap> {
|
|
107
|
+
return provider.getBootstrap()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getContext(provider: KanbanProvider): Promise<ProviderContext> {
|
|
111
|
+
return provider.getContext()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function listColumns(provider: KanbanProvider): Promise<Column[]> {
|
|
115
|
+
return provider.listColumns()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getActivity(
|
|
119
|
+
provider: KanbanProvider,
|
|
120
|
+
limit?: number,
|
|
121
|
+
taskId?: string,
|
|
122
|
+
): Promise<ActivityEntry[]> {
|
|
123
|
+
return provider.getActivity(limit, taskId)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function getMetrics(provider: KanbanProvider): Promise<BoardMetrics> {
|
|
127
|
+
return provider.getMetrics()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function getConfig(provider: KanbanProvider): Promise<BoardConfig> {
|
|
131
|
+
return provider.getConfig()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function patchConfig(
|
|
135
|
+
provider: KanbanProvider,
|
|
136
|
+
input: Partial<BoardConfig>,
|
|
137
|
+
): Promise<BoardConfig> {
|
|
138
|
+
return provider.patchConfig(input)
|
|
139
|
+
}
|
package/src/webhooks.ts
CHANGED
|
@@ -12,6 +12,25 @@ export interface WebhookResult {
|
|
|
12
12
|
message?: string
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Webhook authorization. When secret is configured, verifies the HMAC signature
|
|
17
|
+
* and rejects on mismatch. When secret is unset, accepts all payloads (open dev
|
|
18
|
+
* mode — suitable when the provider webhook is not configured with a signing secret).
|
|
19
|
+
*/
|
|
20
|
+
export function authorizeWebhook(opts: {
|
|
21
|
+
secret: string | undefined
|
|
22
|
+
rawBody: string
|
|
23
|
+
signature: string | undefined | null
|
|
24
|
+
verify: (secret: string, rawBody: string, signature: string | undefined | null) => boolean
|
|
25
|
+
}): WebhookResult | null {
|
|
26
|
+
const { secret, rawBody, signature, verify } = opts
|
|
27
|
+
if (!secret) return null
|
|
28
|
+
if (!verify(secret, rawBody, signature)) {
|
|
29
|
+
return { handled: false, unauthorized: true, message: 'Invalid signature' }
|
|
30
|
+
}
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
15
34
|
export function verifyHmacSha256(
|
|
16
35
|
secret: string,
|
|
17
36
|
rawBody: string,
|