@joe-broadhead/opencode-linear 0.0.5 → 0.0.7

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/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## [0.0.7] - 2026-11-06
6
+
7
+ ### Fixed
8
+
9
+ - `/connect` now clears the "Sign in required" mark on the account after you sign in again.
10
+
11
+ ## [0.0.6] - 2026-11-05
12
+
13
+ ### Changed
14
+
15
+ - The `linear` skill says that `id` is an issue's identifier, such as ENG-123 (there is no `identifier` field), and
16
+ lists the other useful `fields` values, so a `list_issues` call no longer fails on a guessed field.
17
+ - The `linear` skill computes every number an answer states, group totals included, in the first Code Mode call, and
18
+ returns only those numbers and the few issues it names, also for "what am I working on".
19
+ - The `linear` skill finds the team for "this cycle" with `list_teams` when you name none, and calls `list_cycles`
20
+ once without `type` to tell "no cycles" from "no current cycle".
21
+ - The `linear` skill's scripts section says a script uses a session created for it, never one borrowed from history
22
+ or a list, and links the scripting guide as a plain file.
23
+
5
24
  ## [0.0.5] - 2026-11-05
6
25
 
7
26
  ### Added
package/dist/index.js CHANGED
@@ -540,8 +540,10 @@ function watchIntegration(ctx, owned) {
540
540
  }
541
541
  const connection2 = await ctx.integration.connection.active(id);
542
542
  if (connection2?.type !== "credential") return;
543
- const reported = connection2.status?.message === SIGN_IN_AGAIN;
544
- if (server.status.status === "needs_auth" && !connection2.status) {
543
+ const shown = (await ctx.integration.get({ integrationID: id })).data.connections?.find((item) => item.type === "credential" && item.id === connection2.id);
544
+ const status = shown?.type === "credential" ? shown.status : void 0;
545
+ const reported = status?.message === SIGN_IN_AGAIN;
546
+ if (server.status.status === "needs_auth" && !status) {
545
547
  await ctx.integration.connection.status({ integrationID: id, connection: connection2, status: { status: "needs_auth", message: SIGN_IN_AGAIN } });
546
548
  } else if (server.status.status === "connected" && reported) {
547
549
  await ctx.integration.connection.status({ integrationID: id, connection: connection2, status: void 0 });
@@ -791,7 +793,7 @@ function registerSkills(skill, skills) {
791
793
  }
792
794
 
793
795
  // src/version.ts
794
- var VERSION = "0.0.5";
796
+ var VERSION = "0.0.7";
795
797
 
796
798
  // src/status.ts
797
799
  var SIGN_IN = `Run /connect and choose Linear, then press o or Enter to open the link (in a terminal, opencode mcp auth ${SERVER_NAME} opens it automatically).`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joe-broadhead/opencode-linear",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Unofficial OpenCode plugin for Linear: find, read and cite issues, projects and documents through Linear's official MCP server",
5
5
  "keywords": [
6
6
  "opencode",
@@ -21,9 +21,8 @@ the reference for every field; this skill covers the choices they don't explain.
21
21
  list call first. `get_issue` returns no comments: read the discussion with `linear_list_comments` and `issueId`.
22
22
  - **Projects, documents, initiatives, milestones**: the matching `list_*` and `get_*` tools, such as
23
23
  `linear_get_project` with `query` (a name, identifier or slug).
24
- - **Which workspace am I in**: `linear_get_workspace`. Don't look up "me" first: filters take `"me"` directly, and
25
- `linear_get_user` is only for a question about a person's profile.
26
- - **How Linear itself works**: `linear_search_documentation`.
24
+ - **Which workspace am I in**: `linear_get_workspace`. **How Linear works**: `linear_search_documentation`. Don't
25
+ look up "me" first: filters take `"me"` directly; `linear_get_user` is only for a person's profile.
27
26
 
28
27
  ## Filters
29
28
 
@@ -34,29 +33,40 @@ the reference for every field; this skill covers the choices they don't explain.
34
33
  `linear_list_issue_statuses` with `team` gives a team's state names.
35
34
  - Dates (`createdAt`, `updatedAt`, `completedAt`) mean "after" and take an ISO-8601 date or a duration such as
36
35
  `-P7D`. `completedAt` also drops issues that are not completed.
37
- - "This cycle": `linear_list_cycles` with `teamId` (a team name, key or ID) and `type: "current"`. An empty answer
38
- means the team has no current cycle: say so, rather than guessing from dates.
36
+ - "This cycle": `linear_list_cycles` with `teamId` (a team name, key or ID); with no team named, `linear_list_teams`
37
+ gives them, rather than paging issues. Call it once without `type`: `[]` means the team has no cycles, so none is
38
+ current. Only if it has cycles, `type: "current"` gives the running one. Say so plainly rather than guessing from
39
+ dates, and label a fallback, such as the user's started issues, as that, not as "this cycle".
39
40
 
40
41
  ## Result size and pages
41
42
 
42
- - By default each listed issue carries its whole description, about 1.6 KB, so 250 rows can overflow the result.
43
- Pass `fields` with only what the answer needs, such as `["id", "title", "status", "statusType", "url"]`.
44
- - `limit` is 50 by default and at most 250 (`list_projects`: at most 50).
45
- - A page ends with `hasNextPage` and `cursor`. While `hasNextPage` is true, call again with the same filters and that
46
- `cursor`, unchanged. If you stop early, say the answer covers only what you read.
47
- - For a count or breakdown, compute it inside one Code Mode call: page, count there, and return only the numbers
48
- (plus the few rows you will name). Don't return the rows to count them yourself: a big result is cut off, and
49
- counting rows by eye is error-prone. For example, the user's issues by state type:
43
+ - By default each listed issue carries its whole description, about 1.6 KB: pass `fields` with only what the answer
44
+ needs. `id` is the identifier, such as `"ENG-123"` (`uuid` is the UUID); there is no `identifier` field. Others:
45
+ `title`, `url`, `status` (the state's name), `statusType`, `priority` (`{ value, name }`), `team`, `project` and
46
+ `assignee` (names), `teamId` (a UUID), `labels`, `parentId` (an identifier), `cycleId`, `createdAt`, `updatedAt`,
47
+ `completedAt`, `dueDate`. A field outside the schema's list fails the call.
48
+ - `limit` is 50 by default and at most 250 (`list_projects`: 50). A page ends with `hasNextPage` and `cursor`: while
49
+ `hasNextPage` is true, call again with the same filters and that `cursor`. If you stop early, say so.
50
+ - For a count, a breakdown or "what am I working on", decide the grouping first, and in the first Code Mode call
51
+ compute every number you will state (each count, every group's total, the overall total) and pick the few rows you
52
+ will name. Return only those, never all the rows: even with `fields`, a hundred rows are tens of KB, and sums done
53
+ by eye go wrong. If you name only some rows, say how many you left out. For example, the user's issues by state
54
+ type, with the 5 most recently updated of each:
50
55
 
51
56
  ```js
52
- const counts = {}
53
- let cursor
57
+ const groups = {}
58
+ let total = 0, cursor
54
59
  do {
55
- const page = await tools.linear.list_issues({ assignee: "me", fields: ["id", "statusType"], limit: 250, ...(cursor ? { cursor } : {}) })
56
- for (const issue of page.issues) counts[issue.statusType] = (counts[issue.statusType] ?? 0) + 1
60
+ const page = await tools.linear.list_issues({ assignee: "me", fields: ["id", "title", "statusType", "url"], limit: 250, ...(cursor ? { cursor } : {}) })
61
+ for (const { id, title, statusType, url } of page.issues) {
62
+ const group = (groups[statusType] ??= { count: 0, newest: [] })
63
+ group.count++
64
+ if (group.newest.length < 5) group.newest.push({ id, title, url })
65
+ }
66
+ total += page.issues.length
57
67
  cursor = page.hasNextPage ? page.cursor : undefined
58
68
  } while (cursor)
59
- return counts
69
+ return { total, groups }
60
70
  ```
61
71
 
62
72
  ## Changes
@@ -78,9 +88,11 @@ Name each item by its identifier (or a project's name) and give the `url` Linear
78
88
 
79
89
  ## Scripts
80
90
 
81
- A cron job or shell script can run the same reads with no model through the tools RPC `linear.workspace.tools`, as a
82
- session and its agent; writes are never available there. See
83
- https://github.com/joe-broadhead/opencode-linear/blob/HEAD/docs/scripting.md.
91
+ A cron job or shell script can run the same reads with no model through the tools RPC `linear.workspace.tools`;
92
+ writes are never available there. It runs as a session's agent, under its rules, so a script, or a test of one, uses
93
+ a session created for it (`opencode api post /api/session -d '{"title":"…","agent":"build"}'`, keep `data.id`).
94
+ Never borrow an existing session found through history or a list. Details:
95
+ https://raw.githubusercontent.com/joe-broadhead/opencode-linear/HEAD/docs/scripting.md
84
96
 
85
97
  ## When Linear is not available
86
98