@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.
Files changed (48) hide show
  1. package/README.md +42 -19
  2. package/package.json +3 -2
  3. package/src/__tests__/activity.test.ts +12 -0
  4. package/src/__tests__/api.test.ts +4 -2
  5. package/src/__tests__/board-utils.test.ts +16 -3
  6. package/src/__tests__/column-roles.test.ts +34 -0
  7. package/src/__tests__/commands/board.test.ts +7 -0
  8. package/src/__tests__/conflict.test.ts +11 -1
  9. package/src/__tests__/db.test.ts +70 -0
  10. package/src/__tests__/index.test.ts +55 -0
  11. package/src/__tests__/jira-cache.test.ts +56 -0
  12. package/src/__tests__/jira-jql.test.ts +51 -0
  13. package/src/__tests__/jira-provider-read.test.ts +50 -0
  14. package/src/__tests__/mcp-server.test.ts +2 -2
  15. package/src/__tests__/metrics.test.ts +37 -1
  16. package/src/__tests__/postgres-local-provider.test.ts +90 -1
  17. package/src/__tests__/server.test.ts +126 -0
  18. package/src/__tests__/use-cases.test.ts +77 -0
  19. package/src/__tests__/webhooks.test.ts +91 -22
  20. package/src/api.ts +58 -36
  21. package/src/column-roles.ts +52 -0
  22. package/src/commands/board.ts +4 -4
  23. package/src/db.ts +145 -114
  24. package/src/errors.ts +1 -0
  25. package/src/index.ts +84 -33
  26. package/src/mcp/core.ts +8 -7
  27. package/src/metrics.ts +48 -23
  28. package/src/provider-runtime.ts +9 -2
  29. package/src/providers/index.ts +4 -1
  30. package/src/providers/jira-cache.ts +23 -6
  31. package/src/providers/jira-core.ts +926 -0
  32. package/src/providers/jira-jql.ts +48 -0
  33. package/src/providers/jira.ts +111 -759
  34. package/src/providers/linear-cache.ts +5 -3
  35. package/src/providers/linear-core.ts +693 -0
  36. package/src/providers/linear.ts +70 -554
  37. package/src/providers/postgres-jira-cache.ts +597 -0
  38. package/src/providers/postgres-jira.ts +15 -1312
  39. package/src/providers/postgres-linear-cache.ts +500 -0
  40. package/src/providers/postgres-linear.ts +22 -1088
  41. package/src/providers/postgres-local.ts +181 -74
  42. package/src/providers/types.ts +71 -2
  43. package/src/server.ts +118 -32
  44. package/src/use-cases.ts +139 -0
  45. package/src/webhooks.ts +19 -0
  46. package/ui/dist/assets/index-65LcV0R7.js +40 -0
  47. package/ui/dist/index.html +1 -1
  48. package/ui/dist/assets/index-CFhtfqCn.js +0 -40
@@ -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,