@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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ErrorCode, KanbanError } from '../errors'
|
|
2
|
+
|
|
3
|
+
// Jira project keys are alphanumeric with underscores (the API-canonical key,
|
|
4
|
+
// e.g. `ENG`). Anything else would be malformed and, interpolated into JQL,
|
|
5
|
+
// could break out of the query.
|
|
6
|
+
const PROJECT_KEY_RE = /^[A-Za-z0-9_]+$/
|
|
7
|
+
|
|
8
|
+
// JQL datetime literals contain only digits and date/time separators. This
|
|
9
|
+
// covers both the space form (`1970-01-01 00:00`) and the ISO forms Jira
|
|
10
|
+
// returns in `issue.fields.updated` (`2026-01-05T00:00:00Z`, `...+0000`). A
|
|
11
|
+
// double quote, backslash, or any JQL operator/keyword cannot match, so a
|
|
12
|
+
// tampered `updated` value (e.g. delivered via webhook) cannot escape the
|
|
13
|
+
// quoted literal.
|
|
14
|
+
const JQL_TIMESTAMP_RE = /^[0-9 :.\-TZ+]+$/
|
|
15
|
+
|
|
16
|
+
const DEFAULT_SINCE = '1970-01-01 00:00'
|
|
17
|
+
|
|
18
|
+
export function assertSafeProjectKey(key: string): string {
|
|
19
|
+
if (!PROJECT_KEY_RE.test(key)) {
|
|
20
|
+
throw new KanbanError(
|
|
21
|
+
ErrorCode.PROVIDER_NOT_CONFIGURED,
|
|
22
|
+
`Invalid Jira project key ${JSON.stringify(key)}: expected alphanumeric characters only`,
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
return key
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Return the cursor only if it's a safe JQL datetime literal, else null. Callers
|
|
30
|
+
* use this both to build the JQL and to seed `newestUpdatedAt`, so a rejected
|
|
31
|
+
* cursor is never carried forward and re-persisted (which would otherwise trap
|
|
32
|
+
* every future sync into a full scan).
|
|
33
|
+
*/
|
|
34
|
+
export function safeDeltaSince(since: string | null): string | null {
|
|
35
|
+
if (since === null) return null
|
|
36
|
+
return JQL_TIMESTAMP_RE.test(since) ? since : null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Build the delta-sync JQL with both interpolated values validated. An invalid
|
|
41
|
+
* `since` (only possible if a persisted/upstream timestamp was tampered with)
|
|
42
|
+
* falls back to a full scan rather than risking injection.
|
|
43
|
+
*/
|
|
44
|
+
export function buildDeltaJql(projectKey: string, since: string | null): string {
|
|
45
|
+
assertSafeProjectKey(projectKey)
|
|
46
|
+
const sinceClause = safeDeltaSince(since) ?? DEFAULT_SINCE
|
|
47
|
+
return `project = ${projectKey} AND updated >= "${sinceClause}" ORDER BY updated ASC`
|
|
48
|
+
}
|