@dahrk/linear 0.1.0

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/dist/index.js ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @dahrk/linear - the Linear-native control surface (build spec section 14).
3
+ *
4
+ * Two responsibilities:
5
+ * 1. Intake-side (used by the hub): verify the webhook signature, and normalise a
6
+ * raw Linear webhook into the internal LinearEvent. tenantId/workspaceId are
7
+ * resolved from the authenticated connection, never from the payload.
8
+ * 2. Session-side (used by hub + edge): drive the Agent Session API natively -
9
+ * post activities (thought/action/response), render the stage graph as the
10
+ * agent-plan checklist, raise elicitation gates, take prompted-drive turns,
11
+ * handle the stop signal, set externalUrls.
12
+ *
13
+ * Re-implemented directly against the Agent Session API; cyrus's posting code is a
14
+ * reference, not a dependency. Intended runtime dep: the Linear TypeScript SDK
15
+ * (added at M2/M5).
16
+ */
17
+ import { createHmac, timingSafeEqual } from "node:crypto";
18
+ /**
19
+ * Verify a Linear webhook signature and return the parsed payload, or throw.
20
+ * Linear signs the raw request body with HMAC-SHA256 (hex) under the connection's
21
+ * webhook secret; we recompute and compare in constant time over the raw bytes.
22
+ */
23
+ export function verifyWebhook(rawBody, signature, secret) {
24
+ const expected = createHmac("sha256", secret).update(rawBody).digest();
25
+ const given = Buffer.from(signature ?? "", "hex");
26
+ if (expected.length !== given.length || !timingSafeEqual(expected, given)) {
27
+ throw new Error("linear webhook signature mismatch");
28
+ }
29
+ return JSON.parse(rawBody.toString("utf8"));
30
+ }
31
+ /** Fixed 👍/👎 -> sentiment lookup. A reaction's sentiment comes from this table, never an LLM, so the
32
+ * determinism boundary holds. Returns undefined for any emoji we do not treat as feedback. */
33
+ function reactionSentiment(emoji) {
34
+ if (!emoji)
35
+ return undefined;
36
+ if (emoji === "👍" || emoji === "+1" || emoji === "thumbsup")
37
+ return "positive";
38
+ if (emoji === "👎" || emoji === "-1" || emoji === "thumbsdown")
39
+ return "negative";
40
+ return undefined;
41
+ }
42
+ /**
43
+ * Normalise a verified webhook into the internal LinearEvent. `workspaceId` is read
44
+ * from the payload but only trusted once `authenticate` checks it against the
45
+ * connection's registered set. `tenantId` is supplied by the caller from the owning
46
+ * Connection (the single source of truth for a workspace's tenant), never inferred here.
47
+ */
48
+ export function normalise(payload, connectionId, tenantId) {
49
+ const p = (payload ?? {});
50
+ const ts = typeof p.webhookTimestamp === "string" ? p.webhookTimestamp : "1970-01-01T00:00:00Z";
51
+ const base = {
52
+ tenantId,
53
+ connectionId,
54
+ workspaceId: p.organizationId ?? "",
55
+ linearPayload: payload,
56
+ ts,
57
+ };
58
+ if (p.type === "AgentSessionEvent" || p.type === "AgentSession") {
59
+ const agentSessionId = p.agentSession?.id ?? "";
60
+ if (p.action === "created") {
61
+ // Carry the issue id so the hub can map issue -> run (for later Inbox-notification routing).
62
+ const issueId = p.agentSession?.issue?.id;
63
+ return {
64
+ ...base,
65
+ type: "agent-session-created",
66
+ subject: { agentSessionId, ...(issueId ? { issueId } : {}) },
67
+ };
68
+ }
69
+ if (p.action === "prompted") {
70
+ return { ...base, type: "agent-session-prompted", subject: { agentSessionId } };
71
+ }
72
+ if (p.action === "stopped" || p.action === "stop") {
73
+ return { ...base, type: "signal-stop", subject: { agentSessionId } };
74
+ }
75
+ }
76
+ // Inbox notification: the agent was unassigned from an issue -> disengage (stop its run).
77
+ if (p.type === "AppUserNotification" && p.action === "issueUnassignedFromYou") {
78
+ const issueId = p.notification?.issueId ?? p.notification?.issue?.id ?? "";
79
+ return { ...base, type: "issue-unassigned", subject: { issueId } };
80
+ }
81
+ // Inbox notification: the issue's status changed. Only a move to a *canceled* workflow-state type is
82
+ // a disengagement signal (stop its run); any other status change falls through to ignored.
83
+ if (p.type === "AppUserNotification" && p.action === "issueStatusChanged") {
84
+ const stateType = p.notification?.issue?.state?.type ?? p.notification?.issueStatusType;
85
+ if (stateType === "canceled") {
86
+ const issueId = p.notification?.issueId ?? p.notification?.issue?.id ?? "";
87
+ return { ...base, type: "issue-canceled", subject: { issueId } };
88
+ }
89
+ }
90
+ // Inbox notification: a 👍/👎 reaction on a Skakel response -> a feedback signal. A non-thumb emoji
91
+ // falls through to ignored (never mis-dispatched).
92
+ if (p.type === "AppUserNotification" &&
93
+ (p.action === "issueEmojiReaction" || p.action === "issueCommentReaction")) {
94
+ const reaction = reactionSentiment(p.notification?.reaction?.emoji ?? p.notification?.reactionEmoji ?? p.notification?.emoji);
95
+ if (reaction) {
96
+ const issueId = p.notification?.issueId ?? p.notification?.issue?.id ?? "";
97
+ return { ...base, type: "issue-reaction", subject: { issueId }, reaction };
98
+ }
99
+ }
100
+ // The OAuth app install was revoked: the connection is dead, deactivate it. No subject needed.
101
+ if (p.type === "OAuthApp" && p.action === "revoked") {
102
+ return { ...base, type: "oauth-revoked", subject: {} };
103
+ }
104
+ if (p.type === "Issue") {
105
+ const issueId = p.issue?.id ?? p.agentSession?.issue?.id ?? "";
106
+ return { ...base, type: "issue-created", subject: { issueId } };
107
+ }
108
+ throw new Error(`unsupported Linear webhook: type=${p.type} action=${p.action}`);
109
+ }
110
+ /** Keep only the externalUrls Linear accepts: http(s) URLs (internal `skakel://` refs are dropped),
111
+ * with empty/blank URLs removed and duplicates collapsed by `url` (first wins, since Linear requires
112
+ * each URL to be unique within the array). Pure, so it is unit-tested directly. */
113
+ export function filterExternalUrls(urls) {
114
+ const seen = new Set();
115
+ const kept = [];
116
+ for (const u of urls) {
117
+ const url = u.url?.trim();
118
+ if (!url || !/^https?:\/\//.test(url) || seen.has(url))
119
+ continue;
120
+ seen.add(url);
121
+ kept.push({ url, label: u.label });
122
+ }
123
+ return kept;
124
+ }
125
+ export { createRecordingClient } from "./recording-client.js";
126
+ export { createLinearClient } from "./linear-client.js";
127
+ export { authorizeUrl, exchangeCode, refreshTokens, mintAppToken, fetchOrganizationId, probeToken, DEFAULT_AGENT_SCOPES } from "./oauth.js";
128
+ export { provisionLabels, provisionWorkflowLabels, provisionRepoLabels, linearLabelApi, projectLabelApi, fetchIssueProjectRepoLabels, REPO_LABEL_GROUP, } from "./labels.js";
129
+ export { linearTriageApi, linearClientAuth } from "./issues.js";
130
+ export { fetchAttachedDocuments, collectAttachedDocuments, linearDocumentSource, documentSlugFromUrl, documentSlug, } from "./documents.js";
131
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ export interface TriageApi {
2
+ /** Create an issue in `teamKey` (optionally under `projectName`); returns its identifier + url.
3
+ * Created with NO `stateId`, so the issue lands in the team's Triage view when triage is enabled
4
+ * (the intake/review surface), rather than a workflow's default backlog state. */
5
+ createIssue(input: {
6
+ teamKey: string;
7
+ projectName?: string;
8
+ title: string;
9
+ description: string;
10
+ }): Promise<{
11
+ identifier: string;
12
+ url: string;
13
+ }>;
14
+ /** Associate a Customer Request (CustomerNeed) with an issue (SL-359), linking customer feedback to
15
+ * the logged issue. Off-by-default: only called when the source carries customer identity (a
16
+ * `customerId` or external id). Returns the created need's id. */
17
+ createCustomerNeed(input: {
18
+ issueId: string;
19
+ customerId?: string;
20
+ customerExternalId?: string;
21
+ body?: string;
22
+ }): Promise<{
23
+ id: string;
24
+ }>;
25
+ /** Relate one issue to another (SL-379), so a triage-filed fix issue links back to the originating
26
+ * bug. Off-by-default: only called when the target run carries an originating Linear issue. `type`
27
+ * defaults to `related` (a non-directional link); `blocks` records the fix-blocks-bug direction.
28
+ * `issueId`/`relatedIssueId` accept a UUID or an identifier (e.g. `TEST-49`). */
29
+ relateIssues(input: {
30
+ issueId: string;
31
+ relatedIssueId: string;
32
+ type?: "related" | "blocks";
33
+ }): Promise<void>;
34
+ }
35
+ /** Pick the right `@linear/sdk` auth field for a triage token. A personal API key (`lin_api_…`) must
36
+ * go in the raw `Authorization` header (the SDK's `apiKey`); an OAuth access token uses `Bearer` (the
37
+ * SDK's `accessToken`). Sending an API key as a Bearer token fails with "Remove the Bearer prefix…"
38
+ * (SL-399), which is exactly what silently broke triage logging. Exported for testing. */
39
+ export declare function linearClientAuth(token: string): {
40
+ apiKey: string;
41
+ } | {
42
+ accessToken: string;
43
+ };
44
+ /** The live `TriageApi` backed by a Linear token (personal API key or OAuth access token). Resolves
45
+ * team (and optional project) by name, paginating like the label provisioner rather than relying on
46
+ * SDK filter shapes. */
47
+ export declare function linearTriageApi(token: string): TriageApi;
48
+ //# sourceMappingURL=issues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../src/issues.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,SAAS;IACxB;;uFAEmF;IACnF,WAAW,CAAC,KAAK,EAAE;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD;;uEAEmE;IACnE,kBAAkB,CAAC,KAAK,EAAE;QACxB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5B;;;sFAGkF;IAClF,YAAY,CAAC,KAAK,EAAE;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;KAC7B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED;;;2FAG2F;AAC3F,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAE5F;AAED;;yBAEyB;AACzB,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CA8CxD"}
package/dist/issues.js ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Auto-create a Linear triage issue when a run fails (failure-notification path). Mirrors the
3
+ * `LabelApi` seam in ./labels.ts: a small `TriageApi` interface so the hub stays pure and testable,
4
+ * plus a live adapter (`linearTriageApi`) that wraps `@linear/sdk`. It uses the hub's OWN triage
5
+ * token (an internal ops workspace), never a customer connection's token.
6
+ */
7
+ import { IssueRelationType, LinearClient } from "@linear/sdk";
8
+ /** Pick the right `@linear/sdk` auth field for a triage token. A personal API key (`lin_api_…`) must
9
+ * go in the raw `Authorization` header (the SDK's `apiKey`); an OAuth access token uses `Bearer` (the
10
+ * SDK's `accessToken`). Sending an API key as a Bearer token fails with "Remove the Bearer prefix…"
11
+ * (SL-399), which is exactly what silently broke triage logging. Exported for testing. */
12
+ export function linearClientAuth(token) {
13
+ return token.startsWith("lin_api_") ? { apiKey: token } : { accessToken: token };
14
+ }
15
+ /** The live `TriageApi` backed by a Linear token (personal API key or OAuth access token). Resolves
16
+ * team (and optional project) by name, paginating like the label provisioner rather than relying on
17
+ * SDK filter shapes. */
18
+ export function linearTriageApi(token) {
19
+ const client = new LinearClient(linearClientAuth(token));
20
+ return {
21
+ async createIssue(input) {
22
+ const teams = await client.teams();
23
+ while (teams.pageInfo.hasNextPage)
24
+ await teams.fetchNext();
25
+ const team = teams.nodes.find((t) => t.key === input.teamKey);
26
+ if (!team)
27
+ throw new Error(`triage team not found: ${input.teamKey}`);
28
+ let projectId;
29
+ if (input.projectName) {
30
+ const projects = await client.projects();
31
+ while (projects.pageInfo.hasNextPage)
32
+ await projects.fetchNext();
33
+ projectId = projects.nodes.find((p) => p.name === input.projectName)?.id;
34
+ }
35
+ const payload = await client.createIssue({
36
+ teamId: team.id,
37
+ title: input.title,
38
+ description: input.description,
39
+ ...(projectId ? { projectId } : {}),
40
+ });
41
+ const issue = await payload.issue;
42
+ return { identifier: issue?.identifier ?? "", url: issue?.url ?? "" };
43
+ },
44
+ async createCustomerNeed(input) {
45
+ // `issueId` accepts a UUID or an issue identifier (e.g. `TEST-49`); exactly one of
46
+ // `customerId`/`customerExternalId` identifies the customer (the SDK forbids both at once).
47
+ const payload = await client.createCustomerNeed({
48
+ issueId: input.issueId,
49
+ ...(input.customerId ? { customerId: input.customerId } : {}),
50
+ ...(input.customerExternalId ? { customerExternalId: input.customerExternalId } : {}),
51
+ ...(input.body ? { body: input.body } : {}),
52
+ });
53
+ return { id: payload.needId ?? "" };
54
+ },
55
+ async relateIssues(input) {
56
+ await client.createIssueRelation({
57
+ issueId: input.issueId,
58
+ relatedIssueId: input.relatedIssueId,
59
+ type: input.type === "blocks" ? IssueRelationType.Blocks : IssueRelationType.Related,
60
+ });
61
+ },
62
+ };
63
+ }
64
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../src/issues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export interface LabelApi {
2
+ /** Existing workspace labels as a name -> id map. */
3
+ listLabels(): Promise<Map<string, string>>;
4
+ /** Create a label (or label group) and return its id. */
5
+ createLabel(input: {
6
+ name: string;
7
+ color?: string;
8
+ description?: string;
9
+ parentId?: string;
10
+ isGroup?: boolean;
11
+ }): Promise<string>;
12
+ }
13
+ export interface ProvisionOptions {
14
+ /** Colour applied to created labels (hex, e.g. "#5e6ad2"). */
15
+ color?: string;
16
+ /** When set, missing labels are created under a group label of this name (created if absent). */
17
+ groupName?: string;
18
+ /** Description set on the group label when it is created. */
19
+ groupDescription?: string;
20
+ /** Build the description for each created child label. */
21
+ describe?: (name: string) => string;
22
+ }
23
+ /**
24
+ * Idempotently create any missing labels via the `LabelApi` seam. Pre-existing labels (by name) are
25
+ * left untouched; the group, if named, is created once and reused. Returns the names actually created,
26
+ * so callers can log what changed. The seam is namespace-agnostic - pass `linearLabelApi` to provision
27
+ * issue labels or `projectLabelApi` to provision project labels.
28
+ */
29
+ export declare function provisionLabels(api: LabelApi, names: Iterable<string>, opts?: ProvisionOptions): Promise<string[]>;
30
+ /**
31
+ * Idempotently create any missing workflow trigger labels (build spec section 14). Thin wrapper over
32
+ * `provisionLabels` with the workflow-trigger wording, preserving the onboarding behaviour.
33
+ */
34
+ export declare function provisionWorkflowLabels(api: LabelApi, names: Iterable<string>, opts?: ProvisionOptions): Promise<string[]>;
35
+ /** The canonical repo-selector label group: a parent group named `repo` whose children name each
36
+ * repository, rendered `repo › <name>` in Linear. This is the form the routing tier recognises (issue
37
+ * labels override, project labels default); the colon/slash string forms are back-compat only. */
38
+ export declare const REPO_LABEL_GROUP = "repo";
39
+ /**
40
+ * Idempotently create the `repo` label group and a child per repository name, so a `repo › <name>`
41
+ * label is assignable in Linear. Works for either namespace: pass `linearLabelApi(token)` to create the
42
+ * issue-label override group, or `projectLabelApi(token)` to create the project-label default group.
43
+ */
44
+ export declare function provisionRepoLabels(api: LabelApi, repoNames: Iterable<string>, opts?: {
45
+ color?: string;
46
+ }): Promise<string[]>;
47
+ /**
48
+ * Fetch the child names of the issue's **project** `repo` label group (project labels are a separate
49
+ * Linear namespace from issue labels, `Project.labels`). Returns the names of project labels whose
50
+ * parent group is `repo` - e.g. `["skakel-site"]` - so the hub can bind every issue in that project to
51
+ * a repo via the project-label routing tier. Empty when the issue has no project, no project labels, or
52
+ * no `repo` group. A read against the connection token; data assembly, not control flow, so the result
53
+ * feeds deterministic routing and is snapshotted into the run.
54
+ */
55
+ export declare function fetchIssueProjectRepoLabels(token: string, issueId: string): Promise<string[]>;
56
+ /** The live `LabelApi` backed by a Linear bearer token (workspace-scoped labels). */
57
+ export declare function linearLabelApi(token: string): LabelApi;
58
+ /** The live `LabelApi` backed by a Linear bearer token, for **project** labels (a separate namespace
59
+ * from issue labels). Lets `provisionLabels`/`provisionRepoLabels` create the project-label `repo`
60
+ * group that drives the default routing layer. */
61
+ export declare function projectLabelApi(token: string): LabelApi;
62
+ //# sourceMappingURL=labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,yDAAyD;IACzD,WAAW,CAAC,KAAK,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnB;AAED;;mGAEmG;AACnG,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,QAAQ,EACb,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC3B,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB;AAID;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBnG;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAsBtD;AAED;;mDAEmD;AACnD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAsBvD"}
package/dist/labels.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Trigger-label auto-provisioning (build spec section 14; plan item 7). A repository declares its
3
+ * workflows as `.skakel/workflows/*.yaml`, each with a `select.label`; for those labels to be
4
+ * assignable in Linear they must exist in the workspace. Rather than make operators create them by
5
+ * hand, the onboarding path reads the workflow label set and creates any that are missing - once,
6
+ * idempotently - optionally grouped under a single "Dahrk workflow" label group.
7
+ *
8
+ * The `LabelApi` seam keeps this pure and unit-testable: the live adapter (`linearLabelApi`) wraps
9
+ * `@linear/sdk`, while tests inject a fake. Provisioning is read-decoupled from execution - it uses
10
+ * the hub's own credential, not a node's.
11
+ */
12
+ import { LinearClient } from "@linear/sdk";
13
+ /**
14
+ * Idempotently create any missing labels via the `LabelApi` seam. Pre-existing labels (by name) are
15
+ * left untouched; the group, if named, is created once and reused. Returns the names actually created,
16
+ * so callers can log what changed. The seam is namespace-agnostic - pass `linearLabelApi` to provision
17
+ * issue labels or `projectLabelApi` to provision project labels.
18
+ */
19
+ export async function provisionLabels(api, names, opts = {}) {
20
+ const existing = await api.listLabels();
21
+ let parentId;
22
+ if (opts.groupName) {
23
+ parentId =
24
+ existing.get(opts.groupName) ??
25
+ (await api.createLabel({
26
+ name: opts.groupName,
27
+ isGroup: true,
28
+ ...(opts.groupDescription ? { description: opts.groupDescription } : {}),
29
+ }));
30
+ }
31
+ const created = [];
32
+ for (const name of new Set(names)) {
33
+ if (existing.has(name))
34
+ continue;
35
+ await api.createLabel({
36
+ name,
37
+ ...(opts.color ? { color: opts.color } : {}),
38
+ ...(opts.describe ? { description: opts.describe(name) } : {}),
39
+ ...(parentId ? { parentId } : {}),
40
+ });
41
+ created.push(name);
42
+ }
43
+ return created;
44
+ }
45
+ /**
46
+ * Idempotently create any missing workflow trigger labels (build spec section 14). Thin wrapper over
47
+ * `provisionLabels` with the workflow-trigger wording, preserving the onboarding behaviour.
48
+ */
49
+ export async function provisionWorkflowLabels(api, names, opts = {}) {
50
+ return provisionLabels(api, names, {
51
+ ...opts,
52
+ ...(opts.groupName ? { groupDescription: "Dahrk workflow trigger labels" } : {}),
53
+ describe: (name) => `Dahrk workflow trigger: ${name}`,
54
+ });
55
+ }
56
+ /** The canonical repo-selector label group: a parent group named `repo` whose children name each
57
+ * repository, rendered `repo › <name>` in Linear. This is the form the routing tier recognises (issue
58
+ * labels override, project labels default); the colon/slash string forms are back-compat only. */
59
+ export const REPO_LABEL_GROUP = "repo";
60
+ /**
61
+ * Idempotently create the `repo` label group and a child per repository name, so a `repo › <name>`
62
+ * label is assignable in Linear. Works for either namespace: pass `linearLabelApi(token)` to create the
63
+ * issue-label override group, or `projectLabelApi(token)` to create the project-label default group.
64
+ */
65
+ export async function provisionRepoLabels(api, repoNames, opts = {}) {
66
+ return provisionLabels(api, repoNames, {
67
+ ...(opts.color ? { color: opts.color } : {}),
68
+ groupName: REPO_LABEL_GROUP,
69
+ groupDescription: "Dahrk repository selector labels",
70
+ describe: (name) => `Dahrk repository selector: ${name}`,
71
+ });
72
+ }
73
+ const GRAPHQL_URL = "https://api.linear.app/graphql";
74
+ /**
75
+ * Fetch the child names of the issue's **project** `repo` label group (project labels are a separate
76
+ * Linear namespace from issue labels, `Project.labels`). Returns the names of project labels whose
77
+ * parent group is `repo` - e.g. `["skakel-site"]` - so the hub can bind every issue in that project to
78
+ * a repo via the project-label routing tier. Empty when the issue has no project, no project labels, or
79
+ * no `repo` group. A read against the connection token; data assembly, not control flow, so the result
80
+ * feeds deterministic routing and is snapshotted into the run.
81
+ */
82
+ export async function fetchIssueProjectRepoLabels(token, issueId) {
83
+ const res = await fetch(GRAPHQL_URL, {
84
+ method: "POST",
85
+ headers: { "content-type": "application/json", authorization: token },
86
+ body: JSON.stringify({
87
+ query: `query($id:String!){ issue(id:$id){ project{ labels(first:100){ nodes{ name parent{ name } } } } } }`,
88
+ variables: { id: issueId },
89
+ }),
90
+ });
91
+ if (!res.ok)
92
+ throw new Error(`linear graphql ${res.status}`);
93
+ const json = (await res.json().catch(() => ({})));
94
+ if (json.errors?.length)
95
+ throw new Error(json.errors.map((e) => e.message).join("; "));
96
+ const nodes = json.data?.issue?.project?.labels?.nodes ?? [];
97
+ const out = [];
98
+ for (const n of nodes) {
99
+ const group = n.parent?.name;
100
+ if (typeof n.name === "string" && typeof group === "string" && group.trim().toLowerCase() === "repo") {
101
+ out.push(n.name.trim());
102
+ }
103
+ }
104
+ return out;
105
+ }
106
+ /** The live `LabelApi` backed by a Linear bearer token (workspace-scoped labels). */
107
+ export function linearLabelApi(token) {
108
+ const client = new LinearClient({ accessToken: token });
109
+ return {
110
+ async listLabels() {
111
+ const conn = await client.issueLabels();
112
+ while (conn.pageInfo.hasNextPage)
113
+ await conn.fetchNext();
114
+ const map = new Map();
115
+ for (const label of conn.nodes)
116
+ map.set(label.name, label.id);
117
+ return map;
118
+ },
119
+ async createLabel(input) {
120
+ const payload = await client.createIssueLabel({
121
+ name: input.name,
122
+ ...(input.color ? { color: input.color } : {}),
123
+ ...(input.description ? { description: input.description } : {}),
124
+ ...(input.parentId ? { parentId: input.parentId } : {}),
125
+ ...(input.isGroup ? { isGroup: true } : {}),
126
+ });
127
+ const label = await payload.issueLabel;
128
+ return label?.id ?? "";
129
+ },
130
+ };
131
+ }
132
+ /** The live `LabelApi` backed by a Linear bearer token, for **project** labels (a separate namespace
133
+ * from issue labels). Lets `provisionLabels`/`provisionRepoLabels` create the project-label `repo`
134
+ * group that drives the default routing layer. */
135
+ export function projectLabelApi(token) {
136
+ const client = new LinearClient({ accessToken: token });
137
+ return {
138
+ async listLabels() {
139
+ const conn = await client.projectLabels();
140
+ while (conn.pageInfo.hasNextPage)
141
+ await conn.fetchNext();
142
+ const map = new Map();
143
+ for (const label of conn.nodes)
144
+ map.set(label.name, label.id);
145
+ return map;
146
+ },
147
+ async createLabel(input) {
148
+ const payload = await client.createProjectLabel({
149
+ name: input.name,
150
+ ...(input.color ? { color: input.color } : {}),
151
+ ...(input.description ? { description: input.description } : {}),
152
+ ...(input.parentId ? { parentId: input.parentId } : {}),
153
+ ...(input.isGroup ? { isGroup: true } : {}),
154
+ });
155
+ const label = await payload.projectLabel;
156
+ return label?.id ?? "";
157
+ },
158
+ };
159
+ }
160
+ //# sourceMappingURL=labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.js","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { AgentSessionClient } from "./index.js";
2
+ export declare function createLinearClient(token: string): AgentSessionClient;
3
+ //# sourceMappingURL=linear-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-client.d.ts","sourceRoot":"","sources":["../src/linear-client.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAEV,kBAAkB,EAMnB,MAAM,YAAY,CAAC;AAqBpB,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CA4JpE"}