@zibby/skills 0.1.34 → 0.1.35
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 +2 -0
- package/dist/browser.d.ts +19 -0
- package/dist/chat-memory.d.ts +355 -0
- package/dist/chat-notify.d.ts +409 -0
- package/dist/core-tools.d.ts +131 -0
- package/dist/function-skill.d.ts +149 -0
- package/dist/git.d.ts +72 -0
- package/dist/github.d.ts +777 -0
- package/dist/gitlab.d.ts +396 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +43 -43
- package/dist/integrations.d.ts +110 -0
- package/dist/jira.d.ts +547 -0
- package/dist/lark.d.ts +161 -0
- package/dist/linear.d.ts +344 -0
- package/dist/llm-billing.d.ts +294 -0
- package/dist/memory.d.ts +137 -0
- package/dist/package.json +67 -19
- package/dist/plane.d.ts +24 -0
- package/dist/report.d.ts +354 -0
- package/dist/report.js +9 -9
- package/dist/sentry.d.ts +43 -0
- package/dist/skill-installer.d.ts +86 -0
- package/dist/slack.d.ts +284 -0
- package/dist/test-runner.d.ts +220 -0
- package/dist/trackers/github-adapter.d.ts +96 -0
- package/dist/trackers/index.d.ts +27 -0
- package/dist/trackers/jira-adapter.d.ts +90 -0
- package/dist/trackers/linear-adapter.d.ts +89 -0
- package/dist/trackers/plane-adapter.d.ts +101 -0
- package/dist/trackers/types.d.ts +335 -0
- package/dist/workflow-builder.d.ts +245 -0
- package/package.json +67 -19
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export namespace jiraAdapter {
|
|
2
|
+
export let id: string;
|
|
3
|
+
export { toStateCategory };
|
|
4
|
+
export { toNeutral };
|
|
5
|
+
/**
|
|
6
|
+
* listCandidates — JQL search. `opts.query` is the JQL; if omitted we build a
|
|
7
|
+
* bounded default. Returns newest-updated first.
|
|
8
|
+
* @param {import('./types.js').ListCandidatesOptions} [opts]
|
|
9
|
+
* @returns {Promise<import('./types.js').NeutralTicket[]>}
|
|
10
|
+
*/
|
|
11
|
+
export function listCandidates(opts?: import("./types.js").ListCandidatesOptions): Promise<import("./types.js").NeutralTicket[]>;
|
|
12
|
+
/**
|
|
13
|
+
* getTicket — one issue by key. Uses jiraFetch (not jira_get_issue) so the
|
|
14
|
+
* full status object incl. statusCategory is present for bucketing.
|
|
15
|
+
*/
|
|
16
|
+
export function getTicket(key: any): Promise<{
|
|
17
|
+
id: string;
|
|
18
|
+
key: any;
|
|
19
|
+
title: any;
|
|
20
|
+
body: any;
|
|
21
|
+
state: any;
|
|
22
|
+
stateCategory: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
23
|
+
assignee: any;
|
|
24
|
+
url: string;
|
|
25
|
+
_raw: any;
|
|
26
|
+
}>;
|
|
27
|
+
/** getComments — newest first (jira_get_comments already flattens ADF). */
|
|
28
|
+
export function getComments(key: any): Promise<any>;
|
|
29
|
+
/** addComment — delegates to jira_add_comment (wraps text in ADF). */
|
|
30
|
+
export function addComment(key: any, body: any): Promise<{
|
|
31
|
+
ok: boolean;
|
|
32
|
+
id: any;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* transition — reuse jira_transition_issue's fuzzy matching (exact → core →
|
|
36
|
+
* dice). Returns ok + the resulting raw state name and its bucket.
|
|
37
|
+
*/
|
|
38
|
+
export function transition(key: any, targetStateName: any): Promise<{
|
|
39
|
+
ok: boolean;
|
|
40
|
+
error: any;
|
|
41
|
+
_raw: any;
|
|
42
|
+
stateAfter?: undefined;
|
|
43
|
+
stateCategoryAfter?: undefined;
|
|
44
|
+
} | {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
stateAfter: any;
|
|
47
|
+
stateCategoryAfter: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
48
|
+
_raw: any;
|
|
49
|
+
error?: undefined;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* linkPullRequest — try Jira's remote-link API; fall back to a comment.
|
|
53
|
+
* Remote-link needs the granular `write:issue.remote-link:jira` scope; if it
|
|
54
|
+
* 403s (or anything else), we still record the PR via a comment so the link
|
|
55
|
+
* is never silently lost.
|
|
56
|
+
*/
|
|
57
|
+
export function linkPullRequest(key: any, prUrl: any, title: any): Promise<{
|
|
58
|
+
ok: boolean;
|
|
59
|
+
via: string;
|
|
60
|
+
error?: undefined;
|
|
61
|
+
} | {
|
|
62
|
+
ok: boolean;
|
|
63
|
+
via: string;
|
|
64
|
+
error: string;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
export default jiraAdapter;
|
|
68
|
+
/**
|
|
69
|
+
* Map a Jira status into the neutral 5-bucket category.
|
|
70
|
+
* @param {{name?: string, statusCategory?: {key?: string}}} [status]
|
|
71
|
+
* @returns {'todo'|'in_progress'|'done'|'blocked'|'unknown'}
|
|
72
|
+
*/
|
|
73
|
+
declare function toStateCategory(status?: {
|
|
74
|
+
name?: string;
|
|
75
|
+
statusCategory?: {
|
|
76
|
+
key?: string;
|
|
77
|
+
};
|
|
78
|
+
}): "todo" | "in_progress" | "done" | "blocked" | "unknown";
|
|
79
|
+
/** Build a NeutralTicket from a full Jira issue REST payload. */
|
|
80
|
+
declare function toNeutral(issue: any, instanceUrl: any): {
|
|
81
|
+
id: string;
|
|
82
|
+
key: any;
|
|
83
|
+
title: any;
|
|
84
|
+
body: any;
|
|
85
|
+
state: any;
|
|
86
|
+
stateCategory: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
87
|
+
assignee: any;
|
|
88
|
+
url: string;
|
|
89
|
+
_raw: any;
|
|
90
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export namespace linearAdapter {
|
|
2
|
+
export let id: string;
|
|
3
|
+
export { toStateCategory };
|
|
4
|
+
export { toNeutral };
|
|
5
|
+
/**
|
|
6
|
+
* listCandidates — poll issues filtered by team/state/label/assignee/cursor.
|
|
7
|
+
* Linear ignores free-text `query`; pass structured filters via opts/ctx.
|
|
8
|
+
* @param {import('./types.js').ListCandidatesOptions & {ctx?: object}} [opts]
|
|
9
|
+
* @returns {Promise<import('./types.js').NeutralTicket[]>}
|
|
10
|
+
*/
|
|
11
|
+
export function listCandidates(opts?: import("./types.js").ListCandidatesOptions & {
|
|
12
|
+
ctx?: object;
|
|
13
|
+
}): Promise<import("./types.js").NeutralTicket[]>;
|
|
14
|
+
/** getTicket — one issue by identifier (ENG-123) or uuid. */
|
|
15
|
+
export function getTicket(key: any): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
key: any;
|
|
18
|
+
title: any;
|
|
19
|
+
body: any;
|
|
20
|
+
state: any;
|
|
21
|
+
stateCategory: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
22
|
+
assignee: any;
|
|
23
|
+
url: any;
|
|
24
|
+
_raw: any;
|
|
25
|
+
}>;
|
|
26
|
+
/** getComments — newest first. */
|
|
27
|
+
export function getComments(key: any): Promise<any>;
|
|
28
|
+
/** addComment — markdown body. */
|
|
29
|
+
export function addComment(key: any, body: any): Promise<{
|
|
30
|
+
ok: boolean;
|
|
31
|
+
id: any;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* transition — set the issue's workflow state by target NAME. The skill
|
|
35
|
+
* resolves the name to the team's matching state id (exact → type-alias →
|
|
36
|
+
* fuzzy). No transition object in Linear.
|
|
37
|
+
*/
|
|
38
|
+
export function transition(key: any, targetStateName: any): Promise<{
|
|
39
|
+
ok: boolean;
|
|
40
|
+
error: any;
|
|
41
|
+
_raw: any;
|
|
42
|
+
stateAfter?: undefined;
|
|
43
|
+
stateCategoryAfter?: undefined;
|
|
44
|
+
} | {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
stateAfter: any;
|
|
47
|
+
stateCategoryAfter: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
48
|
+
_raw: any;
|
|
49
|
+
error?: undefined;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* linkPullRequest — native Linear attachment; fall back to a comment.
|
|
53
|
+
*/
|
|
54
|
+
export function linkPullRequest(key: any, prUrl: any, title: any): Promise<{
|
|
55
|
+
ok: boolean;
|
|
56
|
+
via: string;
|
|
57
|
+
error?: undefined;
|
|
58
|
+
} | {
|
|
59
|
+
ok: boolean;
|
|
60
|
+
via: string;
|
|
61
|
+
error: string;
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
64
|
+
export default linearAdapter;
|
|
65
|
+
/**
|
|
66
|
+
* Map a Linear state into the neutral 5-bucket category.
|
|
67
|
+
* @param {{name?: string, type?: string}} [state]
|
|
68
|
+
* @returns {'todo'|'in_progress'|'done'|'blocked'|'unknown'}
|
|
69
|
+
*/
|
|
70
|
+
declare function toStateCategory(state?: {
|
|
71
|
+
name?: string;
|
|
72
|
+
type?: string;
|
|
73
|
+
}): "todo" | "in_progress" | "done" | "blocked" | "unknown";
|
|
74
|
+
/**
|
|
75
|
+
* Build a NeutralTicket from the linear.js tool projection. The list and get
|
|
76
|
+
* tools both expose `state` (name) + `stateType` (the WorkflowState type); we
|
|
77
|
+
* bucket off the type, keep the raw name as `state`.
|
|
78
|
+
*/
|
|
79
|
+
declare function toNeutral(issue: any): {
|
|
80
|
+
id: string;
|
|
81
|
+
key: any;
|
|
82
|
+
title: any;
|
|
83
|
+
body: any;
|
|
84
|
+
state: any;
|
|
85
|
+
stateCategory: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
86
|
+
assignee: any;
|
|
87
|
+
url: any;
|
|
88
|
+
_raw: any;
|
|
89
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level Plane REST helper — the SINGLE auth chokepoint (cf. linearFetch).
|
|
3
|
+
* Keep token + base-url resolution here; never re-implement at call sites.
|
|
4
|
+
* Exported so a pipeline can issue raw calls the 6 methods don't cover.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} path path AFTER /api/v1, e.g.
|
|
7
|
+
* `/workspaces/acme/projects/<uuid>/work-items/`
|
|
8
|
+
* @param {{method?:string, body?:any, query?:object, headers?:object}} [opts]
|
|
9
|
+
* @returns {Promise<any>} parsed JSON (or {} for empty body)
|
|
10
|
+
*/
|
|
11
|
+
export function planeFetch(path: string, opts?: {
|
|
12
|
+
method?: string;
|
|
13
|
+
body?: any;
|
|
14
|
+
query?: object;
|
|
15
|
+
headers?: object;
|
|
16
|
+
}): Promise<any>;
|
|
17
|
+
/**
|
|
18
|
+
* Normalize a Plane state into the neutral 5-bucket category.
|
|
19
|
+
* @param {{name?:string, group?:string}} [state]
|
|
20
|
+
* @returns {'todo'|'in_progress'|'done'|'blocked'|'unknown'}
|
|
21
|
+
*/
|
|
22
|
+
export function toStateCategory(state?: {
|
|
23
|
+
name?: string;
|
|
24
|
+
group?: string;
|
|
25
|
+
}): "todo" | "in_progress" | "done" | "blocked" | "unknown";
|
|
26
|
+
export namespace planeAdapter {
|
|
27
|
+
export let id: string;
|
|
28
|
+
export let envKeys: string[];
|
|
29
|
+
export { planeFetch };
|
|
30
|
+
export { toStateCategory };
|
|
31
|
+
/**
|
|
32
|
+
* listCandidates — poll work items for a (workspace, project).
|
|
33
|
+
* @param {import('./types.js').ListCandidatesOptions & {ctx?: object}} [opts]
|
|
34
|
+
* @returns {Promise<import('./types.js').NeutralTicket[]>}
|
|
35
|
+
*/
|
|
36
|
+
export function listCandidates(opts?: import("./types.js").ListCandidatesOptions & {
|
|
37
|
+
ctx?: object;
|
|
38
|
+
}): Promise<import("./types.js").NeutralTicket[]>;
|
|
39
|
+
/**
|
|
40
|
+
* getTicket — one work item by uuid (Plane addresses work items by uuid, NOT
|
|
41
|
+
* by the PROJ-42 human key).
|
|
42
|
+
* TODO: if `key` looks like "PROJ-42", resolve sequence_id → uuid via a
|
|
43
|
+
* filtered list call. For now assume a uuid.
|
|
44
|
+
*/
|
|
45
|
+
export function getTicket(key: any, ctx?: {}): Promise<{
|
|
46
|
+
id: any;
|
|
47
|
+
key: any;
|
|
48
|
+
title: any;
|
|
49
|
+
body: any;
|
|
50
|
+
state: any;
|
|
51
|
+
stateCategory: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
52
|
+
assignee: string;
|
|
53
|
+
url: string;
|
|
54
|
+
_raw: any;
|
|
55
|
+
}>;
|
|
56
|
+
/** getComments — newest first. */
|
|
57
|
+
export function getComments(key: any, ctx?: {}): Promise<any>;
|
|
58
|
+
/**
|
|
59
|
+
* addComment — Plane comments are HTML, not markdown. We wrap plaintext in a
|
|
60
|
+
* <p> so a markdown-y body at least renders as text.
|
|
61
|
+
* TODO: confirm the API accepts comment_html on POST (vs comment_stripped),
|
|
62
|
+
* and whether it sanitizes/strips.
|
|
63
|
+
*/
|
|
64
|
+
export function addComment(key: any, body: any, ctx?: {}): Promise<{
|
|
65
|
+
ok: boolean;
|
|
66
|
+
id: any;
|
|
67
|
+
_raw: any;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* transition — Plane has NO transition object (like Linear). Resolve the
|
|
71
|
+
* target state NAME (or a neutral category word) to the project's matching
|
|
72
|
+
* state uuid, then PATCH work-item { state: <uuid> }.
|
|
73
|
+
*/
|
|
74
|
+
export function transition(key: any, targetStateName: any, ctx?: {}): Promise<{
|
|
75
|
+
ok: boolean;
|
|
76
|
+
error: string;
|
|
77
|
+
availableStates: any;
|
|
78
|
+
stateAfter?: undefined;
|
|
79
|
+
stateCategoryAfter?: undefined;
|
|
80
|
+
_raw?: undefined;
|
|
81
|
+
} | {
|
|
82
|
+
ok: boolean;
|
|
83
|
+
stateAfter: any;
|
|
84
|
+
stateCategoryAfter: "unknown" | "todo" | "in_progress" | "done" | "blocked";
|
|
85
|
+
_raw: any;
|
|
86
|
+
error?: undefined;
|
|
87
|
+
availableStates?: undefined;
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* linkPullRequest — Plane has no first-class "attachment URL on issue" like
|
|
91
|
+
* Linear's attachmentCreate. The portable path is a comment with the link.
|
|
92
|
+
* (Plane does have a GitHub *integration* for repo-level linking, but that's
|
|
93
|
+
* an installed integration, not a per-issue API write.)
|
|
94
|
+
* TODO: if a target Plane exposes a link/attachment endpoint, prefer it.
|
|
95
|
+
*/
|
|
96
|
+
export function linkPullRequest(key: any, prUrl: any, title: any, ctx?: {}): Promise<{
|
|
97
|
+
ok: boolean;
|
|
98
|
+
via: string;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
export default planeAdapter;
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Neutral tracker types — the shared contract every tracker adapter implements.
|
|
3
|
+
* ============================================================================
|
|
4
|
+
*
|
|
5
|
+
* This is the "neutrality payoff": a pipeline reads/writes ANY issue tracker
|
|
6
|
+
* (Jira, Linear, GitHub Issues, Plane) through ONE interface, so a workflow
|
|
7
|
+
* template never hard-codes a provider's REST shape.
|
|
8
|
+
*
|
|
9
|
+
* Design rule (from the build plan, "中立抽象最小版"):
|
|
10
|
+
* A field/method belongs in this contract IFF Jira AND GitHub AND Linear all
|
|
11
|
+
* have it AND the semantics line up. Provider-only data (Jira sprint /
|
|
12
|
+
* story-point, Linear cycle, GitHub milestone, Plane sequence_id) lives in
|
|
13
|
+
* `_raw` — never promoted to a top-level neutral field. Resisting that
|
|
14
|
+
* promotion is what keeps this from becoming "a Jira layer with a hat on".
|
|
15
|
+
*
|
|
16
|
+
* Field names are deliberately aligned to the OpenAI Symphony §4 domain model
|
|
17
|
+
* (id / key / title / body / state / assignee / url) so a future Symphony
|
|
18
|
+
* compatibility layer is additive, not a rewrite.
|
|
19
|
+
*
|
|
20
|
+
* STATE MODEL — the one piece of real cleverness:
|
|
21
|
+
* `state` is the RAW provider status name ("In Progress", "测试", "Done",
|
|
22
|
+
* "started"). It is what you WRITE BACK with — provider workflows reject made-
|
|
23
|
+
* up names, so the pipeline must echo the tracker's own vocabulary.
|
|
24
|
+
* `stateCategory` is the NORMALIZED bucket the pipeline BRANCHES on. Five
|
|
25
|
+
* buckets, no more:
|
|
26
|
+
* - 'todo' not started yet (Jira `new`, Linear backlog/unstarted,
|
|
27
|
+
* GitHub open w/o a progress label, Plane backlog/unstarted)
|
|
28
|
+
* - 'in_progress' actively being worked (Jira `indeterminate`,
|
|
29
|
+
* Linear started, Plane started, GitHub open w/ an
|
|
30
|
+
* in-progress label)
|
|
31
|
+
* - 'done' terminal/closed (Jira `done`, Linear completed/canceled,
|
|
32
|
+
* Plane completed/cancelled, GitHub closed)
|
|
33
|
+
* - 'blocked' explicitly blocked — NOT a native group in any provider;
|
|
34
|
+
* only ever derived from a status NAME match
|
|
35
|
+
* (blocked / on hold / waiting / stuck). Adapters surface
|
|
36
|
+
* it best-effort; absence of 'blocked' is not a bug.
|
|
37
|
+
* - 'unknown' could not classify (missing/unrecognized state)
|
|
38
|
+
* Keeping the pair separate is the whole trick: pipeline logic on the bucket,
|
|
39
|
+
* write-back on the raw name. Don't collapse them.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {'todo'|'in_progress'|'done'|'blocked'|'unknown'} StateCategory
|
|
43
|
+
* Normalized 5-bucket state. The pipeline branches on this; never on `state`.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* A tracker ticket/issue projected onto the neutral model.
|
|
47
|
+
*
|
|
48
|
+
* @typedef {Object} NeutralTicket
|
|
49
|
+
* @property {string} id
|
|
50
|
+
* Stable provider-internal id. Jira: issue id (numeric string). Linear: uuid.
|
|
51
|
+
* GitHub: issue number as a string. Plane: work-item uuid. Opaque — pass it
|
|
52
|
+
* back to the same adapter; do not parse it.
|
|
53
|
+
* @property {string} key
|
|
54
|
+
* Human-facing reference. Jira: `PROJ-123`. Linear: `ENG-12`. GitHub:
|
|
55
|
+
* `owner/repo#123`. Plane: `PROJ-42` (or the uuid if the identifier is
|
|
56
|
+
* unknown). This is what shows up in PR titles / comments.
|
|
57
|
+
* @property {string} title
|
|
58
|
+
* Short summary line (Symphony §4 `title`).
|
|
59
|
+
* @property {string} body
|
|
60
|
+
* Full description as plain text / markdown (Symphony §4 `body`). ADF/HTML is
|
|
61
|
+
* flattened by the adapter; never raw ADF or raw HTML here.
|
|
62
|
+
* @property {string|null} state
|
|
63
|
+
* RAW provider status NAME, exactly as the tracker spells it ("In Progress",
|
|
64
|
+
* "Done", "started", "测试"). Use this for write-back (transition). `null`
|
|
65
|
+
* when the provider/issue has no resolvable status.
|
|
66
|
+
* @property {StateCategory} stateCategory
|
|
67
|
+
* Normalized bucket — what the pipeline branches on.
|
|
68
|
+
* @property {string|null} assignee
|
|
69
|
+
* Single human-readable assignee (display name or login). `null` if
|
|
70
|
+
* unassigned. Multi-assignee providers (GitHub, Plane) collapse to the first;
|
|
71
|
+
* the full list, if any, lives in `_raw`.
|
|
72
|
+
* @property {string|null} url
|
|
73
|
+
* Canonical web URL of the ticket, or `null` if the adapter can't derive one.
|
|
74
|
+
* @property {Object} _raw
|
|
75
|
+
* Escape hatch — the untouched provider payload. Read provider-specific data
|
|
76
|
+
* (sprint, story points, cycle, milestone, sequence_id, labels…) from here.
|
|
77
|
+
* NEVER promote a `_raw` field to a top-level neutral field.
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* A single comment on a ticket, projected onto the neutral model.
|
|
81
|
+
*
|
|
82
|
+
* @typedef {Object} NeutralComment
|
|
83
|
+
* @property {string} id Provider comment id (opaque).
|
|
84
|
+
* @property {string} author Human-readable author (display name/login).
|
|
85
|
+
* @property {string} body Comment text as plain text / markdown
|
|
86
|
+
* (ADF/HTML flattened).
|
|
87
|
+
* @property {string|null} createdAt ISO-8601 creation timestamp, if available.
|
|
88
|
+
* @property {string|null} updatedAt ISO-8601 update timestamp, if available.
|
|
89
|
+
* @property {Object} [_raw] Untouched provider comment payload.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* Options accepted by {@link TrackerAdapter.listCandidates}. Every field is
|
|
93
|
+
* optional; what each provider honors differs (documented per adapter). The
|
|
94
|
+
* shared minimum is "give me a bounded, newest-first slab of work to consider".
|
|
95
|
+
*
|
|
96
|
+
* @typedef {Object} ListCandidatesOptions
|
|
97
|
+
* @property {string} [query]
|
|
98
|
+
* Provider-native query. Jira: a JQL string. GitHub: free-text issue search
|
|
99
|
+
* (or used with `labels`). Linear/Plane: ignored in favor of structured
|
|
100
|
+
* filters below. Adapters that can't honor it ignore it.
|
|
101
|
+
* @property {string|string[]} [labels] Restrict to issues carrying label(s).
|
|
102
|
+
* @property {string} [state] Provider state filter (raw name or, for
|
|
103
|
+
* GitHub, open|closed|all).
|
|
104
|
+
* @property {string} [updatedAfter] ISO-8601 polling cursor; only issues
|
|
105
|
+
* updated at/after this.
|
|
106
|
+
* @property {number} [limit] Max tickets to return (bounded).
|
|
107
|
+
* @property {string} [cursor] Opaque pagination cursor (Plane).
|
|
108
|
+
* @property {Object} [ctx] Provider scope/context (e.g. GitHub
|
|
109
|
+
* {owner, repo}; Plane {workspaceSlug,
|
|
110
|
+
* projectId}). Passed through verbatim.
|
|
111
|
+
*/
|
|
112
|
+
/**
|
|
113
|
+
* The neutral tracker interface — the 6-method MINIMUM contract.
|
|
114
|
+
*
|
|
115
|
+
* Three READ methods + three WRITE methods + identity metadata. Each concrete
|
|
116
|
+
* adapter (jira / linear / github / plane) implements exactly these. Anything a
|
|
117
|
+
* single provider can do that the others can't does NOT get a 7th method — it
|
|
118
|
+
* stays accessible only via that provider's own skill tools / the `_raw` hatch.
|
|
119
|
+
*
|
|
120
|
+
* @typedef {Object} TrackerAdapter
|
|
121
|
+
* @property {string} id
|
|
122
|
+
* Provider id: 'jira' | 'linear' | 'github' | 'plane'.
|
|
123
|
+
*
|
|
124
|
+
* @property {(opts?: ListCandidatesOptions) => Promise<NeutralTicket[]>} listCandidates
|
|
125
|
+
* READ. Return a bounded, newest-first set of tickets to consider for work.
|
|
126
|
+
*
|
|
127
|
+
* @property {(key: string, ctx?: Object) => Promise<NeutralTicket|null>} getTicket
|
|
128
|
+
* READ. Fetch one ticket by its `key` (or id). `null` if not found.
|
|
129
|
+
*
|
|
130
|
+
* @property {(key: string, ctx?: Object) => Promise<NeutralComment[]>} getComments
|
|
131
|
+
* READ. Fetch the comment thread (newest first).
|
|
132
|
+
*
|
|
133
|
+
* @property {(key: string, body: string, ctx?: Object) => Promise<{ok: boolean, id?: string|null, error?: string}>} addComment
|
|
134
|
+
* WRITE. Add a comment. `body` is plain text / markdown; the adapter handles
|
|
135
|
+
* provider encoding (Jira ADF, Plane HTML).
|
|
136
|
+
*
|
|
137
|
+
* @property {(key: string, targetStateName: string, ctx?: Object) => Promise<{ok: boolean, stateAfter?: string|null, stateCategoryAfter?: StateCategory, error?: string}>} transition
|
|
138
|
+
* WRITE. Move the ticket to a target state, addressed by its RAW name
|
|
139
|
+
* (fuzzy-matched per provider). Jira performs a workflow transition; Linear /
|
|
140
|
+
* Plane PATCH the state directly; GitHub maps to open/close (+ a labels
|
|
141
|
+
* convention — see github-adapter). NOT every target name is reachable on
|
|
142
|
+
* every provider; the result carries `ok:false` + `error` when it isn't.
|
|
143
|
+
*
|
|
144
|
+
* @property {(key: string, prUrl: string, title?: string, ctx?: Object) => Promise<{ok: boolean, via?: string, error?: string}>} linkPullRequest
|
|
145
|
+
* WRITE. Associate a PR URL with the ticket. Native where possible (Jira
|
|
146
|
+
* remote-link, Linear attachment); a comment everywhere else. `via` reports
|
|
147
|
+
* which path was used ('remotelink' | 'attachment' | 'comment').
|
|
148
|
+
*/
|
|
149
|
+
/** @type {StateCategory[]} */
|
|
150
|
+
export const TRACKER_STATE_CATEGORIES: StateCategory[];
|
|
151
|
+
/**
|
|
152
|
+
* Normalized 5-bucket state. The pipeline branches on this; never on `state`.
|
|
153
|
+
*/
|
|
154
|
+
export type StateCategory = "todo" | "in_progress" | "done" | "blocked" | "unknown";
|
|
155
|
+
/**
|
|
156
|
+
* A tracker ticket/issue projected onto the neutral model.
|
|
157
|
+
*/
|
|
158
|
+
export type NeutralTicket = {
|
|
159
|
+
/**
|
|
160
|
+
* Stable provider-internal id. Jira: issue id (numeric string). Linear: uuid.
|
|
161
|
+
* GitHub: issue number as a string. Plane: work-item uuid. Opaque — pass it
|
|
162
|
+
* back to the same adapter; do not parse it.
|
|
163
|
+
*/
|
|
164
|
+
id: string;
|
|
165
|
+
/**
|
|
166
|
+
* Human-facing reference. Jira: `PROJ-123`. Linear: `ENG-12`. GitHub:
|
|
167
|
+
* `owner/repo#123`. Plane: `PROJ-42` (or the uuid if the identifier is
|
|
168
|
+
* unknown). This is what shows up in PR titles / comments.
|
|
169
|
+
*/
|
|
170
|
+
key: string;
|
|
171
|
+
/**
|
|
172
|
+
* Short summary line (Symphony §4 `title`).
|
|
173
|
+
*/
|
|
174
|
+
title: string;
|
|
175
|
+
/**
|
|
176
|
+
* Full description as plain text / markdown (Symphony §4 `body`). ADF/HTML is
|
|
177
|
+
* flattened by the adapter; never raw ADF or raw HTML here.
|
|
178
|
+
*/
|
|
179
|
+
body: string;
|
|
180
|
+
/**
|
|
181
|
+
* RAW provider status NAME, exactly as the tracker spells it ("In Progress",
|
|
182
|
+
* "Done", "started", "测试"). Use this for write-back (transition). `null`
|
|
183
|
+
* when the provider/issue has no resolvable status.
|
|
184
|
+
*/
|
|
185
|
+
state: string | null;
|
|
186
|
+
/**
|
|
187
|
+
* Normalized bucket — what the pipeline branches on.
|
|
188
|
+
*/
|
|
189
|
+
stateCategory: StateCategory;
|
|
190
|
+
/**
|
|
191
|
+
* Single human-readable assignee (display name or login). `null` if
|
|
192
|
+
* unassigned. Multi-assignee providers (GitHub, Plane) collapse to the first;
|
|
193
|
+
* the full list, if any, lives in `_raw`.
|
|
194
|
+
*/
|
|
195
|
+
assignee: string | null;
|
|
196
|
+
/**
|
|
197
|
+
* Canonical web URL of the ticket, or `null` if the adapter can't derive one.
|
|
198
|
+
*/
|
|
199
|
+
url: string | null;
|
|
200
|
+
/**
|
|
201
|
+
* Escape hatch — the untouched provider payload. Read provider-specific data
|
|
202
|
+
* (sprint, story points, cycle, milestone, sequence_id, labels…) from here.
|
|
203
|
+
* NEVER promote a `_raw` field to a top-level neutral field.
|
|
204
|
+
*/
|
|
205
|
+
_raw: any;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* A single comment on a ticket, projected onto the neutral model.
|
|
209
|
+
*/
|
|
210
|
+
export type NeutralComment = {
|
|
211
|
+
/**
|
|
212
|
+
* Provider comment id (opaque).
|
|
213
|
+
*/
|
|
214
|
+
id: string;
|
|
215
|
+
/**
|
|
216
|
+
* Human-readable author (display name/login).
|
|
217
|
+
*/
|
|
218
|
+
author: string;
|
|
219
|
+
/**
|
|
220
|
+
* Comment text as plain text / markdown
|
|
221
|
+
* (ADF/HTML flattened).
|
|
222
|
+
*/
|
|
223
|
+
body: string;
|
|
224
|
+
/**
|
|
225
|
+
* ISO-8601 creation timestamp, if available.
|
|
226
|
+
*/
|
|
227
|
+
createdAt: string | null;
|
|
228
|
+
/**
|
|
229
|
+
* ISO-8601 update timestamp, if available.
|
|
230
|
+
*/
|
|
231
|
+
updatedAt: string | null;
|
|
232
|
+
/**
|
|
233
|
+
* Untouched provider comment payload.
|
|
234
|
+
*/
|
|
235
|
+
_raw?: any;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Options accepted by {@link TrackerAdapter.listCandidates}. Every field is
|
|
239
|
+
* optional; what each provider honors differs (documented per adapter). The
|
|
240
|
+
* shared minimum is "give me a bounded, newest-first slab of work to consider".
|
|
241
|
+
*/
|
|
242
|
+
export type ListCandidatesOptions = {
|
|
243
|
+
/**
|
|
244
|
+
* Provider-native query. Jira: a JQL string. GitHub: free-text issue search
|
|
245
|
+
* (or used with `labels`). Linear/Plane: ignored in favor of structured
|
|
246
|
+
* filters below. Adapters that can't honor it ignore it.
|
|
247
|
+
*/
|
|
248
|
+
query?: string;
|
|
249
|
+
/**
|
|
250
|
+
* Restrict to issues carrying label(s).
|
|
251
|
+
*/
|
|
252
|
+
labels?: string | string[];
|
|
253
|
+
/**
|
|
254
|
+
* Provider state filter (raw name or, for
|
|
255
|
+
* GitHub, open|closed|all).
|
|
256
|
+
*/
|
|
257
|
+
state?: string;
|
|
258
|
+
/**
|
|
259
|
+
* ISO-8601 polling cursor; only issues
|
|
260
|
+
* updated at/after this.
|
|
261
|
+
*/
|
|
262
|
+
updatedAfter?: string;
|
|
263
|
+
/**
|
|
264
|
+
* Max tickets to return (bounded).
|
|
265
|
+
*/
|
|
266
|
+
limit?: number;
|
|
267
|
+
/**
|
|
268
|
+
* Opaque pagination cursor (Plane).
|
|
269
|
+
*/
|
|
270
|
+
cursor?: string;
|
|
271
|
+
/**
|
|
272
|
+
* Provider scope/context (e.g. GitHub
|
|
273
|
+
* {owner, repo}; Plane {workspaceSlug,
|
|
274
|
+
* projectId}). Passed through verbatim.
|
|
275
|
+
*/
|
|
276
|
+
ctx?: any;
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* The neutral tracker interface — the 6-method MINIMUM contract.
|
|
280
|
+
*
|
|
281
|
+
* Three READ methods + three WRITE methods + identity metadata. Each concrete
|
|
282
|
+
* adapter (jira / linear / github / plane) implements exactly these. Anything a
|
|
283
|
+
* single provider can do that the others can't does NOT get a 7th method — it
|
|
284
|
+
* stays accessible only via that provider's own skill tools / the `_raw` hatch.
|
|
285
|
+
*/
|
|
286
|
+
export type TrackerAdapter = {
|
|
287
|
+
/**
|
|
288
|
+
* Provider id: 'jira' | 'linear' | 'github' | 'plane'.
|
|
289
|
+
*/
|
|
290
|
+
id: string;
|
|
291
|
+
/**
|
|
292
|
+
* READ. Return a bounded, newest-first set of tickets to consider for work.
|
|
293
|
+
*/
|
|
294
|
+
listCandidates: (opts?: ListCandidatesOptions) => Promise<NeutralTicket[]>;
|
|
295
|
+
/**
|
|
296
|
+
* READ. Fetch one ticket by its `key` (or id). `null` if not found.
|
|
297
|
+
*/
|
|
298
|
+
getTicket: (key: string, ctx?: any) => Promise<NeutralTicket | null>;
|
|
299
|
+
/**
|
|
300
|
+
* READ. Fetch the comment thread (newest first).
|
|
301
|
+
*/
|
|
302
|
+
getComments: (key: string, ctx?: any) => Promise<NeutralComment[]>;
|
|
303
|
+
/**
|
|
304
|
+
* WRITE. Add a comment. `body` is plain text / markdown; the adapter handles
|
|
305
|
+
* provider encoding (Jira ADF, Plane HTML).
|
|
306
|
+
*/
|
|
307
|
+
addComment: (key: string, body: string, ctx?: any) => Promise<{
|
|
308
|
+
ok: boolean;
|
|
309
|
+
id?: string | null;
|
|
310
|
+
error?: string;
|
|
311
|
+
}>;
|
|
312
|
+
/**
|
|
313
|
+
* WRITE. Move the ticket to a target state, addressed by its RAW name
|
|
314
|
+
* (fuzzy-matched per provider). Jira performs a workflow transition; Linear /
|
|
315
|
+
* Plane PATCH the state directly; GitHub maps to open/close (+ a labels
|
|
316
|
+
* convention — see github-adapter). NOT every target name is reachable on
|
|
317
|
+
* every provider; the result carries `ok:false` + `error` when it isn't.
|
|
318
|
+
*/
|
|
319
|
+
transition: (key: string, targetStateName: string, ctx?: any) => Promise<{
|
|
320
|
+
ok: boolean;
|
|
321
|
+
stateAfter?: string | null;
|
|
322
|
+
stateCategoryAfter?: StateCategory;
|
|
323
|
+
error?: string;
|
|
324
|
+
}>;
|
|
325
|
+
/**
|
|
326
|
+
* WRITE. Associate a PR URL with the ticket. Native where possible (Jira
|
|
327
|
+
* remote-link, Linear attachment); a comment everywhere else. `via` reports
|
|
328
|
+
* which path was used ('remotelink' | 'attachment' | 'comment').
|
|
329
|
+
*/
|
|
330
|
+
linkPullRequest: (key: string, prUrl: string, title?: string, ctx?: any) => Promise<{
|
|
331
|
+
ok: boolean;
|
|
332
|
+
via?: string;
|
|
333
|
+
error?: string;
|
|
334
|
+
}>;
|
|
335
|
+
};
|