@orc-brain/plugin-linear 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Paulo Lima
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/api.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Linear GraphQL client (spec 003 §R10–§R11): hand-written queries over the
3
+ * injectable `fetchFn` (defaults to global fetch) — no SDK dependency. Every
4
+ * response is mapped to the shared {@link ExternalTask} shape; every failure
5
+ * surfaces as a readable Error (never a hang — the server caps the call).
6
+ */
7
+ import type { ExternalTask, TaskQuery } from "@orc-brain/shared";
8
+ /** Injectable fetch (tests substitute canned GraphQL fixtures, §N3). */
9
+ export type FetchFn = typeof fetch;
10
+ /** Raw issue node as returned by the Linear API. */
11
+ interface IssueNode {
12
+ id: string;
13
+ identifier: string;
14
+ title: string;
15
+ description: string | null;
16
+ url: string;
17
+ updatedAt: string;
18
+ state: {
19
+ name: string;
20
+ type: string;
21
+ } | null;
22
+ assignee: {
23
+ displayName: string;
24
+ } | null;
25
+ labels: {
26
+ nodes: Array<{
27
+ name: string;
28
+ }>;
29
+ } | null;
30
+ }
31
+ /** A team workflow state (§R12 — transitions resolve by `type`, not name). */
32
+ export interface WorkflowState {
33
+ id: string;
34
+ name: string;
35
+ type: string;
36
+ position: number;
37
+ }
38
+ /** Maps a Linear issue node to the normalized {@link ExternalTask} (§R11). */
39
+ export declare function mapIssue(node: IssueNode): ExternalTask;
40
+ /** Builds the Linear `IssueFilter` for a {@link TaskQuery} (§R11). */
41
+ export declare function buildIssueFilter(query: TaskQuery): Record<string, unknown>;
42
+ /** Thin GraphQL transport + the queries/mutations the plugin needs. */
43
+ export declare class LinearClient {
44
+ /** Read at call time so a key set after boot works without a reload. */
45
+ private readonly apiKey;
46
+ private readonly fetchFn;
47
+ constructor(
48
+ /** Read at call time so a key set after boot works without a reload. */
49
+ apiKey: () => string | undefined, fetchFn?: FetchFn);
50
+ private gql;
51
+ /** Issues matching a query, newest-updated first (§R11 listTasks). */
52
+ listIssues(query: TaskQuery): Promise<ExternalTask[]>;
53
+ /** One issue by UUID or human identifier (`ENG-123`), or null (§R11). */
54
+ getIssue(idOrIdentifier: string): Promise<ExternalTask | null>;
55
+ /** Comments on an issue (§R12). */
56
+ createComment(issueId: string, body: string): Promise<void>;
57
+ /** Workflow states of the issue's team, ordered by position (§R12). */
58
+ listIssueTeamStates(issueId: string): Promise<WorkflowState[]>;
59
+ /**
60
+ * Moves an issue to its team's first state of `type` (e.g. `"started"`,
61
+ * `"completed"`) — resolved by type so any workspace works (§R12). Returns
62
+ * the state moved to, or null when the team has none of that type.
63
+ */
64
+ moveIssueToStateType(issueId: string, type: string): Promise<WorkflowState | null>;
65
+ }
66
+ export {};
67
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEjE,wEAAwE;AACxE,MAAM,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC;AAoBnC,oDAAoD;AACpD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7C,QAAQ,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;CACnD;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAatD;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgB1E;AAED,uEAAuE;AACvE,qBAAa,YAAY;IAErB,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;;IAFxB,wEAAwE;IACvD,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,EAChC,OAAO,GAAE,OAAe;YAG7B,GAAG;IAiCjB,sEAAsE;IAChE,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAY3D,yEAAyE;IACnE,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAoCpE,mCAAmC;IAC7B,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjE,uEAAuE;IACjE,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAkBpE;;;;OAIG;IACG,oBAAoB,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CAajC"}
package/dist/api.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Linear GraphQL client (spec 003 §R10–§R11): hand-written queries over the
3
+ * injectable `fetchFn` (defaults to global fetch) — no SDK dependency. Every
4
+ * response is mapped to the shared {@link ExternalTask} shape; every failure
5
+ * surfaces as a readable Error (never a hang — the server caps the call).
6
+ */
7
+ const LINEAR_GRAPHQL_URL = "https://api.linear.app/graphql";
8
+ /** Human identifier form, e.g. `ENG-123` (§R11 getTask). */
9
+ const IDENTIFIER_RE = /^([A-Za-z][A-Za-z0-9]*)-(\d+)$/;
10
+ /** Fields fetched for every issue, matching {@link ExternalTask}. */
11
+ const ISSUE_FIELDS = `
12
+ id
13
+ identifier
14
+ title
15
+ description
16
+ url
17
+ updatedAt
18
+ state { name type }
19
+ assignee { displayName }
20
+ labels { nodes { name } }
21
+ `;
22
+ /** Maps a Linear issue node to the normalized {@link ExternalTask} (§R11). */
23
+ export function mapIssue(node) {
24
+ return {
25
+ provider: "linear",
26
+ id: node.id,
27
+ identifier: node.identifier,
28
+ title: node.title,
29
+ description: node.description ?? "",
30
+ url: node.url,
31
+ state: node.state?.name ?? "",
32
+ ...(node.assignee ? { assignee: node.assignee.displayName } : {}),
33
+ labels: (node.labels?.nodes ?? []).map((l) => l.name),
34
+ updated_at: node.updatedAt,
35
+ };
36
+ }
37
+ /** Builds the Linear `IssueFilter` for a {@link TaskQuery} (§R11). */
38
+ export function buildIssueFilter(query) {
39
+ const filter = {};
40
+ filter.state = query.state
41
+ ? { name: { eqIgnoreCase: query.state } }
42
+ : { type: { nin: ["completed", "canceled"] } };
43
+ if (query.team) {
44
+ filter.team = {
45
+ or: [
46
+ { key: { eqIgnoreCase: query.team } },
47
+ { name: { eqIgnoreCase: query.team } },
48
+ ],
49
+ };
50
+ }
51
+ if (query.search)
52
+ filter.searchableContent = { contains: query.search };
53
+ if (query.assigned_to_me)
54
+ filter.assignee = { isMe: { eq: true } };
55
+ return filter;
56
+ }
57
+ /** Thin GraphQL transport + the queries/mutations the plugin needs. */
58
+ export class LinearClient {
59
+ apiKey;
60
+ fetchFn;
61
+ constructor(
62
+ /** Read at call time so a key set after boot works without a reload. */
63
+ apiKey, fetchFn = fetch) {
64
+ this.apiKey = apiKey;
65
+ this.fetchFn = fetchFn;
66
+ }
67
+ async gql(query, variables) {
68
+ const key = this.apiKey();
69
+ if (!key) {
70
+ throw new Error("LINEAR_API_KEY is not set — run: orc plugin secret set linear LINEAR_API_KEY");
71
+ }
72
+ const res = await this.fetchFn(LINEAR_GRAPHQL_URL, {
73
+ method: "POST",
74
+ headers: { "Content-Type": "application/json", Authorization: key },
75
+ body: JSON.stringify({ query, variables }),
76
+ });
77
+ if (!res.ok) {
78
+ throw new Error(`Linear API HTTP ${res.status}${res.status === 401 || res.status === 400 ? " — check LINEAR_API_KEY" : ""}`);
79
+ }
80
+ const body = (await res.json());
81
+ if (body.errors?.length) {
82
+ throw new Error(`Linear API error: ${body.errors.map((e) => e.message).join("; ")}`);
83
+ }
84
+ if (!body.data)
85
+ throw new Error("Linear API returned no data");
86
+ return body.data;
87
+ }
88
+ /** Issues matching a query, newest-updated first (§R11 listTasks). */
89
+ async listIssues(query) {
90
+ const data = await this.gql(`query Issues($filter: IssueFilter, $first: Int) {
91
+ issues(filter: $filter, first: $first, orderBy: updatedAt) {
92
+ nodes { ${ISSUE_FIELDS} }
93
+ }
94
+ }`, { filter: buildIssueFilter(query), first: query.limit ?? 25 });
95
+ return data.issues.nodes.map(mapIssue);
96
+ }
97
+ /** One issue by UUID or human identifier (`ENG-123`), or null (§R11). */
98
+ async getIssue(idOrIdentifier) {
99
+ const m = IDENTIFIER_RE.exec(idOrIdentifier);
100
+ if (m) {
101
+ const data = await this.gql(`query IssueByIdentifier($filter: IssueFilter) {
102
+ issues(filter: $filter, first: 1) {
103
+ nodes { ${ISSUE_FIELDS} }
104
+ }
105
+ }`, {
106
+ filter: {
107
+ team: { key: { eqIgnoreCase: m[1] } },
108
+ number: { eq: Number(m[2]) },
109
+ },
110
+ });
111
+ const node = data.issues.nodes[0];
112
+ return node ? mapIssue(node) : null;
113
+ }
114
+ try {
115
+ const data = await this.gql(`query Issue($id: String!) {
116
+ issue(id: $id) { ${ISSUE_FIELDS} }
117
+ }`, { id: idOrIdentifier });
118
+ return data.issue ? mapIssue(data.issue) : null;
119
+ }
120
+ catch (err) {
121
+ // Linear answers an unknown id with an "entity not found" error.
122
+ if (/not found/i.test(err instanceof Error ? err.message : "")) {
123
+ return null;
124
+ }
125
+ throw err;
126
+ }
127
+ }
128
+ /** Comments on an issue (§R12). */
129
+ async createComment(issueId, body) {
130
+ await this.gql(`mutation CommentCreate($issueId: String!, $body: String!) {
131
+ commentCreate(input: { issueId: $issueId, body: $body }) { success }
132
+ }`, { issueId, body });
133
+ }
134
+ /** Workflow states of the issue's team, ordered by position (§R12). */
135
+ async listIssueTeamStates(issueId) {
136
+ const data = await this.gql(`query IssueTeamStates($id: String!) {
137
+ issue(id: $id) {
138
+ team { states { nodes { id name type position } } }
139
+ }
140
+ }`, { id: issueId });
141
+ return (data.issue?.team.states.nodes ?? [])
142
+ .slice()
143
+ .sort((a, b) => a.position - b.position);
144
+ }
145
+ /**
146
+ * Moves an issue to its team's first state of `type` (e.g. `"started"`,
147
+ * `"completed"`) — resolved by type so any workspace works (§R12). Returns
148
+ * the state moved to, or null when the team has none of that type.
149
+ */
150
+ async moveIssueToStateType(issueId, type) {
151
+ const state = (await this.listIssueTeamStates(issueId)).find((s) => s.type === type);
152
+ if (!state)
153
+ return null;
154
+ await this.gql(`mutation IssueUpdate($id: String!, $stateId: String!) {
155
+ issueUpdate(id: $id, input: { stateId: $stateId }) { success }
156
+ }`, { id: issueId, stateId: state.id });
157
+ return state;
158
+ }
159
+ }
160
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The Linear plugin (spec 003 §R10–§R13) — orc-brain's first and reference
3
+ * plugin. Bundled in the repo but loaded through the public plugin mechanism
4
+ * (builtin alias `"linear"`). Depends on `@orc-brain/shared` only, proving
5
+ * the third-party contract. Capabilities: `task-provider` (browse/import
6
+ * issues) plus outbound status sync (comments + state transitions).
7
+ *
8
+ * Settings (via `plugins.json`):
9
+ * - `complete_on_success` (boolean, default false): move the issue to a
10
+ * `completed`-type state when a run succeeds (§R12).
11
+ * - `fetchFn` (function, test-only): injectable fetch for offline tests.
12
+ */
13
+ import { type OrcPlugin } from "@orc-brain/shared";
14
+ export { LinearClient, buildIssueFilter, mapIssue } from "./api.js";
15
+ export type { FetchFn, WorkflowState } from "./api.js";
16
+ export { attachSync } from "./sync.js";
17
+ /** Plugin factory (spec 003 §R1 `OrcPluginModule`). */
18
+ export default function createLinearPlugin(settings: Record<string, unknown>): OrcPlugin;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAIL,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,uDAAuD;AACvD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,SAAS,CAmDX"}
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The Linear plugin (spec 003 §R10–§R13) — orc-brain's first and reference
3
+ * plugin. Bundled in the repo but loaded through the public plugin mechanism
4
+ * (builtin alias `"linear"`). Depends on `@orc-brain/shared` only, proving
5
+ * the third-party contract. Capabilities: `task-provider` (browse/import
6
+ * issues) plus outbound status sync (comments + state transitions).
7
+ *
8
+ * Settings (via `plugins.json`):
9
+ * - `complete_on_success` (boolean, default false): move the issue to a
10
+ * `completed`-type state when a run succeeds (§R12).
11
+ * - `fetchFn` (function, test-only): injectable fetch for offline tests.
12
+ */
13
+ import { PLUGIN_API_VERSION, } from "@orc-brain/shared";
14
+ import { LinearClient } from "./api.js";
15
+ import { attachSync } from "./sync.js";
16
+ export { LinearClient, buildIssueFilter, mapIssue } from "./api.js";
17
+ export { attachSync } from "./sync.js";
18
+ /** Plugin factory (spec 003 §R1 `OrcPluginModule`). */
19
+ export default function createLinearPlugin(settings) {
20
+ let host = null;
21
+ const client = new LinearClient(() => host?.getSecret("LINEAR_API_KEY"), settings.fetchFn ?? fetch);
22
+ return {
23
+ manifest: {
24
+ name: "linear",
25
+ version: "1.0.0",
26
+ apiVersion: PLUGIN_API_VERSION,
27
+ capabilities: ["task-provider"],
28
+ secrets: ["LINEAR_API_KEY"],
29
+ },
30
+ init(h) {
31
+ host = h;
32
+ attachSync({
33
+ host: h,
34
+ client,
35
+ completeOnSuccess: settings.complete_on_success === true,
36
+ });
37
+ },
38
+ taskProvider: {
39
+ listTasks: (query) => client.listIssues(query),
40
+ getTask: (id) => client.getIssue(id),
41
+ },
42
+ async onTaskImported(task, goal) {
43
+ // Import comment (§R12): fire-and-forget from the registry; a failure
44
+ // is audited there and must not fail the import.
45
+ const ref = goal.external_ref ?? undefined;
46
+ try {
47
+ await client.createComment(task.id, `orc-brain imported this issue as goal \`${goal.id}\` and is planning.`);
48
+ host?.reportSync("imported", { ref, ok: true });
49
+ }
50
+ catch (err) {
51
+ host?.reportSync("imported", {
52
+ ref,
53
+ ok: false,
54
+ detail: err instanceof Error ? err.message : String(err),
55
+ });
56
+ }
57
+ },
58
+ };
59
+ }
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,kBAAkB,GAMnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAgB,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,uDAAuD;AACvD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CACxC,QAAiC;IAEjC,IAAI,IAAI,GAAsB,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,YAAY,CAC7B,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,gBAAgB,CAAC,EACtC,QAAQ,CAAC,OAA+B,IAAI,KAAK,CACnD,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,OAAO;YAChB,UAAU,EAAE,kBAAkB;YAC9B,YAAY,EAAE,CAAC,eAAe,CAAC;YAC/B,OAAO,EAAE,CAAC,gBAAgB,CAAC;SAC5B;QAED,IAAI,CAAC,CAAa;YAChB,IAAI,GAAG,CAAC,CAAC;YACT,UAAU,CAAC;gBACT,IAAI,EAAE,CAAC;gBACP,MAAM;gBACN,iBAAiB,EAAE,QAAQ,CAAC,mBAAmB,KAAK,IAAI;aACzD,CAAC,CAAC;QACL,CAAC;QAED,YAAY,EAAE;YACZ,SAAS,EAAE,CAAC,KAAgB,EAA2B,EAAE,CACvD,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;YAC1B,OAAO,EAAE,CAAC,EAAU,EAAgC,EAAE,CACpD,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;SACtB;QAED,KAAK,CAAC,cAAc,CAAC,IAAkB,EAAE,IAAU;YACjD,sEAAsE;YACtE,iDAAiD;YACjD,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,aAAa,CACxB,IAAI,CAAC,EAAE,EACP,2CAA2C,IAAI,CAAC,EAAE,qBAAqB,CACxE,CAAC;gBACF,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,EAAE,UAAU,CAAC,UAAU,EAAE;oBAC3B,GAAG;oBACH,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACzD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/sync.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Status sync back to Linear (spec 003 §R12): bus-driven, outbound-only, and
3
+ * strictly fire-and-forget — every Linear call is wrapped so an outage can
4
+ * never affect a run. Actions fire once per run (in-memory guard), only for
5
+ * goals whose `external_ref.provider === "linear"`, and each is reported via
6
+ * `host.reportSync` (audit entry + `plugin.sync` bus event, §R6/§R9).
7
+ */
8
+ import type { PluginHost } from "@orc-brain/shared";
9
+ import type { LinearClient } from "./api.js";
10
+ /** Options for {@link attachSync}. */
11
+ export interface SyncOptions {
12
+ host: PluginHost;
13
+ client: LinearClient;
14
+ /**
15
+ * Move the issue to a `completed`-type state on run success. Default false:
16
+ * comment only — a human verifies before closing (§R12).
17
+ */
18
+ completeOnSuccess: boolean;
19
+ }
20
+ /** Subscribes the sync reactions to the bus (§R12). Idempotent per plugin. */
21
+ export declare function attachSync(opts: SyncOptions): void;
22
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAqB,UAAU,EAAO,MAAM,mBAAmB,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB;;;OAGG;IACH,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAgBD,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAgHlD"}
package/dist/sync.js ADDED
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Status sync back to Linear (spec 003 §R12): bus-driven, outbound-only, and
3
+ * strictly fire-and-forget — every Linear call is wrapped so an outage can
4
+ * never affect a run. Actions fire once per run (in-memory guard), only for
5
+ * goals whose `external_ref.provider === "linear"`, and each is reported via
6
+ * `host.reportSync` (audit entry + `plugin.sync` bus event, §R6/§R9).
7
+ */
8
+ /** The goal behind a run event, when it is a Linear-imported goal. */
9
+ async function linearGoalOfRun(host, runId) {
10
+ const run = await host.getRun(runId);
11
+ if (!run)
12
+ return null;
13
+ const goal = await host.getGoal(run.goal_id);
14
+ if (!goal?.external_ref || goal.external_ref.provider !== "linear") {
15
+ return null;
16
+ }
17
+ return { run, goal, ref: goal.external_ref };
18
+ }
19
+ /** Subscribes the sync reactions to the bus (§R12). Idempotent per plugin. */
20
+ export function attachSync(opts) {
21
+ const { host, client } = opts;
22
+ // Once-per-run guards: a resume re-emits `running`, and terminal states must
23
+ // not double-comment (§8 edge cases — "comment once per run, not per tick").
24
+ const started = new Set();
25
+ const settled = new Set();
26
+ const onRunning = async (runId) => {
27
+ const hit = await linearGoalOfRun(host, runId);
28
+ if (!hit)
29
+ return;
30
+ const { ref } = hit;
31
+ try {
32
+ const state = await client.moveIssueToStateType(ref.id, "started");
33
+ await client.createComment(ref.id, `orc-brain started run \`${runId}\` for goal \`${hit.goal.id}\` (${hit.goal.title}).`);
34
+ host.reportSync("run_started", {
35
+ ref,
36
+ ok: true,
37
+ run_id: runId,
38
+ detail: state
39
+ ? `moved to "${state.name}" and commented`
40
+ : "commented (no started-type state found)",
41
+ });
42
+ }
43
+ catch (err) {
44
+ host.reportSync("run_started", {
45
+ ref,
46
+ ok: false,
47
+ run_id: runId,
48
+ detail: err instanceof Error ? err.message : String(err),
49
+ });
50
+ }
51
+ };
52
+ const onDone = async (runId) => {
53
+ const hit = await linearGoalOfRun(host, runId);
54
+ if (!hit)
55
+ return;
56
+ const { ref, run, goal } = hit;
57
+ try {
58
+ const scopes = await host.listScopesByGoal(goal.id);
59
+ const branches = scopes
60
+ .map((s) => s.branch_name)
61
+ .filter((b) => !!b);
62
+ const lines = [
63
+ `orc-brain finished working on this issue.`,
64
+ ``,
65
+ `- Goal: ${goal.title} (\`${goal.id}\`)`,
66
+ `- Run: \`${runId}\``,
67
+ `- Cost: $${run.budget_spent_usd.toFixed(2)}`,
68
+ ...(branches.length
69
+ ? [`- Branches: ${branches.map((b) => `\`${b}\``).join(", ")}`]
70
+ : []),
71
+ ];
72
+ await client.createComment(ref.id, lines.join("\n"));
73
+ let detail = "commented";
74
+ if (opts.completeOnSuccess) {
75
+ const state = await client.moveIssueToStateType(ref.id, "completed");
76
+ if (state)
77
+ detail = `commented and moved to "${state.name}"`;
78
+ }
79
+ host.reportSync("run_succeeded", {
80
+ ref,
81
+ ok: true,
82
+ run_id: runId,
83
+ detail,
84
+ });
85
+ }
86
+ catch (err) {
87
+ host.reportSync("run_succeeded", {
88
+ ref,
89
+ ok: false,
90
+ run_id: runId,
91
+ detail: err instanceof Error ? err.message : String(err),
92
+ });
93
+ }
94
+ };
95
+ const onFailed = async (runId, reason) => {
96
+ const hit = await linearGoalOfRun(host, runId);
97
+ if (!hit)
98
+ return;
99
+ const { ref } = hit;
100
+ try {
101
+ // Failure never changes the issue state (§R12).
102
+ await client.createComment(ref.id, `orc-brain run \`${runId}\` failed${reason ? `: ${reason}` : "."}`);
103
+ host.reportSync("run_failed", { ref, ok: true, run_id: runId });
104
+ }
105
+ catch (err) {
106
+ host.reportSync("run_failed", {
107
+ ref,
108
+ ok: false,
109
+ run_id: runId,
110
+ detail: err instanceof Error ? err.message : String(err),
111
+ });
112
+ }
113
+ };
114
+ host.subscribe((event) => {
115
+ if (event.type !== "run.state" || !event.run_id)
116
+ return;
117
+ const runId = event.run_id;
118
+ const { state, reason } = event.payload;
119
+ if (state === "running" && !started.has(runId)) {
120
+ started.add(runId);
121
+ void onRunning(runId);
122
+ }
123
+ else if (state === "done" && !settled.has(runId)) {
124
+ settled.add(runId);
125
+ void onDone(runId);
126
+ }
127
+ else if (state === "failed" && !settled.has(runId)) {
128
+ settled.add(runId);
129
+ void onFailed(runId, reason);
130
+ }
131
+ });
132
+ }
133
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@orc-brain/plugin-linear",
3
+ "version": "1.0.0",
4
+ "description": "Linear task-provider plugin for orc-brain (spec 003 reference plugin).",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Paulo Lima",
8
+ "homepage": "https://github.com/anplabs/orc-brain#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/anplabs/orc-brain.git",
12
+ "directory": "packages/plugin-linear"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "engines": {
29
+ "node": ">=22"
30
+ },
31
+ "dependencies": {
32
+ "@orc-brain/shared": "1.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.10.7"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.json",
39
+ "clean": "rm -rf dist"
40
+ }
41
+ }