@dahrk/linear 0.1.0 → 0.2.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.
Files changed (67) hide show
  1. package/README.md +24 -12
  2. package/dist/batch-source.d.ts +63 -0
  3. package/dist/batch-source.d.ts.map +1 -0
  4. package/dist/batch-source.js +149 -0
  5. package/dist/batch-source.js.map +1 -0
  6. package/dist/comments.d.ts +36 -0
  7. package/dist/comments.d.ts.map +1 -0
  8. package/dist/comments.js +104 -0
  9. package/dist/comments.js.map +1 -0
  10. package/dist/documents.d.ts +1 -15
  11. package/dist/documents.d.ts.map +1 -1
  12. package/dist/documents.js +37 -27
  13. package/dist/documents.js.map +1 -1
  14. package/dist/format-action.d.ts +25 -0
  15. package/dist/format-action.d.ts.map +1 -0
  16. package/dist/format-action.js +250 -0
  17. package/dist/format-action.js.map +1 -0
  18. package/dist/index.d.ts +119 -15
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +231 -59
  21. package/dist/index.js.map +1 -1
  22. package/dist/issue-graph.d.ts +37 -0
  23. package/dist/issue-graph.d.ts.map +1 -0
  24. package/dist/issue-graph.js +125 -0
  25. package/dist/issue-graph.js.map +1 -0
  26. package/dist/issues.d.ts +27 -2
  27. package/dist/issues.d.ts.map +1 -1
  28. package/dist/issues.js +33 -10
  29. package/dist/issues.js.map +1 -1
  30. package/dist/labels.d.ts +48 -1
  31. package/dist/labels.d.ts.map +1 -1
  32. package/dist/labels.js +72 -24
  33. package/dist/labels.js.map +1 -1
  34. package/dist/linear-client.d.ts +51 -0
  35. package/dist/linear-client.d.ts.map +1 -1
  36. package/dist/linear-client.js +233 -34
  37. package/dist/linear-client.js.map +1 -1
  38. package/dist/oauth.d.ts +52 -12
  39. package/dist/oauth.d.ts.map +1 -1
  40. package/dist/oauth.js +91 -34
  41. package/dist/oauth.js.map +1 -1
  42. package/dist/recording-client.d.ts +20 -2
  43. package/dist/recording-client.d.ts.map +1 -1
  44. package/dist/recording-client.js +39 -1
  45. package/dist/recording-client.js.map +1 -1
  46. package/dist/responding-client.d.ts +49 -0
  47. package/dist/responding-client.d.ts.map +1 -0
  48. package/dist/responding-client.js +47 -0
  49. package/dist/responding-client.js.map +1 -0
  50. package/dist/teams.d.ts +20 -0
  51. package/dist/teams.d.ts.map +1 -0
  52. package/dist/teams.js +32 -0
  53. package/dist/teams.js.map +1 -0
  54. package/package.json +8 -10
  55. package/src/batch-source.ts +208 -0
  56. package/src/comments.ts +126 -0
  57. package/src/documents.ts +162 -0
  58. package/src/format-action.ts +279 -0
  59. package/src/index.ts +617 -0
  60. package/src/issue-graph.ts +169 -0
  61. package/src/issues.ts +142 -0
  62. package/src/labels.ts +254 -0
  63. package/src/linear-client.ts +448 -0
  64. package/src/oauth.ts +255 -0
  65. package/src/recording-client.ts +141 -0
  66. package/src/responding-client.ts +106 -0
  67. package/src/teams.ts +44 -0
package/dist/oauth.js CHANGED
@@ -5,11 +5,12 @@
5
5
  * the authorization-code flow with `actor=app` and the `app:assignable` / `app:mentionable`
6
6
  * scopes (admin consent). That flow also yields the access + refresh tokens the hub posts with.
7
7
  * Access tokens last ~24h, so the hub refreshes them with the refresh token (see the hub's
8
- * `resolveClient`). Plain `fetch`, no SDK; cyrus is a reference, not a dependency.
8
+ * `resolveClient`). Token grants use plain `fetch`; post-token reads use the typed LinearClient.
9
9
  */
10
+ import { LinearClient } from "@linear/sdk";
10
11
  const AUTHORIZE_URL = "https://linear.app/oauth/authorize";
11
12
  const TOKEN_URL = "https://api.linear.app/oauth/token";
12
- const GRAPHQL_URL = "https://api.linear.app/graphql";
13
+ const REVOKE_URL = "https://api.linear.app/oauth/revoke";
13
14
  /** The agent scopes: read/write plus the two that make the app assignable + mentionable. */
14
15
  export const DEFAULT_AGENT_SCOPES = ["read", "write", "app:assignable", "app:mentionable"];
15
16
  /**
@@ -25,8 +26,8 @@ export function authorizeUrl(params) {
25
26
  u.searchParams.set("scope", (params.scopes ?? DEFAULT_AGENT_SCOPES).join(","));
26
27
  u.searchParams.set("state", params.state);
27
28
  u.searchParams.set("actor", params.actor ?? "app");
28
- // Force the consent screen so re-installing always re-grants (and re-issues a refresh token).
29
- u.searchParams.set("prompt", "consent");
29
+ if ((params.prompt ?? "consent") === "consent")
30
+ u.searchParams.set("prompt", "consent");
30
31
  return u.toString();
31
32
  }
32
33
  async function postToken(body, now) {
@@ -58,24 +59,24 @@ export function exchangeCode(params, now = () => new Date()) {
58
59
  redirect_uri: params.redirectUri,
59
60
  }, now);
60
61
  }
62
+ /**
63
+ * Personal API keys start with `lin_api_` and must be sent as `apiKey` (not Bearer accessToken).
64
+ * OAuth access tokens use `accessToken` so LinearClient adds the Bearer prefix automatically.
65
+ */
66
+ function makeLinearClient(token) {
67
+ return token.startsWith("lin_api_")
68
+ ? new LinearClient({ apiKey: token })
69
+ : new LinearClient({ accessToken: token });
70
+ }
61
71
  /**
62
72
  * Resolve the workspace (organization) id the access token belongs to. Used at install to backfill
63
73
  * a connection's `workspaceIds` from the token, so an operator need not paste the org id by hand and
64
- * intake can match the workspace on the very first webhook. Plain GraphQL fetch, no SDK.
74
+ * intake can match the workspace on the very first webhook.
65
75
  */
66
76
  export async function fetchOrganizationId(accessToken) {
67
- const res = await fetch(GRAPHQL_URL, {
68
- method: "POST",
69
- headers: { "content-type": "application/json", authorization: accessToken },
70
- body: JSON.stringify({ query: "query { organization { id } }" }),
71
- });
72
- const json = (await res.json().catch(() => ({})));
73
- const id = json.data?.organization?.id;
74
- if (!res.ok || !id) {
75
- const detail = json.errors?.[0]?.message || `${res.status}`;
76
- throw new Error(`linear organization query failed: ${detail}`);
77
- }
78
- return id;
77
+ const client = makeLinearClient(accessToken);
78
+ const org = await client.organization;
79
+ return org.id;
79
80
  }
80
81
  /**
81
82
  * Probe a stored access token: query `viewer` (the app/agent user) and `organization` (the bound
@@ -83,31 +84,87 @@ export async function fetchOrganizationId(accessToken) {
83
84
  * binds to. Throws on an auth failure / GraphQL error, which the caller renders as "token invalid".
84
85
  */
85
86
  export async function probeToken(accessToken) {
86
- const res = await fetch(GRAPHQL_URL, {
87
- method: "POST",
88
- headers: { "content-type": "application/json", authorization: accessToken },
89
- body: JSON.stringify({ query: "query { viewer { id name } organization { id name urlKey } }" }),
90
- });
91
- const json = (await res.json().catch(() => ({})));
92
- if (!res.ok || json.errors?.length || !json.data) {
93
- const detail = json.errors?.[0]?.message || `${res.status}`;
94
- throw new Error(`linear probe failed: ${detail}`);
87
+ const client = makeLinearClient(accessToken);
88
+ const [viewer, org] = await Promise.all([client.viewer, client.organization]);
89
+ const probe = {};
90
+ if (viewer?.id) {
91
+ probe.viewer = {
92
+ id: viewer.id,
93
+ ...(viewer.name ? { name: viewer.name } : {}),
94
+ ...(viewer.email ? { email: viewer.email } : {}),
95
+ ...(typeof viewer.admin === "boolean" ? { admin: viewer.admin } : {}),
96
+ };
95
97
  }
96
- const v = json.data.viewer;
97
- const o = json.data.organization;
98
- return {
99
- ...(v?.id ? { viewer: { id: v.id, ...(v.name ? { name: v.name } : {}) } } : {}),
100
- ...(o?.id ? { organization: { id: o.id, ...(o.name ? { name: o.name } : {}), ...(o.urlKey ? { urlKey: o.urlKey } : {}) } } : {}),
101
- };
98
+ if (org?.id) {
99
+ probe.organization = {
100
+ id: org.id,
101
+ ...(org.name ? { name: org.name } : {}),
102
+ ...(org.urlKey ? { urlKey: org.urlKey } : {}),
103
+ };
104
+ }
105
+ return probe;
102
106
  }
103
- /** Rotate the access token using the stored refresh token (the hub calls this near expiry / on 401). */
107
+ /**
108
+ * Rotate the access token using the stored refresh token (the hub calls this near expiry / on 401).
109
+ *
110
+ * Linear rotates refresh tokens **single-use**: the request consumes the one presented and the response
111
+ * carries "a new valid access token and a new refresh token" (oauth-2-0-authentication.md, "Refresh an
112
+ * access token"). So the replacement is mandatory, and a response without one means the old token has
113
+ * been consumed while we learned nothing - the caller MUST NOT carry on with the previous value, which
114
+ * is now dead. Throwing here is what makes that loud instead of silently arming a connection to fail
115
+ * on its next refresh, forever (DHK-1306).
116
+ *
117
+ * Linear gives a 30-minute grace period for exactly this case: the original request can be replayed to
118
+ * retrieve the new refresh token. Recovery is the caller's to attempt; this function's job is to refuse
119
+ * to report success when the rotation is unaccounted for.
120
+ */
104
121
  export function refreshTokens(params, now = () => new Date()) {
105
122
  return postToken({
106
123
  grant_type: "refresh_token",
107
124
  client_id: params.clientId,
108
125
  client_secret: params.clientSecret,
109
126
  refresh_token: params.refreshToken,
110
- }, now);
127
+ }, now).then((t) => {
128
+ if (!t.refreshToken) {
129
+ throw new Error("linear refresh returned no replacement refresh token: the presented token is now consumed. " +
130
+ "Replay the same request within 30 minutes to recover it.");
131
+ }
132
+ return t;
133
+ });
134
+ }
135
+ /**
136
+ * Revoke an access token at Linear, de-authorising the app for the workspace that token belongs to.
137
+ *
138
+ * This is the ONLY app-callable lever Linear gives us over an install: there is no uninstall mutation
139
+ * and nothing in the GraphQL schema that names or targets an install (`revokeOauthToken`,
140
+ * `userAuthorizedApplications`, `applicationWithAuthorization` are all absent). De-authorisation is
141
+ * per organisation - Linear signals it with an `OAuthApp revoked` webhook carrying `organizationId`.
142
+ *
143
+ * Why it matters beyond hygiene: while an install exists, Linear's authorize hop resolves against it
144
+ * and shows "Dahrk already installed - Continue" rather than a consent screen for the workspace the
145
+ * user is actually in. So a user who wanted to move the connection to another workspace got the old
146
+ * one back, every time, with no way out from inside the product. Forgetting a token locally is not
147
+ * enough; Linear has to be told.
148
+ *
149
+ * A `400` counts as revoked. The endpoint returns it for an already-revoked token, and the caller's
150
+ * question is "is this token dead", to which "Linear dropped it earlier" is a yes. A `401` does not:
151
+ * it means we could not authenticate the revocation at all, so the install may well still be live and
152
+ * the caller must say so rather than report a clean disconnect.
153
+ */
154
+ export async function revokeToken(params) {
155
+ const body = { token: params.token };
156
+ // Documented as optional but helpful; must not be combined with the legacy access_token/refresh_token
157
+ // form fields, which we never send.
158
+ if (params.tokenTypeHint)
159
+ body.token_type_hint = params.tokenTypeHint;
160
+ const res = await fetch(REVOKE_URL, {
161
+ method: "POST",
162
+ headers: { "content-type": "application/x-www-form-urlencoded" },
163
+ body: new URLSearchParams(body).toString(),
164
+ });
165
+ if (res.ok || res.status === 400)
166
+ return;
167
+ throw new Error(`linear revoke endpoint failed: ${res.status}`);
111
168
  }
112
169
  /**
113
170
  * Mint an `app` actor token via the `client_credentials` grant: headless (no user, no redirect, no
package/dist/oauth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  * externalUrls) is verified with no Linear credentials. The real `@linear/sdk` client is
7
7
  * the live path (./linear-client.ts).
8
8
  */
9
- import type { Activity, AgentSessionClient, AuthRequest, DocumentInput, ElicitOption, ExternalUrl, PlanItem, PrAttachment, RepoCandidate, SessionState } from "./index.js";
9
+ import type { Activity, AgentSessionClient, AuthRequest, DocumentInput, ElicitOption, ExternalUrl, IssueEngagement, PlanItem, PrAttachment, RepoCandidate, SessionState } from "./index.js";
10
10
  export type RecordedCall = {
11
11
  call: "postActivity";
12
12
  sessionId: string;
@@ -59,10 +59,28 @@ export type RecordedCall = {
59
59
  call: "setState";
60
60
  sessionId: string;
61
61
  state: SessionState;
62
+ } | {
63
+ call: "readIssueEngagement";
64
+ issueIds: string[];
65
+ } | {
66
+ call: "createSessionOnIssue";
67
+ issueId: string;
68
+ } | {
69
+ call: "createSessionOnComment";
70
+ commentId: string;
62
71
  };
63
72
  export interface RecordingClient extends AgentSessionClient {
64
73
  /** Every call made, in order. */
65
74
  readonly calls: RecordedCall[];
66
75
  }
67
- export declare function createRecordingClient(): RecordingClient;
76
+ /** Drive the read-only ground-truth methods so a test can simulate a disengaged issue. */
77
+ export interface RecordingClientOptions {
78
+ /** The app user id `appUserId()` returns (default "app-user"). */
79
+ appUserId?: string;
80
+ /** Per-issue engagement `readIssueEngagement` returns. Any requested id NOT present here defaults
81
+ * to a fully-engaged issue delegated + assigned to `appUserId` (so an unconfigured sweep never
82
+ * false-cancels). Set an id to `null` to simulate a hard-deleted issue (omitted from the result). */
83
+ engagement?: Record<string, IssueEngagement | null>;
84
+ }
85
+ export declare function createRecordingClient(opts?: RecordingClientOptions): RecordingClient;
68
86
  //# sourceMappingURL=recording-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"recording-client.d.ts","sourceRoot":"","sources":["../src/recording-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EACV,QAAQ,EACR,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,YAAY,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,aAAa,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,EAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAEjE,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC;CAChC;AAED,wBAAgB,qBAAqB,IAAI,eAAe,CAkDvD"}
1
+ {"version":3,"file":"recording-client.d.ts","sourceRoot":"","sources":["../src/recording-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EACV,QAAQ,EACR,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,YAAY,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,aAAa,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,EAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC;CAChC;AAED,0FAA0F;AAC1F,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;0GAEsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC,CAAC;CACrD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,sBAA2B,GAAG,eAAe,CAqFxF"}
@@ -1,5 +1,7 @@
1
- export function createRecordingClient() {
1
+ export function createRecordingClient(opts = {}) {
2
2
  const calls = [];
3
+ const appUserId = opts.appUserId ?? "app-user";
4
+ const engagement = opts.engagement ?? {};
3
5
  return {
4
6
  calls,
5
7
  async postActivity(sessionId, activity) {
@@ -25,9 +27,13 @@ export function createRecordingClient() {
25
27
  },
26
28
  async startIssue(sessionId) {
27
29
  calls.push({ call: "startIssue", sessionId });
30
+ // Offline stub: report a successful move so the reporter's no-op surfacing stays quiet.
31
+ return { moved: true, stateName: "In Progress" };
28
32
  },
29
33
  async moveIssueToReview(sessionId) {
30
34
  calls.push({ call: "moveIssueToReview", sessionId });
35
+ // Offline stub: report a successful move so the reporter's no-op surfacing stays quiet.
36
+ return { moved: true, stateName: "In Review" };
31
37
  },
32
38
  async commentOnIssue(sessionId, body) {
33
39
  calls.push({ call: "commentOnIssue", sessionId, body });
@@ -47,6 +53,38 @@ export function createRecordingClient() {
47
53
  async setState(sessionId, state) {
48
54
  calls.push({ call: "setState", sessionId, state });
49
55
  },
56
+ async readIssueEngagement(issueIds) {
57
+ calls.push({ call: "readIssueEngagement", issueIds });
58
+ const out = new Map();
59
+ for (const id of issueIds) {
60
+ if (!id)
61
+ continue;
62
+ if (Object.prototype.hasOwnProperty.call(engagement, id)) {
63
+ const e = engagement[id];
64
+ // null => hard-deleted: leave it out of the result entirely.
65
+ if (e)
66
+ out.set(id, e);
67
+ }
68
+ else {
69
+ // Default: fully engaged (delegated + assigned to the app user), so a sweep against an
70
+ // unconfigured recording client reads every issue as still-engaged.
71
+ out.set(id, { present: true, archived: false, stateType: "started", delegateId: appUserId, assigneeId: appUserId });
72
+ }
73
+ }
74
+ return out;
75
+ },
76
+ async appUserId() {
77
+ return appUserId;
78
+ },
79
+ async createSessionOnIssue(issueId) {
80
+ calls.push({ call: "createSessionOnIssue", issueId });
81
+ // Deterministic synthetic session id so offline runs and tests have a stable reference.
82
+ return `sess-${issueId}`;
83
+ },
84
+ async createSessionOnComment(commentId) {
85
+ calls.push({ call: "createSessionOnComment", commentId });
86
+ return `sess-${commentId}`;
87
+ },
50
88
  };
51
89
  }
52
90
  //# sourceMappingURL=recording-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recording-client.js","sourceRoot":"","sources":["../src/recording-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recording-client.js","sourceRoot":"","sources":["../src/recording-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * An actively-responding, credential-free AgentSessionClient for the `pnpm dev` offline
3
+ * environment. It is a superset of the recording client (./recording-client.ts): it keeps
4
+ * the ordered `calls` log so it is a drop-in wherever the recording client is injected, but
5
+ * it additionally
6
+ *
7
+ * 1. maintains a small, queryable per-session projection of what the hub last pushed
8
+ * (latest state, latest plan, appended activities, set external URLs), so a dev can
9
+ * observe a run without touching Linear, and
10
+ * 2. exposes a pure, pre-declared gate-decision policy (`decide`) a dev CLI reads to know
11
+ * which answer to fire for a stage.
12
+ *
13
+ * The gate policy is a value the dev supplies up front; it NEVER chooses the next stage
14
+ * (that would cross the determinism boundary). Gate answers remain human-drive: the CLI
15
+ * uses `decide` only to pick which `prompted` webhook to send.
16
+ */
17
+ import type { Activity, ElicitOption, ExternalUrl, PlanItem, SessionState } from "./index.js";
18
+ import { type RecordingClient, type RecordingClientOptions } from "./recording-client.js";
19
+ /** A pre-declared gate answer for a stage. Never a control-flow decision (see file header). */
20
+ export type GateDecision = "allow" | "deny";
21
+ /** What the hub last pushed for one session, observable offline without touching Linear. */
22
+ export interface SessionProjection {
23
+ /** The latest session state the hub mirrored, or undefined if none was set yet. */
24
+ state?: SessionState;
25
+ /** The latest plan (agent-plan checklist); replaced wholesale on each `setPlan`. */
26
+ plan: PlanItem[];
27
+ /** Every activity posted to the session, in order. */
28
+ activities: Activity[];
29
+ /** The latest external-URL set; replaced wholesale on each `setExternalUrls`. */
30
+ externalUrls: ExternalUrl[];
31
+ /** The latest elicitation raised on the session, if any. */
32
+ elicitation?: {
33
+ prompt: string;
34
+ options?: ElicitOption[];
35
+ };
36
+ }
37
+ export interface RespondingClientOptions extends RecordingClientOptions {
38
+ /** Per-stage gate answers the dev pre-declares. A stage absent here defaults to "allow". */
39
+ gateDecisions?: Record<string, GateDecision>;
40
+ }
41
+ export interface RespondingClient extends RecordingClient {
42
+ /** The queryable projection of what the hub last pushed for a session, or undefined if the
43
+ * hub has not touched that session. */
44
+ session(sessionId: string): SessionProjection | undefined;
45
+ /** The dev's pre-declared gate answer for a stage (default "allow"). Pure. */
46
+ decide(stageId: string): GateDecision;
47
+ }
48
+ export declare function createRespondingLinearClient(opts?: RespondingClientOptions): RespondingClient;
49
+ //# sourceMappingURL=responding-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responding-client.d.ts","sourceRoot":"","sources":["../src/responding-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,YAAY,EACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAE/B,+FAA+F;AAC/F,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5C,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,oFAAoF;IACpF,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,sDAAsD;IACtD,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,iFAAiF;IACjF,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,4DAA4D;IAC5D,WAAW,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;CAC5D;AAED,MAAM,WAAW,uBAAwB,SAAQ,sBAAsB;IACrE,4FAA4F;IAC5F,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD;4CACwC;IACxC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAAC;IAC1D,8EAA8E;IAC9E,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC;CACvC;AAED,wBAAgB,4BAA4B,CAAC,IAAI,GAAE,uBAA4B,GAAG,gBAAgB,CA8CjG"}
@@ -0,0 +1,47 @@
1
+ import { createRecordingClient, } from "./recording-client.js";
2
+ export function createRespondingLinearClient(opts = {}) {
3
+ // Reuse the recording client wholesale for the ordered call log and the seeded read-side
4
+ // methods (engagement, appUserId, createDocument), then wrap the mutating methods to also
5
+ // update a per-session projection.
6
+ const base = createRecordingClient(opts);
7
+ const gateDecisions = opts.gateDecisions ?? {};
8
+ const projections = new Map();
9
+ const projectionFor = (sessionId) => {
10
+ let p = projections.get(sessionId);
11
+ if (!p) {
12
+ p = { plan: [], activities: [], externalUrls: [] };
13
+ projections.set(sessionId, p);
14
+ }
15
+ return p;
16
+ };
17
+ return {
18
+ ...base,
19
+ async setPlan(sessionId, items) {
20
+ await base.setPlan(sessionId, items);
21
+ projectionFor(sessionId).plan = items;
22
+ },
23
+ async postActivity(sessionId, activity) {
24
+ await base.postActivity(sessionId, activity);
25
+ projectionFor(sessionId).activities.push(activity);
26
+ },
27
+ async raiseElicitation(sessionId, prompt, options) {
28
+ await base.raiseElicitation(sessionId, prompt, options);
29
+ projectionFor(sessionId).elicitation = { prompt, ...(options ? { options } : {}) };
30
+ },
31
+ async setExternalUrls(sessionId, urls) {
32
+ await base.setExternalUrls(sessionId, urls);
33
+ projectionFor(sessionId).externalUrls = urls;
34
+ },
35
+ async setState(sessionId, state) {
36
+ await base.setState(sessionId, state);
37
+ projectionFor(sessionId).state = state;
38
+ },
39
+ session(sessionId) {
40
+ return projections.get(sessionId);
41
+ },
42
+ decide(stageId) {
43
+ return gateDecisions[stageId] ?? "allow";
44
+ },
45
+ };
46
+ }
47
+ //# sourceMappingURL=responding-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responding-client.js","sourceRoot":"","sources":["../src/responding-client.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,qBAAqB,GAGtB,MAAM,uBAAuB,CAAC;AAgC/B,MAAM,UAAU,4BAA4B,CAAC,OAAgC,EAAE;IAC7E,yFAAyF;IACzF,0FAA0F;IAC1F,mCAAmC;IACnC,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,GAAG,EAA6B,CAAC;IAEzD,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAqB,EAAE;QAC7D,IAAI,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;YACnD,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,IAAI;QACP,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK;YAC5B,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACrC,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;QACxC,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ;YACpC,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAC7C,aAAa,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO;YAC/C,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YACxD,aAAa,CAAC,SAAS,CAAC,CAAC,WAAW,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACrF,CAAC;QACD,KAAK,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI;YACnC,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC5C,aAAa,CAAC,SAAS,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC;QAC/C,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK;YAC7B,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACtC,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC;QACzC,CAAC;QACD,OAAO,CAAC,SAAS;YACf,OAAO,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,CAAC,OAAO;YACZ,OAAO,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ /** A workspace team, reduced to just what the picker needs. */
2
+ export interface Team {
3
+ id: string;
4
+ key: string;
5
+ name: string;
6
+ }
7
+ /** The injectable seam: list the workspace's teams. */
8
+ export interface TeamsApi {
9
+ listTeams(): Promise<Team[]>;
10
+ }
11
+ /**
12
+ * List the workspace's teams via the `TeamsApi` seam, normalised to `{id,key,name}` and sorted by
13
+ * key so the picker renders in a stable, deterministic order. A thin deterministic transform - no
14
+ * control flow, no network - so it feeds the portal picker directly.
15
+ */
16
+ export declare function listWorkspaceTeams(api: TeamsApi): Promise<Team[]>;
17
+ /** The live `TeamsApi` backed by a Linear bearer token (workspace-scoped teams). Paginates
18
+ * `client.teams()` exactly as `linearLabelApi` paginates `issueLabels()`. */
19
+ export declare function linearTeamsApi(token: string): TeamsApi;
20
+ //# sourceMappingURL=teams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../src/teams.ts"],"names":[],"mappings":"AAQA,+DAA+D;AAC/D,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAKvE;AAED;8EAC8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAStD"}
package/dist/teams.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Workspace-team listing (DHK-777). A repository routes issues to itself partly by team key
3
+ * (`Repository.routing.teamKeys`); the portal offers the real keys instead of free text by reading
4
+ * the linked workspace's teams. The `TeamsApi` seam keeps this pure and unit-testable: the live
5
+ * adapter (`linearTeamsApi`) wraps `@linear/sdk`, while tests inject a fake - mirroring `LabelApi`.
6
+ */
7
+ import { LinearClient } from "@linear/sdk";
8
+ /**
9
+ * List the workspace's teams via the `TeamsApi` seam, normalised to `{id,key,name}` and sorted by
10
+ * key so the picker renders in a stable, deterministic order. A thin deterministic transform - no
11
+ * control flow, no network - so it feeds the portal picker directly.
12
+ */
13
+ export async function listWorkspaceTeams(api) {
14
+ const teams = await api.listTeams();
15
+ return teams
16
+ .map((t) => ({ id: t.id, key: t.key, name: t.name }))
17
+ .sort((a, b) => a.key.localeCompare(b.key));
18
+ }
19
+ /** The live `TeamsApi` backed by a Linear bearer token (workspace-scoped teams). Paginates
20
+ * `client.teams()` exactly as `linearLabelApi` paginates `issueLabels()`. */
21
+ export function linearTeamsApi(token) {
22
+ const client = new LinearClient({ accessToken: token });
23
+ return {
24
+ async listTeams() {
25
+ const conn = await client.teams();
26
+ while (conn.pageInfo.hasNextPage)
27
+ await conn.fetchNext();
28
+ return conn.nodes.map((t) => ({ id: t.id, key: t.key, name: t.name }));
29
+ },
30
+ };
31
+ }
32
+ //# sourceMappingURL=teams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams.js","sourceRoot":"","sources":["../src/teams.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAc3C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAa;IACpD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC;IACpC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SACpD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC;AAED;8EAC8E;AAC9E,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,OAAO;QACL,KAAK,CAAC,SAAS;YACb,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW;gBAAE,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACzE,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,16 +1,12 @@
1
1
  {
2
2
  "name": "@dahrk/linear",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "The Linear Agent Session API client and webhook verification. The native control surface: activities, agent-plan checklist, elicitation gates, prompted-drive, stop signal, externalUrls.",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/skakel/dahrk.git"
10
- },
11
- "homepage": "https://github.com/skakel/dahrk#readme",
7
+ "homepage": "https://dahrk.ai",
12
8
  "bugs": {
13
- "url": "https://github.com/skakel/dahrk/issues"
9
+ "url": "https://github.com/dahrkai/dahrk-node/issues"
14
10
  },
15
11
  "exports": {
16
12
  ".": {
@@ -19,14 +15,15 @@
19
15
  }
20
16
  },
21
17
  "files": [
22
- "dist"
18
+ "dist",
19
+ "src"
23
20
  ],
24
21
  "publishConfig": {
25
22
  "access": "public"
26
23
  },
27
24
  "dependencies": {
28
25
  "@linear/sdk": "^86.0.0",
29
- "@dahrk/contracts": "0.1.0"
26
+ "@dahrk/contracts": "0.29.0"
30
27
  },
31
28
  "devDependencies": {
32
29
  "tsx": "^4.19.0"
@@ -35,7 +32,8 @@
35
32
  "build": "tsc -p tsconfig.json",
36
33
  "typecheck": "tsc -p tsconfig.json --noEmit",
37
34
  "test": "node --import tsx --test test/*.test.ts",
38
- "spike/live": "tsx spike/run.ts"
35
+ "spike/live": "tsx spike/run.ts",
36
+ "spike/filter": "tsx spike/filter-probe.ts"
39
37
  },
40
38
  "main": "./dist/index.js",
41
39
  "types": "./dist/index.d.ts"