@made-by-moonlight/athene-plugin-tracker-linear 0.9.1
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 +22 -0
- package/dist/activity-events.test.d.ts +7 -0
- package/dist/activity-events.test.d.ts.map +1 -0
- package/dist/activity-events.test.js +114 -0
- package/dist/activity-events.test.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +608 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Composio, Inc.
|
|
4
|
+
Copyright (c) 2026 slievr (Athene fork)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-events.test.d.ts","sourceRoot":"","sources":["../src/activity-events.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for plugin-internal activity events (issue #1659).
|
|
3
|
+
*
|
|
4
|
+
* Covers tracker.dep_missing (MUST emit, deduped once-per-process).
|
|
5
|
+
*/
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
const { recordActivityEventMock, requestMock } = vi.hoisted(() => ({
|
|
8
|
+
recordActivityEventMock: vi.fn(),
|
|
9
|
+
requestMock: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
vi.mock("node:https", () => ({
|
|
12
|
+
request: requestMock,
|
|
13
|
+
}));
|
|
14
|
+
vi.mock("@made-by-moonlight/athene-core", async () => {
|
|
15
|
+
const actual = (await vi.importActual("@made-by-moonlight/athene-core"));
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
recordActivityEvent: recordActivityEventMock,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
// @composio/core is intentionally not installed — the real dynamic import
|
|
22
|
+
// will fail with ERR_MODULE_NOT_FOUND, which is exactly the dep_missing
|
|
23
|
+
// shape we want to exercise.
|
|
24
|
+
import { create, _resetDepMissingEmittedForTesting } from "./index.js";
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.clearAllMocks();
|
|
27
|
+
recordActivityEventMock.mockReset();
|
|
28
|
+
requestMock.mockReset();
|
|
29
|
+
_resetDepMissingEmittedForTesting();
|
|
30
|
+
process.env.COMPOSIO_API_KEY = "test-key";
|
|
31
|
+
process.env.COMPOSIO_ENTITY_ID = "test-entity";
|
|
32
|
+
delete process.env.LINEAR_API_KEY;
|
|
33
|
+
});
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
delete process.env.COMPOSIO_API_KEY;
|
|
36
|
+
delete process.env.COMPOSIO_ENTITY_ID;
|
|
37
|
+
delete process.env.LINEAR_API_KEY;
|
|
38
|
+
vi.useRealTimers();
|
|
39
|
+
});
|
|
40
|
+
function makeProject() {
|
|
41
|
+
return {
|
|
42
|
+
name: "test-project",
|
|
43
|
+
repo: "test/repo",
|
|
44
|
+
path: "/repo/path",
|
|
45
|
+
defaultBranch: "main",
|
|
46
|
+
sessionPrefix: "test",
|
|
47
|
+
tracker: { teamId: "TEAM-1" },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
describe("tracker.dep_missing (MUST emit)", () => {
|
|
51
|
+
it("emits when Composio SDK is not installed", async () => {
|
|
52
|
+
const tracker = create();
|
|
53
|
+
// Any tracker call routes through the composio transport, which will
|
|
54
|
+
// fail to load the missing SDK on first use.
|
|
55
|
+
await expect(tracker.getIssue("TEST-1", makeProject())).rejects.toThrow(/Composio SDK.*not installed/);
|
|
56
|
+
expect(recordActivityEventMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
57
|
+
source: "tracker",
|
|
58
|
+
kind: "tracker.dep_missing",
|
|
59
|
+
level: "error",
|
|
60
|
+
data: expect.objectContaining({
|
|
61
|
+
plugin: "tracker-linear",
|
|
62
|
+
package: "@composio/core",
|
|
63
|
+
}),
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
it("emits exactly once across multiple calls (deduped per-process)", async () => {
|
|
67
|
+
const tracker = create();
|
|
68
|
+
await expect(tracker.getIssue("TEST-1", makeProject())).rejects.toThrow();
|
|
69
|
+
await expect(tracker.getIssue("TEST-2", makeProject())).rejects.toThrow();
|
|
70
|
+
await expect(tracker.getIssue("TEST-3", makeProject())).rejects.toThrow();
|
|
71
|
+
const depMissingCalls = recordActivityEventMock.mock.calls.filter(([event]) => event.kind === "tracker.dep_missing");
|
|
72
|
+
expect(depMissingCalls).toHaveLength(1);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe("tracker.api_timeout", () => {
|
|
76
|
+
it("rejects direct transport timeouts even when activity logging throws", async () => {
|
|
77
|
+
delete process.env.COMPOSIO_API_KEY;
|
|
78
|
+
delete process.env.COMPOSIO_ENTITY_ID;
|
|
79
|
+
process.env.LINEAR_API_KEY = "linear-key";
|
|
80
|
+
vi.useFakeTimers();
|
|
81
|
+
const req = {
|
|
82
|
+
setTimeout: vi.fn(),
|
|
83
|
+
on: vi.fn(),
|
|
84
|
+
write: vi.fn(),
|
|
85
|
+
end: vi.fn(),
|
|
86
|
+
destroy: vi.fn(),
|
|
87
|
+
};
|
|
88
|
+
req.setTimeout.mockImplementation((_timeoutMs, cb) => {
|
|
89
|
+
setTimeout(cb, 0);
|
|
90
|
+
return req;
|
|
91
|
+
});
|
|
92
|
+
req.on.mockReturnValue(req);
|
|
93
|
+
requestMock.mockReturnValue(req);
|
|
94
|
+
recordActivityEventMock.mockImplementationOnce(() => {
|
|
95
|
+
throw new Error("activity sink failed");
|
|
96
|
+
});
|
|
97
|
+
const tracker = create();
|
|
98
|
+
const timeoutExpectation = expect(tracker.getIssue("TEST-1", makeProject())).rejects.toThrow("Linear API request timed out after 30s");
|
|
99
|
+
await vi.runAllTimersAsync();
|
|
100
|
+
await timeoutExpectation;
|
|
101
|
+
expect(req.destroy).toHaveBeenCalled();
|
|
102
|
+
expect(recordActivityEventMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
103
|
+
source: "tracker",
|
|
104
|
+
kind: "tracker.api_timeout",
|
|
105
|
+
level: "warn",
|
|
106
|
+
data: expect.objectContaining({
|
|
107
|
+
plugin: "tracker-linear",
|
|
108
|
+
transport: "direct",
|
|
109
|
+
timeoutMs: 30_000,
|
|
110
|
+
}),
|
|
111
|
+
}));
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=activity-events.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-events.test.js","sourceRoot":"","sources":["../src/activity-events.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tracker-linear plugin — Linear as an issue tracker.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Linear GraphQL API with either:
|
|
5
|
+
* - LINEAR_API_KEY (direct API access)
|
|
6
|
+
* - COMPOSIO_API_KEY (via Composio SDK's LINEAR_RUN_QUERY_OR_MUTATION tool)
|
|
7
|
+
*
|
|
8
|
+
* Auto-detects which key is available and routes accordingly.
|
|
9
|
+
*/
|
|
10
|
+
import { type Tracker } from "@made-by-moonlight/athene-core";
|
|
11
|
+
/** Test-only: reset the once-per-process dep_missing guard. */
|
|
12
|
+
export declare function _resetDepMissingEmittedForTesting(): void;
|
|
13
|
+
export declare const manifest: {
|
|
14
|
+
name: string;
|
|
15
|
+
slot: "tracker";
|
|
16
|
+
description: string;
|
|
17
|
+
version: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function create(): Tracker;
|
|
20
|
+
declare const _default: {
|
|
21
|
+
manifest: {
|
|
22
|
+
name: string;
|
|
23
|
+
slot: "tracker";
|
|
24
|
+
description: string;
|
|
25
|
+
version: string;
|
|
26
|
+
};
|
|
27
|
+
create: typeof create;
|
|
28
|
+
};
|
|
29
|
+
export default _default;
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAQL,KAAK,OAAO,EACb,MAAM,gCAAgC,CAAC;AAOxC,+DAA+D;AAC/D,wBAAgB,iCAAiC,IAAI,IAAI,CAExD;AAoxBD,eAAO,MAAM,QAAQ;;;;;CAKpB,CAAC;AAEF,wBAAgB,MAAM,IAAI,OAAO,CAOhC;;;;;;;;;;AAED,wBAAoE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tracker-linear plugin — Linear as an issue tracker.
|
|
3
|
+
*
|
|
4
|
+
* Uses the Linear GraphQL API with either:
|
|
5
|
+
* - LINEAR_API_KEY (direct API access)
|
|
6
|
+
* - COMPOSIO_API_KEY (via Composio SDK's LINEAR_RUN_QUERY_OR_MUTATION tool)
|
|
7
|
+
*
|
|
8
|
+
* Auto-detects which key is available and routes accordingly.
|
|
9
|
+
*/
|
|
10
|
+
import { request } from "node:https";
|
|
11
|
+
import { recordActivityEvent, } from "@made-by-moonlight/athene-core";
|
|
12
|
+
// Module-level guard so we only emit tracker.dep_missing once per process
|
|
13
|
+
// even if multiple sessions trigger the missing-SDK path.
|
|
14
|
+
let depMissingEmitted = false;
|
|
15
|
+
/** Test-only: reset the once-per-process dep_missing guard. */
|
|
16
|
+
export function _resetDepMissingEmittedForTesting() {
|
|
17
|
+
depMissingEmitted = false;
|
|
18
|
+
}
|
|
19
|
+
function recordTransportActivityEvent(event) {
|
|
20
|
+
try {
|
|
21
|
+
recordActivityEvent(event);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Activity logging must never prevent timeout promises from settling.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Direct Linear API transport
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
const LINEAR_API_URL = "https://api.linear.app/graphql";
|
|
31
|
+
const DIRECT_TRANSPORT_MAX_ATTEMPTS = 3;
|
|
32
|
+
const DIRECT_TRANSPORT_RETRY_DELAY_MS = 500;
|
|
33
|
+
class LinearHttpError extends Error {
|
|
34
|
+
status;
|
|
35
|
+
constructor(status, body) {
|
|
36
|
+
super(`Linear API returned HTTP ${status}: ${body.slice(0, 200)}`);
|
|
37
|
+
this.status = status;
|
|
38
|
+
}
|
|
39
|
+
get transient() {
|
|
40
|
+
return this.status === 408 || this.status === 429 || this.status >= 500;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
class LinearNetworkError extends Error {
|
|
44
|
+
constructor(message) {
|
|
45
|
+
super(`Linear API network error: ${message}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class LinearTimeoutError extends Error {
|
|
49
|
+
constructor() {
|
|
50
|
+
super("Linear API request timed out after 30s");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function sleep(ms) {
|
|
54
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
55
|
+
}
|
|
56
|
+
function isRetryableDirectTransportError(err) {
|
|
57
|
+
if (err instanceof LinearHttpError)
|
|
58
|
+
return err.transient;
|
|
59
|
+
if (err instanceof LinearTimeoutError)
|
|
60
|
+
return true;
|
|
61
|
+
return err instanceof LinearNetworkError;
|
|
62
|
+
}
|
|
63
|
+
function getApiKey() {
|
|
64
|
+
const key = process.env["LINEAR_API_KEY"];
|
|
65
|
+
if (!key) {
|
|
66
|
+
throw new Error("LINEAR_API_KEY environment variable is required for the Linear tracker plugin");
|
|
67
|
+
}
|
|
68
|
+
return key;
|
|
69
|
+
}
|
|
70
|
+
function createDirectTransport() {
|
|
71
|
+
return async (query, variables) => {
|
|
72
|
+
const apiKey = getApiKey();
|
|
73
|
+
const body = JSON.stringify({ query, variables });
|
|
74
|
+
const execute = () => new Promise((resolve, reject) => {
|
|
75
|
+
const url = new URL(LINEAR_API_URL);
|
|
76
|
+
let settled = false;
|
|
77
|
+
const settle = (fn) => {
|
|
78
|
+
if (!settled) {
|
|
79
|
+
settled = true;
|
|
80
|
+
fn();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const req = request({
|
|
84
|
+
hostname: url.hostname,
|
|
85
|
+
path: url.pathname,
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/json",
|
|
89
|
+
Authorization: apiKey,
|
|
90
|
+
"Content-Length": Buffer.byteLength(body),
|
|
91
|
+
},
|
|
92
|
+
}, (res) => {
|
|
93
|
+
const chunks = [];
|
|
94
|
+
res.on("error", (err) => settle(() => reject(new LinearNetworkError(err.message))));
|
|
95
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
96
|
+
res.on("end", () => {
|
|
97
|
+
settle(() => {
|
|
98
|
+
try {
|
|
99
|
+
const text = Buffer.concat(chunks).toString("utf-8");
|
|
100
|
+
const status = res.statusCode ?? 0;
|
|
101
|
+
if (status < 200 || status >= 300) {
|
|
102
|
+
reject(new LinearHttpError(status, text));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const json = JSON.parse(text);
|
|
106
|
+
if (json.errors && json.errors.length > 0) {
|
|
107
|
+
reject(new Error(`Linear API error: ${json.errors[0].message}`));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (!json.data) {
|
|
111
|
+
reject(new Error("Linear API returned no data"));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
resolve(json.data);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
reject(err);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
req.setTimeout(30_000, () => {
|
|
123
|
+
settle(() => {
|
|
124
|
+
req.destroy();
|
|
125
|
+
recordTransportActivityEvent({
|
|
126
|
+
source: "tracker",
|
|
127
|
+
kind: "tracker.api_timeout",
|
|
128
|
+
level: "warn",
|
|
129
|
+
summary: "Linear API request timed out after 30s",
|
|
130
|
+
data: {
|
|
131
|
+
plugin: "tracker-linear",
|
|
132
|
+
transport: "direct",
|
|
133
|
+
timeoutMs: 30_000,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
reject(new LinearTimeoutError());
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
req.on("error", (err) => settle(() => reject(new LinearNetworkError(err.message))));
|
|
140
|
+
req.write(body);
|
|
141
|
+
req.end();
|
|
142
|
+
});
|
|
143
|
+
for (let attempt = 1; attempt <= DIRECT_TRANSPORT_MAX_ATTEMPTS; attempt++) {
|
|
144
|
+
try {
|
|
145
|
+
return await execute();
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
const shouldRetry = isRetryableDirectTransportError(err) && attempt < DIRECT_TRANSPORT_MAX_ATTEMPTS;
|
|
149
|
+
if (!shouldRetry)
|
|
150
|
+
throw err;
|
|
151
|
+
await sleep(DIRECT_TRANSPORT_RETRY_DELAY_MS * attempt);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
throw new Error("unreachable");
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function createComposioTransport(apiKey, entityId) {
|
|
158
|
+
// Lazy-load the Composio client — cached as a promise so the constructor
|
|
159
|
+
// is called only once, even under concurrent requests.
|
|
160
|
+
let clientPromise;
|
|
161
|
+
function getClient() {
|
|
162
|
+
if (!clientPromise) {
|
|
163
|
+
clientPromise = (async () => {
|
|
164
|
+
try {
|
|
165
|
+
const { Composio } = await import("@composio/core");
|
|
166
|
+
const client = new Composio({ apiKey });
|
|
167
|
+
return client.tools;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
171
|
+
if (msg.includes("Cannot find module") ||
|
|
172
|
+
msg.includes("Cannot find package") ||
|
|
173
|
+
msg.includes("ERR_MODULE_NOT_FOUND")) {
|
|
174
|
+
// User-actionable, system-wide. Emit once per process.
|
|
175
|
+
if (!depMissingEmitted) {
|
|
176
|
+
depMissingEmitted = true;
|
|
177
|
+
recordActivityEvent({
|
|
178
|
+
source: "tracker",
|
|
179
|
+
kind: "tracker.dep_missing",
|
|
180
|
+
level: "error",
|
|
181
|
+
summary: "Composio SDK (@composio/core) is not installed",
|
|
182
|
+
data: {
|
|
183
|
+
plugin: "tracker-linear",
|
|
184
|
+
package: "@composio/core",
|
|
185
|
+
installHint: "pnpm add @composio/core",
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
throw new Error("Composio SDK (@composio/core) is not installed. " +
|
|
190
|
+
"Install it with: pnpm add @composio/core", { cause: err });
|
|
191
|
+
}
|
|
192
|
+
throw err;
|
|
193
|
+
}
|
|
194
|
+
})();
|
|
195
|
+
}
|
|
196
|
+
return clientPromise;
|
|
197
|
+
}
|
|
198
|
+
return async (query, variables) => {
|
|
199
|
+
const tools = await getClient();
|
|
200
|
+
const resultPromise = tools.execute("LINEAR_RUN_QUERY_OR_MUTATION", {
|
|
201
|
+
entityId,
|
|
202
|
+
arguments: {
|
|
203
|
+
query_or_mutation: query,
|
|
204
|
+
variables: variables ? JSON.stringify(variables) : "{}",
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
// Apply 30s timeout for parity with the direct transport
|
|
208
|
+
let timer;
|
|
209
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
210
|
+
timer = setTimeout(() => {
|
|
211
|
+
recordTransportActivityEvent({
|
|
212
|
+
source: "tracker",
|
|
213
|
+
kind: "tracker.api_timeout",
|
|
214
|
+
level: "warn",
|
|
215
|
+
summary: "Composio Linear API request timed out after 30s",
|
|
216
|
+
data: {
|
|
217
|
+
plugin: "tracker-linear",
|
|
218
|
+
transport: "composio",
|
|
219
|
+
timeoutMs: 30_000,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
reject(new Error("Composio Linear API request timed out after 30s"));
|
|
223
|
+
}, 30_000);
|
|
224
|
+
});
|
|
225
|
+
// Whichever promise loses the race is left without a handler.
|
|
226
|
+
// Attach no-op .catch() to both so the loser doesn't trigger an
|
|
227
|
+
// unhandled promise rejection. This does not affect Promise.race —
|
|
228
|
+
// it still propagates the winning rejection normally.
|
|
229
|
+
resultPromise.catch(() => { });
|
|
230
|
+
timeoutPromise.catch(() => { });
|
|
231
|
+
try {
|
|
232
|
+
const result = await Promise.race([resultPromise, timeoutPromise]);
|
|
233
|
+
if (!result.successful) {
|
|
234
|
+
throw new Error(`Composio Linear API error: ${result.error ?? "unknown error"}`);
|
|
235
|
+
}
|
|
236
|
+
if (!result.data) {
|
|
237
|
+
throw new Error("Composio Linear API returned no data");
|
|
238
|
+
}
|
|
239
|
+
return result.data;
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
clearTimeout(timer);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// State mapping
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
function mapLinearState(stateType) {
|
|
250
|
+
switch (stateType) {
|
|
251
|
+
case "completed":
|
|
252
|
+
return "closed";
|
|
253
|
+
case "canceled":
|
|
254
|
+
return "cancelled";
|
|
255
|
+
case "started":
|
|
256
|
+
return "in_progress";
|
|
257
|
+
default:
|
|
258
|
+
// triage, backlog, unstarted
|
|
259
|
+
return "open";
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
// Issue fields fragment
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
const ISSUE_FIELDS = `
|
|
266
|
+
id
|
|
267
|
+
identifier
|
|
268
|
+
title
|
|
269
|
+
description
|
|
270
|
+
url
|
|
271
|
+
priority
|
|
272
|
+
branchName
|
|
273
|
+
state { name type }
|
|
274
|
+
labels { nodes { name } }
|
|
275
|
+
assignee { name displayName }
|
|
276
|
+
team { key }
|
|
277
|
+
`;
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// Tracker implementation
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
function createLinearTracker(query) {
|
|
282
|
+
return {
|
|
283
|
+
name: "linear",
|
|
284
|
+
async getIssue(identifier, _project) {
|
|
285
|
+
const data = await query(`query($id: String!) {
|
|
286
|
+
issue(id: $id) {
|
|
287
|
+
${ISSUE_FIELDS}
|
|
288
|
+
}
|
|
289
|
+
}`, { id: identifier });
|
|
290
|
+
const node = data.issue;
|
|
291
|
+
return {
|
|
292
|
+
id: node.identifier,
|
|
293
|
+
title: node.title,
|
|
294
|
+
description: node.description ?? "",
|
|
295
|
+
url: node.url,
|
|
296
|
+
state: mapLinearState(node.state.type),
|
|
297
|
+
labels: node.labels.nodes.map((l) => l.name),
|
|
298
|
+
assignee: node.assignee?.displayName ?? node.assignee?.name,
|
|
299
|
+
priority: node.priority,
|
|
300
|
+
branchName: node.branchName ?? undefined,
|
|
301
|
+
};
|
|
302
|
+
},
|
|
303
|
+
async isCompleted(identifier, _project) {
|
|
304
|
+
const data = await query(`query($id: String!) {
|
|
305
|
+
issue(id: $id) {
|
|
306
|
+
state { type }
|
|
307
|
+
}
|
|
308
|
+
}`, { id: identifier });
|
|
309
|
+
const stateType = data.issue.state.type;
|
|
310
|
+
return stateType === "completed" || stateType === "canceled";
|
|
311
|
+
},
|
|
312
|
+
issueUrl(identifier, project) {
|
|
313
|
+
const slug = project.tracker?.["workspaceSlug"];
|
|
314
|
+
if (slug) {
|
|
315
|
+
return `https://linear.app/${slug}/issue/${identifier}`;
|
|
316
|
+
}
|
|
317
|
+
// Fallback: Linear also supports /issue/ URLs that redirect,
|
|
318
|
+
// but they require authentication
|
|
319
|
+
return `https://linear.app/issue/${identifier}`;
|
|
320
|
+
},
|
|
321
|
+
issueLabel(url, _project) {
|
|
322
|
+
// Extract identifier from Linear URL
|
|
323
|
+
// Examples:
|
|
324
|
+
// https://linear.app/composio/issue/INT-1327
|
|
325
|
+
// https://linear.app/issue/INT-1327
|
|
326
|
+
const match = url.match(/\/issue\/([A-Z]+-\d+)/);
|
|
327
|
+
if (match) {
|
|
328
|
+
return match[1];
|
|
329
|
+
}
|
|
330
|
+
// Fallback: return the last segment of the URL
|
|
331
|
+
const parts = url.split("/");
|
|
332
|
+
return parts[parts.length - 1] || url;
|
|
333
|
+
},
|
|
334
|
+
branchName(identifier, _project) {
|
|
335
|
+
// Linear convention: feat/INT-1330
|
|
336
|
+
return `feat/${identifier}`;
|
|
337
|
+
},
|
|
338
|
+
async generatePrompt(identifier, project) {
|
|
339
|
+
const issue = await this.getIssue(identifier, project);
|
|
340
|
+
const lines = [
|
|
341
|
+
`You are working on Linear ticket ${issue.id}: ${issue.title}`,
|
|
342
|
+
`Issue URL: ${issue.url}`,
|
|
343
|
+
"",
|
|
344
|
+
];
|
|
345
|
+
if (issue.labels.length > 0) {
|
|
346
|
+
lines.push(`Labels: ${issue.labels.join(", ")}`);
|
|
347
|
+
}
|
|
348
|
+
if (issue.priority !== undefined) {
|
|
349
|
+
const priorityNames = {
|
|
350
|
+
0: "No priority",
|
|
351
|
+
1: "Urgent",
|
|
352
|
+
2: "High",
|
|
353
|
+
3: "Normal",
|
|
354
|
+
4: "Low",
|
|
355
|
+
};
|
|
356
|
+
lines.push(`Priority: ${priorityNames[issue.priority] ?? String(issue.priority)}`);
|
|
357
|
+
}
|
|
358
|
+
if (issue.description) {
|
|
359
|
+
lines.push("## Description", "", issue.description);
|
|
360
|
+
}
|
|
361
|
+
lines.push("", "Please implement the changes described in this ticket. When done, commit and push your changes.");
|
|
362
|
+
return lines.join("\n");
|
|
363
|
+
},
|
|
364
|
+
async listIssues(filters, project) {
|
|
365
|
+
// Build filter object using GraphQL variables to prevent injection
|
|
366
|
+
const filter = {};
|
|
367
|
+
const variables = {};
|
|
368
|
+
if (filters.state === "closed") {
|
|
369
|
+
filter["state"] = { type: { in: ["completed", "canceled"] } };
|
|
370
|
+
}
|
|
371
|
+
else if (filters.state !== "all") {
|
|
372
|
+
// Default to open (exclude completed/canceled) to match tracker-github
|
|
373
|
+
filter["state"] = { type: { nin: ["completed", "canceled"] } };
|
|
374
|
+
}
|
|
375
|
+
if (filters.assignee) {
|
|
376
|
+
filter["assignee"] = { displayName: { eq: filters.assignee } };
|
|
377
|
+
}
|
|
378
|
+
if (filters.labels && filters.labels.length > 0) {
|
|
379
|
+
filter["labels"] = { name: { in: filters.labels } };
|
|
380
|
+
}
|
|
381
|
+
// Add team filter if available from project config
|
|
382
|
+
const teamId = project.tracker?.["teamId"];
|
|
383
|
+
if (teamId) {
|
|
384
|
+
filter["team"] = { id: { eq: teamId } };
|
|
385
|
+
}
|
|
386
|
+
variables["filter"] = Object.keys(filter).length > 0 ? filter : undefined;
|
|
387
|
+
variables["first"] = filters.limit ?? 30;
|
|
388
|
+
const data = await query(`query($filter: IssueFilter, $first: Int!) {
|
|
389
|
+
issues(filter: $filter, first: $first) {
|
|
390
|
+
nodes {
|
|
391
|
+
${ISSUE_FIELDS}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}`, variables);
|
|
395
|
+
return data.issues.nodes.map((node) => ({
|
|
396
|
+
id: node.identifier,
|
|
397
|
+
title: node.title,
|
|
398
|
+
description: node.description ?? "",
|
|
399
|
+
url: node.url,
|
|
400
|
+
state: mapLinearState(node.state.type),
|
|
401
|
+
labels: node.labels.nodes.map((l) => l.name),
|
|
402
|
+
assignee: node.assignee?.displayName ?? node.assignee?.name,
|
|
403
|
+
priority: node.priority,
|
|
404
|
+
branchName: node.branchName ?? undefined,
|
|
405
|
+
}));
|
|
406
|
+
},
|
|
407
|
+
async updateIssue(identifier, update, _project) {
|
|
408
|
+
// Linear's issue() query accepts both UUID and short identifier (e.g. "INT-1330").
|
|
409
|
+
// We resolve to UUID here for use in mutations.
|
|
410
|
+
const issueData = await query(`query($id: String!) {
|
|
411
|
+
issue(id: $id) {
|
|
412
|
+
id
|
|
413
|
+
team { id }
|
|
414
|
+
}
|
|
415
|
+
}`, { id: identifier });
|
|
416
|
+
const issueUuid = issueData.issue.id;
|
|
417
|
+
const teamId = issueData.issue.team.id;
|
|
418
|
+
// Handle state change
|
|
419
|
+
if (update.state) {
|
|
420
|
+
// Need to find the correct workflow state ID
|
|
421
|
+
const statesData = await query(`query($teamId: ID!) {
|
|
422
|
+
workflowStates(filter: { team: { id: { eq: $teamId } } }) {
|
|
423
|
+
nodes { id name type }
|
|
424
|
+
}
|
|
425
|
+
}`, { teamId });
|
|
426
|
+
const targetType = update.state === "closed"
|
|
427
|
+
? "completed"
|
|
428
|
+
: update.state === "open"
|
|
429
|
+
? "unstarted"
|
|
430
|
+
: "started";
|
|
431
|
+
const targetState = statesData.workflowStates.nodes.find((s) => s.type === targetType);
|
|
432
|
+
if (!targetState) {
|
|
433
|
+
throw new Error(`No workflow state of type "${targetType}" found for team ${teamId}`);
|
|
434
|
+
}
|
|
435
|
+
await query(`mutation($id: String!, $stateId: String!) {
|
|
436
|
+
issueUpdate(id: $id, input: { stateId: $stateId }) {
|
|
437
|
+
success
|
|
438
|
+
}
|
|
439
|
+
}`, { id: issueUuid, stateId: targetState.id });
|
|
440
|
+
}
|
|
441
|
+
// Handle assignee
|
|
442
|
+
if (update.assignee) {
|
|
443
|
+
const usersData = await query(`query($filter: UserFilter) {
|
|
444
|
+
users(filter: $filter) {
|
|
445
|
+
nodes { id displayName name }
|
|
446
|
+
}
|
|
447
|
+
}`, { filter: { displayName: { eq: update.assignee } } });
|
|
448
|
+
const user = usersData.users.nodes[0];
|
|
449
|
+
if (user) {
|
|
450
|
+
await query(`mutation($id: String!, $assigneeId: String!) {
|
|
451
|
+
issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
|
|
452
|
+
success
|
|
453
|
+
}
|
|
454
|
+
}`, { id: issueUuid, assigneeId: user.id });
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Handle labels (additive — merge with existing labels to match tracker-github behavior)
|
|
458
|
+
if (update.labels && update.labels.length > 0) {
|
|
459
|
+
// Fetch existing label IDs on the issue
|
|
460
|
+
const existingData = await query(`query($id: String!) {
|
|
461
|
+
issue(id: $id) {
|
|
462
|
+
labels { nodes { id } }
|
|
463
|
+
}
|
|
464
|
+
}`, { id: issueUuid });
|
|
465
|
+
const existingIds = new Set(existingData.issue.labels.nodes.map((l) => l.id));
|
|
466
|
+
// Resolve new label names to IDs
|
|
467
|
+
const labelsData = await query(`query($teamId: ID) {
|
|
468
|
+
issueLabels(filter: { team: { id: { eq: $teamId } } }) {
|
|
469
|
+
nodes { id name }
|
|
470
|
+
}
|
|
471
|
+
}`, { teamId });
|
|
472
|
+
const labelMap = new Map(labelsData.issueLabels.nodes.map((l) => [l.name, l.id]));
|
|
473
|
+
for (const name of update.labels) {
|
|
474
|
+
const id = labelMap.get(name);
|
|
475
|
+
if (id)
|
|
476
|
+
existingIds.add(id);
|
|
477
|
+
}
|
|
478
|
+
await query(`mutation($id: String!, $labelIds: [String!]!) {
|
|
479
|
+
issueUpdate(id: $id, input: { labelIds: $labelIds }) {
|
|
480
|
+
success
|
|
481
|
+
}
|
|
482
|
+
}`, { id: issueUuid, labelIds: [...existingIds] });
|
|
483
|
+
}
|
|
484
|
+
// Handle comment
|
|
485
|
+
if (update.comment) {
|
|
486
|
+
await query(`mutation($issueId: String!, $body: String!) {
|
|
487
|
+
commentCreate(input: { issueId: $issueId, body: $body }) {
|
|
488
|
+
success
|
|
489
|
+
}
|
|
490
|
+
}`, { issueId: issueUuid, body: update.comment });
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
async createIssue(input, project) {
|
|
494
|
+
const teamId = project.tracker?.["teamId"];
|
|
495
|
+
if (!teamId) {
|
|
496
|
+
throw new Error("Linear tracker requires 'teamId' in project tracker config");
|
|
497
|
+
}
|
|
498
|
+
const variables = {
|
|
499
|
+
title: input.title,
|
|
500
|
+
description: input.description ?? "",
|
|
501
|
+
teamId,
|
|
502
|
+
};
|
|
503
|
+
if (input.priority !== undefined) {
|
|
504
|
+
variables["priority"] = input.priority;
|
|
505
|
+
}
|
|
506
|
+
const data = await query(`mutation($title: String!, $description: String!, $teamId: String!, $priority: Int) {
|
|
507
|
+
issueCreate(input: {
|
|
508
|
+
title: $title,
|
|
509
|
+
description: $description,
|
|
510
|
+
teamId: $teamId,
|
|
511
|
+
priority: $priority
|
|
512
|
+
}) {
|
|
513
|
+
success
|
|
514
|
+
issue {
|
|
515
|
+
${ISSUE_FIELDS}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}`, variables);
|
|
519
|
+
const node = data.issueCreate.issue;
|
|
520
|
+
const issue = {
|
|
521
|
+
id: node.identifier,
|
|
522
|
+
title: node.title,
|
|
523
|
+
description: node.description ?? "",
|
|
524
|
+
url: node.url,
|
|
525
|
+
state: mapLinearState(node.state.type),
|
|
526
|
+
labels: node.labels.nodes.map((l) => l.name),
|
|
527
|
+
assignee: node.assignee?.displayName ?? node.assignee?.name,
|
|
528
|
+
priority: node.priority,
|
|
529
|
+
branchName: node.branchName ?? undefined,
|
|
530
|
+
};
|
|
531
|
+
// Assign after creation (Linear's issueCreate uses assigneeId, not display name)
|
|
532
|
+
if (input.assignee) {
|
|
533
|
+
try {
|
|
534
|
+
const usersData = await query(`query($filter: UserFilter) {
|
|
535
|
+
users(filter: $filter) {
|
|
536
|
+
nodes { id displayName name }
|
|
537
|
+
}
|
|
538
|
+
}`, { filter: { displayName: { eq: input.assignee } } });
|
|
539
|
+
const user = usersData.users.nodes[0];
|
|
540
|
+
if (user) {
|
|
541
|
+
await query(`mutation($id: String!, $assigneeId: String!) {
|
|
542
|
+
issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
|
|
543
|
+
success
|
|
544
|
+
}
|
|
545
|
+
}`, { id: node.id, assigneeId: user.id });
|
|
546
|
+
issue.assignee = input.assignee;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
// Assignee is best-effort
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// Add labels after creation (Linear's issueCreate doesn't accept label names directly)
|
|
554
|
+
if (input.labels && input.labels.length > 0) {
|
|
555
|
+
try {
|
|
556
|
+
// Look up label IDs by name for the team
|
|
557
|
+
const labelsData = await query(`query($teamId: ID) {
|
|
558
|
+
issueLabels(filter: { team: { id: { eq: $teamId } } }) {
|
|
559
|
+
nodes { id name }
|
|
560
|
+
}
|
|
561
|
+
}`, { teamId });
|
|
562
|
+
const labelMap = new Map(labelsData.issueLabels.nodes.map((l) => [l.name, l.id]));
|
|
563
|
+
const appliedLabels = [];
|
|
564
|
+
const labelIds = [];
|
|
565
|
+
for (const name of input.labels) {
|
|
566
|
+
const id = labelMap.get(name);
|
|
567
|
+
if (id) {
|
|
568
|
+
labelIds.push(id);
|
|
569
|
+
appliedLabels.push(name);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (labelIds.length > 0) {
|
|
573
|
+
await query(`mutation($id: String!, $labelIds: [String!]!) {
|
|
574
|
+
issueUpdate(id: $id, input: { labelIds: $labelIds }) {
|
|
575
|
+
success
|
|
576
|
+
}
|
|
577
|
+
}`, { id: node.id, labelIds });
|
|
578
|
+
// Reflect only the labels that actually exist in Linear
|
|
579
|
+
issue.labels = appliedLabels;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
catch {
|
|
583
|
+
// Labels are best-effort; don't fail the whole creation
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return issue;
|
|
587
|
+
},
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
// ---------------------------------------------------------------------------
|
|
591
|
+
// Plugin module export
|
|
592
|
+
// ---------------------------------------------------------------------------
|
|
593
|
+
export const manifest = {
|
|
594
|
+
name: "linear",
|
|
595
|
+
slot: "tracker",
|
|
596
|
+
description: "Tracker plugin: Linear issue tracker",
|
|
597
|
+
version: "0.1.0",
|
|
598
|
+
};
|
|
599
|
+
export function create() {
|
|
600
|
+
const composioKey = process.env["COMPOSIO_API_KEY"];
|
|
601
|
+
if (composioKey) {
|
|
602
|
+
const entityId = process.env["COMPOSIO_ENTITY_ID"] ?? "default";
|
|
603
|
+
return createLinearTracker(createComposioTransport(composioKey, entityId));
|
|
604
|
+
}
|
|
605
|
+
return createLinearTracker(createDirectTransport());
|
|
606
|
+
}
|
|
607
|
+
export default { manifest, create };
|
|
608
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@made-by-moonlight/athene-plugin-tracker-linear",
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "Tracker plugin: Linear",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/slievr/Athene.git",
|
|
21
|
+
"directory": "packages/plugins/tracker-linear"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/slievr/Athene",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/slievr/Athene/issues"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.0.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@made-by-moonlight/athene-core": "0.9.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^25.2.3",
|
|
35
|
+
"typescript": "^5.7.0",
|
|
36
|
+
"vitest": "^3.0.0"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"clean": "rm -rf dist"
|
|
46
|
+
}
|
|
47
|
+
}
|