@mastra/factory 0.18.0 → 0.19.0-alpha.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/README.md +13 -1
- package/dist/boards/registry.d.ts.map +1 -1
- package/dist/boards/registry.js +0 -2
- package/dist/boards/registry.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +12 -2
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/default-rules.d.ts +10 -2
- package/dist/integrations/github/default-rules.d.ts.map +1 -1
- package/dist/integrations/github/default-rules.js +28 -4
- package/dist/integrations/github/default-rules.js.map +1 -1
- package/dist/integrations/github/integration.js +1 -1
- package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/reconcile-worker.js +1 -2
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +2 -15
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.d.ts +5 -0
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +17 -8
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/stale-reviews.d.ts +22 -0
- package/dist/integrations/github/stale-reviews.d.ts.map +1 -0
- package/dist/integrations/github/stale-reviews.js +70 -0
- package/dist/integrations/github/stale-reviews.js.map +1 -0
- package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
- package/dist/integrations/gitlab/version-control.js +4 -5
- package/dist/integrations/gitlab/version-control.js.map +1 -1
- package/dist/integrations/gitlab/webhook.d.ts.map +1 -1
- package/dist/integrations/gitlab/webhook.js +2 -2
- package/dist/integrations/gitlab/webhook.js.map +1 -1
- package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/issue-reconcile-worker.js +1 -2
- package/dist/integrations/issue-reconcile-worker.js.map +1 -1
- package/dist/integrations/jira/integration.d.ts.map +1 -1
- package/dist/integrations/jira/integration.js +7 -1
- package/dist/integrations/jira/integration.js.map +1 -1
- package/dist/integrations/linear/integration.d.ts.map +1 -1
- package/dist/integrations/linear/integration.js +10 -30
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +1 -2
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.js +1 -1
- package/dist/integrations/platform/gitlab/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/gitlab/event-worker.js +1 -2
- package/dist/integrations/platform/gitlab/event-worker.js.map +1 -1
- package/dist/integrations/platform/jira/integration.d.ts.map +1 -1
- package/dist/integrations/platform/jira/integration.js +7 -1
- package/dist/integrations/platform/jira/integration.js.map +1 -1
- package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/linear/event-worker.js +1 -2
- package/dist/integrations/platform/linear/event-worker.js.map +1 -1
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
- package/dist/integrations/platform/linear/integration.js +9 -9
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/integrations/slack/slack.d.ts.map +1 -1
- package/dist/integrations/slack/slack.js +1 -2
- package/dist/integrations/slack/slack.js.map +1 -1
- package/dist/review-verdict.d.ts +6 -0
- package/dist/review-verdict.d.ts.map +1 -0
- package/dist/review-verdict.js +14 -0
- package/dist/review-verdict.js.map +1 -0
- package/dist/routes/attention-providers.d.ts +6 -7
- package/dist/routes/attention-providers.d.ts.map +1 -1
- package/dist/routes/attention-providers.js +12 -5
- package/dist/routes/attention-providers.js.map +1 -1
- package/dist/routes/attention.d.ts +2 -0
- package/dist/routes/attention.d.ts.map +1 -1
- package/dist/routes/attention.js +9 -3
- package/dist/routes/attention.js.map +1 -1
- package/dist/routes/oauth.d.ts.map +1 -1
- package/dist/routes/oauth.js +3 -3
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/source-control-sessions.d.ts.map +1 -1
- package/dist/routes/source-control-sessions.js +1 -2
- package/dist/routes/source-control-sessions.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +10 -5
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/decision-applicability.d.ts +26 -0
- package/dist/rules/decision-applicability.d.ts.map +1 -0
- package/dist/rules/decision-applicability.js +47 -0
- package/dist/rules/decision-applicability.js.map +1 -0
- package/dist/rules/dispatcher.d.ts +4 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +33 -24
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +5 -5
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +1 -2
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +18 -1
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.d.ts.map +1 -1
- package/dist/rules/validation.js +20 -0
- package/dist/rules/validation.js.map +1 -1
- package/dist/secret-encryption.js +2 -2
- package/dist/secret-encryption.js.map +1 -1
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +1 -2
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/source-control-tools.d.ts +9 -0
- package/dist/session/source-control-tools.d.ts.map +1 -1
- package/dist/session/source-control-tools.js +51 -2
- package/dist/session/source-control-tools.js.map +1 -1
- package/dist/state-signing.js +3 -3
- package/dist/state-signing.js.map +1 -1
- package/dist/storage/domains/audit/base.d.ts.map +1 -1
- package/dist/storage/domains/audit/base.js +2 -3
- package/dist/storage/domains/audit/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +5 -6
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +3 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +15 -2
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/supervisor/write-tools.d.ts +2 -0
- package/dist/supervisor/write-tools.d.ts.map +1 -1
- package/dist/supervisor/write-tools.js +3 -0
- package/dist/supervisor/write-tools.js.map +1 -1
- package/factory-skills/configure-factory-rules/SKILL.md +1 -1
- package/factory-skills/factory-gitlab-rereview/SKILL.md +1 -1
- package/factory-skills/factory-gitlab-review/SKILL.md +1 -1
- package/factory-skills/factory-rereview/SKILL.md +12 -3
- package/factory-skills/factory-review/SKILL.md +12 -3
- package/package.json +9 -9
|
@@ -7,7 +7,6 @@ import { buildLinearRoutes } from "../../linear/routes.js";
|
|
|
7
7
|
import { buildLinearAgentTools } from "../../linear/agent-tools.js";
|
|
8
8
|
import { PlatformLinearEventWorker } from "./event-worker.js";
|
|
9
9
|
import { registerApiRoute } from "@mastra/core/server";
|
|
10
|
-
import { createHash } from "crypto";
|
|
11
10
|
//#region src/integrations/platform/linear/integration.ts
|
|
12
11
|
const API_PREFIX = "/v1/server/linear";
|
|
13
12
|
const PAGE_SIZE = 30;
|
|
@@ -493,7 +492,7 @@ var PlatformLinearIntegration = class {
|
|
|
493
492
|
});
|
|
494
493
|
}
|
|
495
494
|
}
|
|
496
|
-
const cursors = decodeCursor(cursor, sourceIds, attributionSourceIds);
|
|
495
|
+
const cursors = await decodeCursor(cursor, sourceIds, attributionSourceIds);
|
|
497
496
|
const normalizedLabels = normalizeLabels(labels);
|
|
498
497
|
const nextState = {};
|
|
499
498
|
let hasNextPage = false;
|
|
@@ -516,7 +515,7 @@ var PlatformLinearIntegration = class {
|
|
|
516
515
|
workspace
|
|
517
516
|
}));
|
|
518
517
|
}))).flat(), sourceIds),
|
|
519
|
-
nextCursor: hasNextPage ? encodeCursor(nextState, sourceIds, attributionSourceIds) : null
|
|
518
|
+
nextCursor: hasNextPage ? await encodeCursor(nextState, sourceIds, attributionSourceIds) : null
|
|
520
519
|
};
|
|
521
520
|
}
|
|
522
521
|
async #findIssue(sourceId, issueId, sourceIds, routedSourceIds) {
|
|
@@ -704,32 +703,33 @@ function normalizeLabels(labels) {
|
|
|
704
703
|
function canonicalSourceIds(sourceIds) {
|
|
705
704
|
return [...new Set(sourceIds)].sort();
|
|
706
705
|
}
|
|
707
|
-
function linearSourceSetFingerprint(sourceIds, attributionSourceIds) {
|
|
706
|
+
async function linearSourceSetFingerprint(sourceIds, attributionSourceIds) {
|
|
708
707
|
const scope = {
|
|
709
708
|
sourceIds: canonicalSourceIds(sourceIds),
|
|
710
709
|
attributionSourceIds: canonicalSourceIds(attributionSourceIds)
|
|
711
710
|
};
|
|
712
|
-
|
|
711
|
+
const bytes = new TextEncoder().encode(JSON.stringify(scope));
|
|
712
|
+
return Buffer.from(await globalThis.crypto.subtle.digest("SHA-256", bytes)).toString("base64url");
|
|
713
713
|
}
|
|
714
714
|
function invalidLinearCursor() {
|
|
715
715
|
return Object.assign(/* @__PURE__ */ new Error("Linear cursor is invalid or stale."), { code: "invalid_cursor" });
|
|
716
716
|
}
|
|
717
|
-
function decodeCursor(cursor, sourceIds, attributionSourceIds) {
|
|
717
|
+
async function decodeCursor(cursor, sourceIds, attributionSourceIds) {
|
|
718
718
|
if (!cursor) return {};
|
|
719
719
|
try {
|
|
720
720
|
const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
721
721
|
const canonical = canonicalSourceIds(sourceIds);
|
|
722
|
-
if (parsed.v !== 1 || parsed.sourceSet !== linearSourceSetFingerprint(sourceIds, attributionSourceIds) || !Array.isArray(parsed.cursors) || parsed.cursors.length !== canonical.length || !parsed.cursors.every((value) => value === null || typeof value === "string")) throw invalidLinearCursor();
|
|
722
|
+
if (parsed.v !== 1 || parsed.sourceSet !== await linearSourceSetFingerprint(sourceIds, attributionSourceIds) || !Array.isArray(parsed.cursors) || parsed.cursors.length !== canonical.length || !parsed.cursors.every((value) => value === null || typeof value === "string")) throw invalidLinearCursor();
|
|
723
723
|
return Object.fromEntries(canonical.map((sourceId, index) => [sourceId, parsed.cursors[index]]));
|
|
724
724
|
} catch {
|
|
725
725
|
throw invalidLinearCursor();
|
|
726
726
|
}
|
|
727
727
|
}
|
|
728
|
-
function encodeCursor(state, sourceIds, attributionSourceIds) {
|
|
728
|
+
async function encodeCursor(state, sourceIds, attributionSourceIds) {
|
|
729
729
|
const canonical = canonicalSourceIds(sourceIds);
|
|
730
730
|
const cursor = {
|
|
731
731
|
v: 1,
|
|
732
|
-
sourceSet: linearSourceSetFingerprint(sourceIds, attributionSourceIds),
|
|
732
|
+
sourceSet: await linearSourceSetFingerprint(sourceIds, attributionSourceIds),
|
|
733
733
|
cursors: canonical.map((sourceId) => state[sourceId] ?? null)
|
|
734
734
|
};
|
|
735
735
|
return Buffer.from(JSON.stringify(cursor)).toString("base64url");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","names":["#client","#endpointHost","#workflowStatesByTeam","#resolveIntakeDispatch","#listProjectSources","#listTeamSources","#listIssues","#findIssue","#loadComments","#resolveWorkspaceForIssue","#listWorkflowStates","#rules","#projects","#auth","#listWorkspaces","#connectRoute","#candidateWorkspaceIds"],"sources":["../../../../src/integrations/platform/linear/integration.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\nimport type { Context } from 'hono';\n\nimport type { IntegrationConnection } from '../../../capabilities/connection.js';\nimport type { Intake, IntakeIssue, IntakeIssueDetail, UpdateIntakeIssueInput } from '../../../capabilities/intake.js';\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../../../storage/domains/projects/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';\nimport { buildLinearAgentTools } from '../../linear/agent-tools.js';\nimport type { LinearEventRules, LinearRuleOverrides } from '../../linear/default-rules.js';\nimport { resolveLinearRules } from '../../linear/default-rules.js';\nimport type {\n LinearConnectionCheck,\n LinearIntegration,\n LinearIssueDetail as LinearRouteIssueDetail,\n} from '../../linear/integration.js';\nimport { attachLinearIssueReconciler } from '../../linear/issue-reconciler.js';\nimport {\n linearIssueReconciliationEnabled,\n linearIssueReconciliationInterval,\n} from '../../linear/reconciliation-config.js';\nimport { buildLinearRoutes } from '../../linear/routes.js';\nimport { attachLinearRules } from '../../linear/rules.js';\nimport type { LinearConnectionData, LinearConnectionRow, LinearStorageHandle } from '../../linear/storage.js';\nimport {\n logPlatformInfo,\n logPlatformWarn,\n PlatformApiClient,\n PlatformApiError,\n platformApiClientConfigFromEnv,\n} from '../api-client.js';\nimport { PlatformLinearEventWorker } from './event-worker.js';\nimport type { PlatformLinearEventStorage } from './event-worker.js';\n\ntype PageInfo = { hasNextPage: boolean; endCursor: string | null };\ntype LinearUser = {\n id: string;\n name: string;\n displayName: string;\n email: string | null;\n avatarUrl: string | null;\n};\ntype LinearIssue = {\n id: string;\n identifier: string;\n number: number;\n title: string;\n description: string | null;\n url: string;\n priority: number;\n priorityLabel: string;\n labels: Array<{ id: string; name: string }>;\n state: { id: string; name: string; type: string };\n team: { id: string; key: string; name: string };\n project: { id: string } | null;\n assignee: LinearUser | null;\n creator: LinearUser | null;\n createdAt: string;\n updatedAt: string;\n archivedAt: string | null;\n};\ntype LinearComment = {\n id: string;\n body: string;\n url: string;\n issue: { id: string; identifier: string };\n user: LinearUser | null;\n parent: { id: string } | null;\n createdAt: string;\n updatedAt: string;\n};\ntype LinearWorkspace = {\n linearWorkspaceId: string;\n linearWorkspaceName: string;\n urlKey: string | null;\n connected: boolean;\n};\ntype LinearProject = {\n id: string;\n name: string;\n state: string;\n teams: Array<{ id: string; key: string; name: string }>;\n};\ntype LinearTeam = { id: string; key: string; name: string };\ntype ProjectSource = { workspace: LinearWorkspace; project: LinearProject };\ntype TeamSource = { workspace: LinearWorkspace; team: LinearTeam };\ntype LinearWorkflowState = {\n id: string;\n name: string;\n type: string;\n position: number;\n teamId: string;\n};\n\nconst API_PREFIX = '/v1/server/linear';\nconst PAGE_SIZE = 30;\nconst MAX_REFERENCE_PAGES = 20;\nconst MAX_COMMENT_PAGES = 20;\nconst PLATFORM_MANAGED_CONNECTION_TOKEN = 'platform-managed';\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction routeBaseUrl(ctx: IntegrationContext, requestUrl: string): string {\n return (ctx.baseUrl || new URL(requestUrl).origin).replace(/\\/+$/, '');\n}\n\nexport class PlatformLinearIntegration implements FactoryIntegration {\n readonly id = 'linear';\n readonly #client: PlatformApiClient;\n readonly #endpointHost: string;\n #projects: FactoryProjectsStorage | undefined;\n #auth: RouteAuth | undefined;\n /**\n * Per-instance workflow-state cache keyed by `${workspaceId}:${teamId}`. Scoped to the process\n * lifetime; not shared across requests intentionally to keep failure modes simple (stale states\n * clear on process restart). Populated lazily on first `updateIssue` per team.\n */\n readonly #workflowStatesByTeam = new Map<string, LinearWorkflowState[]>();\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: async () => {\n const [projectSources, teamSources] = await Promise.all([this.#listProjectSources(), this.#listTeamSources()]);\n const projects = projectSources.map(({ workspace, project }) => ({\n id: encodeSourceId(workspace.linearWorkspaceId, project.id),\n name: project.name,\n type: 'project' as const,\n metadata: {\n workspaceId: workspace.linearWorkspaceId,\n workspaceName: workspace.linearWorkspaceName,\n workspaceUrlKey: workspace.urlKey,\n state: project.state,\n teams: project.teams,\n },\n }));\n const teams = teamSources.map(({ workspace, team }) => ({\n id: encodeTeamSourceId(workspace.linearWorkspaceId, team.id),\n name: team.name,\n type: 'team' as const,\n metadata: {\n workspaceId: workspace.linearWorkspaceId,\n workspaceName: workspace.linearWorkspaceName,\n workspaceUrlKey: workspace.urlKey,\n teamKey: team.key,\n },\n }));\n return [...projects, ...teams];\n },\n listItems: async ({ sourceIds, attributionSourceIds, cursor }) => {\n const result = await this.#listIssues(sourceIds, cursor, undefined, attributionSourceIds);\n return {\n items: result.issues.map(({ issue, sourceId, workspace }) => ({\n source: { type: 'issue', externalId: issue.id, url: issue.url },\n sourceId,\n title: issue.title,\n status: issue.state.name,\n labels: issue.labels.map(label => label.name),\n assignee: issue.assignee?.displayName ?? issue.assignee?.name ?? null,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: {\n identifier: issue.identifier,\n workspaceId: workspace.linearWorkspaceId,\n workspaceName: workspace.linearWorkspaceName,\n projectId: issue.project?.id ?? null,\n team: issue.team.key,\n priority: issue.priorityLabel,\n },\n })),\n nextCursor: result.nextCursor,\n };\n },\n listIssues: async ({ connection, sourceIds, attributionSourceIds, labels, cursor }) => {\n requireLinearConnection(connection);\n const result = await this.#listIssues(sourceIds, cursor, labels, attributionSourceIds);\n return {\n issues: result.issues.map(({ issue, sourceId }) => ({\n ...parseIssue(issue),\n sourceId,\n })),\n nextCursor: result.nextCursor,\n };\n },\n getIssue: async ({ connection, sourceId, issueId }) => {\n requireLinearConnection(connection);\n const located = await this.#findIssue(sourceId, issueId);\n if (!located) return null;\n const comments = await this.#loadComments(located.workspaceId, issueId, located.issue.comments);\n return parseIssueDetail(located.issue, comments);\n },\n createComment: async ({ connection, sourceId, issueId, body }) => {\n requireLinearConnection(connection);\n const workspaceId = await this.#resolveWorkspaceForIssue(sourceId, issueId);\n if (!workspaceId) return null;\n try {\n const comment = await this.#client.request<LinearComment>(\n 'POST',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}/comments`,\n { body },\n );\n return { id: comment.id, url: comment.url };\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n },\n updateIssue: async (input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> => {\n requireLinearConnection(input.connection);\n const located = await this.#findIssue(input.sourceId, input.issueId);\n if (!located) return null;\n const { workspaceId, issue } = located;\n\n const target = input.state;\n // Idempotency: skip the write entirely if the issue is already at the target state.\n if (target.kind === 'byType' && issue.state.type === target.stateType) {\n return parseIssue(issue);\n }\n if (target.kind === 'byName' && issue.state.name.toLowerCase() === target.name.toLowerCase()) {\n return parseIssue(issue);\n }\n\n let states: LinearWorkflowState[];\n try {\n states = await this.#listWorkflowStates(workspaceId, issue.team.id);\n } catch (error) {\n if (isNotFound(error)) {\n // Platform companion endpoint not deployed yet — degrade to policy skip so PR 1\n // is standalone-mergeable ahead of the platform-side workflow-states route landing.\n logPlatformWarn('Platform Linear: workflow-states endpoint not available; skipping updateIssue.', {\n workspaceId,\n teamId: issue.team.id,\n });\n return null;\n }\n throw error;\n }\n let matched: LinearWorkflowState | undefined;\n if (target.kind === 'byType') {\n matched = states\n .slice()\n .sort((a, b) => a.position - b.position)\n .find(s => s.type === target.stateType);\n } else {\n const wanted = target.name.toLowerCase();\n matched = states.find(s => s.name.toLowerCase() === wanted);\n }\n if (!matched) {\n logPlatformWarn('Platform Linear: no workflow state matched target; skipping updateIssue.', {\n workspaceId,\n teamId: issue.team.id,\n target,\n });\n return null;\n }\n\n try {\n await this.#client.request<LinearIssue>(\n 'PATCH',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(input.issueId)}`,\n { stateId: matched.id },\n );\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n\n const refreshed = await this.#findIssue(input.sourceId, input.issueId);\n return refreshed ? parseIssue(refreshed.issue) : null;\n },\n };\n\n readonly #rules: LinearEventRules;\n\n get rules(): LinearEventRules {\n return this.#rules;\n }\n\n constructor({ rules }: { rules?: LinearRuleOverrides } = {}) {\n this.#rules = resolveLinearRules(rules);\n const config = platformApiClientConfigFromEnv();\n this.#client = new PlatformApiClient(config);\n this.#endpointHost = new URL(config.baseUrl).host;\n }\n\n get storage(): LinearStorageHandle {\n const now = new Date();\n return {\n integrationId: this.id,\n connections: {\n get: async (orgId: string) => ({\n id: `platform-linear:${orgId}`,\n orgId,\n userId: null,\n data: {\n accessToken: PLATFORM_MANAGED_CONNECTION_TOKEN,\n refreshToken: null,\n expiresAtMs: null,\n scope: 'read,comments:create',\n workspaceName: null,\n workspaceUrlKey: null,\n } satisfies LinearConnectionData,\n metadata: {},\n createdAt: now,\n updatedAt: now,\n }),\n },\n } as unknown as LinearStorageHandle;\n }\n\n get projects(): FactoryProjectsStorage {\n if (!this.#projects) throw new Error('PlatformLinearIntegration projects storage has not been initialized.');\n return this.#projects;\n }\n\n initialize({ projects, auth }: { projects: FactoryProjectsStorage; auth?: RouteAuth }): void {\n this.#projects = projects;\n this.#auth = auth;\n logPlatformInfo('Platform Linear integration initialized', { endpointHost: this.#endpointHost });\n }\n\n get authEnabled(): boolean {\n return this.#auth?.enabled() ?? false;\n }\n\n async resolveOrgId(resourceId: string): Promise<string | null> {\n try {\n const project = await this.projects.getById({ id: resourceId });\n return project?.orgId ?? null;\n } catch {\n return null;\n }\n }\n\n async loadConnection(orgId: string): Promise<LinearConnectionRow | null> {\n const workspace = (await this.#listWorkspaces())[0];\n if (!workspace) return null;\n const now = new Date();\n return {\n id: `platform-linear:${orgId}`,\n orgId,\n userId: null,\n accessToken: PLATFORM_MANAGED_CONNECTION_TOKEN,\n scope: 'read,comments:create',\n refreshToken: null,\n expiresAt: null,\n workspaceName: workspace.linearWorkspaceName,\n workspaceUrlKey: workspace.urlKey,\n createdAt: now,\n updatedAt: now,\n };\n }\n\n async getFreshAccessToken(_connection: LinearConnectionRow): Promise<string> {\n return PLATFORM_MANAGED_CONNECTION_TOKEN;\n }\n\n /**\n * Background-dispatch context: platform-managed connection token when the\n * org has a connected workspace. Linear work items store the issue UUID\n * directly as `externalId`.\n */\n async #resolveIntakeDispatch({\n orgId,\n externalSource,\n }: {\n orgId: string;\n externalSource: { type: string; externalId: string };\n }): Promise<{ connection: IntegrationConnection; issueId: string } | null> {\n if (externalSource.type !== 'issue') return null;\n const connection = await this.loadConnection(orgId);\n if (!connection) return null;\n return {\n connection: { type: 'oauth', accessToken: PLATFORM_MANAGED_CONNECTION_TOKEN },\n issueId: externalSource.externalId,\n };\n }\n\n canPostComments(connection: LinearConnectionRow): boolean {\n const scopes = (connection.scope ?? '').split(/[\\s,]+/).filter(Boolean);\n return scopes.some(scope => scope === 'comments:create' || scope === 'write' || scope === 'admin');\n }\n\n async checkConnection(orgId: string): Promise<LinearConnectionCheck> {\n const connection = await this.loadConnection(orgId);\n return {\n connected: connection !== null,\n canComment: connection !== null && this.canPostComments(connection),\n checkedAt: Date.now(),\n };\n }\n\n workers(ctx: IntegrationContext): MastraWorker[] {\n const pollingEnabled = process.env.MASTRACODE_PLATFORM_LINEAR_POLLING_ENABLED?.trim().toLowerCase() !== 'false';\n const reconcileEnabled = linearIssueReconciliationEnabled();\n if (!pollingEnabled && !reconcileEnabled) return [];\n\n const ingest = attachLinearRules(this, ctx);\n const reconcile = reconcileEnabled ? attachLinearIssueReconciler(this, ctx) : undefined;\n const workItems = ctx.runtime?.workItems;\n if (!workItems) return [];\n if (!ingest && !reconcile) return [];\n\n const pollIntervalMs = optionalPositiveIntegerEnv('MASTRACODE_PLATFORM_LINEAR_POLLING_INTERVAL_MS');\n const reconcileIntervalMs = linearIssueReconciliationInterval();\n\n return [\n new PlatformLinearEventWorker({\n client: this.#client,\n linear: { listWorkspaces: () => this.listWorkspaces() },\n storage: ctx.storage.generic as unknown as PlatformLinearEventStorage,\n projects: ctx.storage.projects,\n workItems,\n ...(ingest ? { ingestFactoryIssue: ingest } : {}),\n ...(reconcile ? { reconcileFactoryState: reconcile } : {}),\n pollEventsEnabled: pollingEnabled,\n ...(pollIntervalMs !== undefined ? { intervalMs: pollIntervalMs } : {}),\n ...(reconcileIntervalMs !== undefined ? { reconcileIntervalMs } : {}),\n }),\n ];\n }\n\n routes(ctx: IntegrationContext): ApiRoute[] {\n return [\n this.#connectRoute(ctx),\n ...buildLinearRoutes({\n auth: ctx.auth,\n linear: this as unknown as LinearIntegration,\n stateSigner: ctx.stateSigner,\n baseUrl: ctx.baseUrl,\n intake: ctx.storage.intake,\n projects: ctx.storage.projects,\n ingestFactoryIssues: attachLinearRules(this, ctx),\n workItems: ctx.runtime?.workItems,\n boards: ctx.runtime?.boards,\n }).filter(route => !route.path.startsWith('/auth/linear/')),\n ];\n }\n\n #connectRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/auth/linear/connect', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const returnTo = c.req.query('return_to') || '/';\n const originator = routeBaseUrl(ctx, c.req.url);\n logPlatformInfo('Starting Platform Linear connect flow', {\n orgId: tenant.orgId,\n returnTo,\n originator,\n });\n const query = new URLSearchParams({ return_to: returnTo, originator });\n const location = await this.#client.requestRedirect('GET', `${API_PREFIX}/authorize?${query}`);\n return c.redirect(location);\n },\n });\n }\n\n async agentTools({ requestContext }: { requestContext: RequestContext }): Promise<IntegrationTools> {\n return buildLinearAgentTools({ requestContext, linear: this as unknown as LinearIntegration });\n }\n\n diagnostics(): Record<string, unknown> {\n return { mode: 'platform', endpointHost: this.#endpointHost };\n }\n\n async listProjects(): Promise<Array<LinearProject & { workspaceId: string }>> {\n return (await this.#listProjectSources()).map(({ workspace, project }) => ({\n ...project,\n id: encodeSourceId(workspace.linearWorkspaceId, project.id),\n workspaceId: workspace.linearWorkspaceId,\n }));\n }\n\n async listTeams(_accessToken: string): Promise<Array<LinearTeam & { workspaceId: string; sourceId: string }>> {\n return (await this.#listTeamSources()).map(({ workspace, team }) => ({\n ...team,\n workspaceId: workspace.linearWorkspaceId,\n sourceId: encodeTeamSourceId(workspace.linearWorkspaceId, team.id),\n }));\n }\n\n async fetchIssueDetail(\n _accessToken: string,\n idOrIdentifier: string,\n sourceIds?: string[],\n routedSourceIds?: string[],\n ): Promise<LinearRouteIssueDetail | null> {\n const located = await this.#findIssue(undefined, idOrIdentifier, sourceIds, routedSourceIds);\n if (!located) return null;\n const comments = await this.#loadComments(located.workspaceId, located.issue.id, located.issue.comments);\n const issue = located.issue;\n return {\n id: issue.id,\n projectId: issue.project?.id ?? null,\n workspaceId: located.workspaceId,\n teamId: issue.team.id,\n identifier: issue.identifier,\n title: issue.title,\n description: issue.description?.trim() ? issue.description : null,\n url: issue.url,\n state: issue.state.name,\n stateType: issue.state.type,\n priorityLabel: issue.priorityLabel,\n assignee: issue.assignee?.displayName ?? issue.assignee?.name ?? null,\n creator: issue.creator?.displayName ?? issue.creator?.name ?? null,\n team: issue.team.key,\n labels: issue.labels.map(label => label.name),\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n comments: comments.map(comment => ({\n author: comment.user?.displayName ?? comment.user?.name ?? null,\n body: comment.body,\n createdAt: comment.createdAt,\n })),\n };\n }\n\n sourceMatchesIssue(\n sourceId: string,\n issue: Pick<LinearRouteIssueDetail, 'workspaceId' | 'projectId' | 'teamId'>,\n ): boolean {\n const source = parseSourceId(sourceId);\n if (issue.workspaceId !== source.workspaceId) return false;\n return source.kind === 'team' ? issue.teamId === source.teamId : issue.projectId === source.projectId;\n }\n\n async #listProjectSources(workspaceIds?: ReadonlySet<string>): Promise<ProjectSource[]> {\n const workspaces = await this.#listWorkspaces();\n const scopedWorkspaces = workspaceIds\n ? workspaces.filter(workspace => workspaceIds.has(workspace.linearWorkspaceId))\n : workspaces;\n const projectGroups = await Promise.all(\n scopedWorkspaces.map(async workspace => {\n const projects: LinearProject[] = [];\n let after: string | undefined;\n for (let page = 0; page < MAX_REFERENCE_PAGES; page += 1) {\n const query = new URLSearchParams({ first: '200' });\n if (after) query.set('after', after);\n const result = await this.#client.request<{ projects: LinearProject[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspace.linearWorkspaceId)}/projects?${query}`,\n );\n projects.push(...result.projects);\n if (!result.pageInfo.hasNextPage || !result.pageInfo.endCursor) break;\n // A page that hands back the cursor it was asked for would replay forever.\n if (result.pageInfo.endCursor === after) throw invalidLinearCursor();\n after = result.pageInfo.endCursor;\n }\n return projects.map(project => ({ workspace, project }));\n }),\n );\n return projectGroups.flat();\n }\n\n async #listTeamSources(workspaceIds?: ReadonlySet<string>): Promise<TeamSource[]> {\n const workspaces = await this.#listWorkspaces();\n const scopedWorkspaces = workspaceIds\n ? workspaces.filter(workspace => workspaceIds.has(workspace.linearWorkspaceId))\n : workspaces;\n const teamGroups = await Promise.all(\n scopedWorkspaces.map(async workspace => {\n const teams: LinearTeam[] = [];\n let after: string | undefined;\n for (let page = 0; page < MAX_REFERENCE_PAGES; page += 1) {\n const query = new URLSearchParams({ first: '200' });\n if (after) query.set('after', after);\n const result = await this.#client.request<{ teams: LinearTeam[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspace.linearWorkspaceId)}/teams?${query}`,\n );\n teams.push(...result.teams);\n if (!result.pageInfo.hasNextPage || !result.pageInfo.endCursor) break;\n // A page that hands back the cursor it was asked for would replay forever.\n if (result.pageInfo.endCursor === after) throw invalidLinearCursor();\n after = result.pageInfo.endCursor;\n }\n return teams.map(team => ({ workspace, team }));\n }),\n );\n return teamGroups.flat();\n }\n\n async listWorkspaces(): Promise<LinearWorkspace[]> {\n return this.#listWorkspaces();\n }\n\n async #listWorkspaces(): Promise<LinearWorkspace[]> {\n const result = await this.#client.request<{ workspaces: LinearWorkspace[] }>('GET', `${API_PREFIX}/workspaces`);\n return result.workspaces.filter(workspace => workspace.connected);\n }\n\n async #listIssues(sourceIds: string[], cursor?: string, labels?: string[], attributionSourceIds = sourceIds) {\n type ListedIssue = { issue: LinearIssue; sourceId: string; workspace: LinearWorkspace };\n if (sourceIds.length === 0) return { issues: [] as ListedIssue[], nextCursor: null };\n\n // Resolve every selected source to a concrete listing descriptor. Project\n // and team sources are listed separately: a project source filters by\n // `projectIds`, a team source filters by `teamId` (and returns projectless\n // issues too). Filters are never combined on one request.\n const parsedSources = sourceIds.map(sourceId => parseSourceId(sourceId));\n const projectWorkspaceIds = new Set(\n parsedSources.flatMap(source => (source.kind === 'project' ? [source.workspaceId] : [])),\n );\n const teamWorkspaceIds = new Set(\n parsedSources.flatMap(source => (source.kind === 'team' ? [source.workspaceId] : [])),\n );\n const [projectSources, teamSources] = await Promise.all([\n projectWorkspaceIds.size > 0\n ? this.#listProjectSources(projectWorkspaceIds)\n : Promise.resolve([] as ProjectSource[]),\n teamWorkspaceIds.size > 0 ? this.#listTeamSources(teamWorkspaceIds) : Promise.resolve([] as TeamSource[]),\n ]);\n const projectMap = new Map(\n projectSources.map(source => [encodeSourceId(source.workspace.linearWorkspaceId, source.project.id), source]),\n );\n const teamMap = new Map(\n teamSources.map(source => [encodeTeamSourceId(source.workspace.linearWorkspaceId, source.team.id), source]),\n );\n\n type Descriptor = {\n kind: 'project' | 'team';\n sourceId: string;\n workspace: LinearWorkspace;\n query: URLSearchParams;\n };\n const descriptors: Descriptor[] = [];\n const selectedProjectIdsByWorkspace = new Map<string, Set<string>>();\n for (const attributionSourceId of attributionSourceIds) {\n const source = parseSourceId(attributionSourceId);\n if (source.kind !== 'project') continue;\n const selectedProjectIds = selectedProjectIdsByWorkspace.get(source.workspaceId) ?? new Set<string>();\n selectedProjectIds.add(source.projectId);\n selectedProjectIdsByWorkspace.set(source.workspaceId, selectedProjectIds);\n }\n for (const sourceId of sourceIds) {\n const projectSource = projectMap.get(sourceId);\n if (projectSource) {\n const query = new URLSearchParams({\n first: String(PAGE_SIZE),\n projectIds: projectSource.project.id,\n stateType: 'triage,backlog,unstarted,started',\n orderBy: 'updatedAt',\n });\n const workspaceId = projectSource.workspace.linearWorkspaceId;\n const selectedProjectIds = selectedProjectIdsByWorkspace.get(workspaceId) ?? new Set<string>();\n selectedProjectIds.add(projectSource.project.id);\n selectedProjectIdsByWorkspace.set(workspaceId, selectedProjectIds);\n descriptors.push({ kind: 'project', sourceId, workspace: projectSource.workspace, query });\n continue;\n }\n const teamSource = teamMap.get(sourceId);\n if (teamSource) {\n const query = new URLSearchParams({\n first: String(PAGE_SIZE),\n teamId: teamSource.team.id,\n stateType: 'triage,backlog,unstarted,started',\n orderBy: 'updatedAt',\n });\n descriptors.push({ kind: 'team', sourceId, workspace: teamSource.workspace, query });\n }\n }\n\n const cursors = decodeCursor(cursor, sourceIds, attributionSourceIds);\n const normalizedLabels = normalizeLabels(labels);\n const nextState: Record<string, string | null> = {};\n let hasNextPage = false;\n const pages = await Promise.all(\n descriptors.map(async ({ kind, sourceId, workspace, query }) => {\n if (cursors[sourceId] === null) {\n nextState[sourceId] = null;\n return [] as ListedIssue[];\n }\n const after = cursors[sourceId];\n if (after) query.set('after', after);\n const result = await this.#client.request<{ issues: LinearIssue[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspace.linearWorkspaceId)}/issues?${query}`,\n );\n const next = result.pageInfo.hasNextPage ? result.pageInfo.endCursor : null;\n // A page that hands back the cursor it was asked for would replay forever.\n if (next !== null && next === after) throw invalidLinearCursor();\n nextState[sourceId] = next;\n hasNextPage ||= next !== null;\n return result.issues\n .filter(\n issue => normalizedLabels.length === 0 || issue.labels.some(label => normalizedLabels.includes(label.name)),\n )\n .filter(\n issue =>\n kind === 'project' ||\n issue.project === null ||\n !selectedProjectIdsByWorkspace.get(workspace.linearWorkspaceId)?.has(issue.project.id),\n )\n .map(issue => ({ issue, sourceId, workspace }));\n }),\n );\n return {\n issues: dedupeIssuesBySource(pages.flat(), sourceIds),\n nextCursor: hasNextPage ? encodeCursor(nextState, sourceIds, attributionSourceIds) : null,\n };\n }\n\n async #findIssue(\n sourceId: string | undefined,\n issueId: string,\n sourceIds?: string[],\n routedSourceIds?: string[],\n ): Promise<{\n workspaceId: string;\n issue: LinearIssue & { comments?: { nodes: LinearComment[]; pageInfo: PageInfo } };\n } | null> {\n const scopedSourceIds = sourceIds ?? (sourceId ? [sourceId] : undefined);\n const scopedSources = scopedSourceIds?.map(sourceKey => ({\n sourceKey,\n source: parseSourceId(sourceKey),\n }));\n const routedSourceSet = routedSourceIds ? new Set(routedSourceIds) : undefined;\n const workspaceIds = routedSourceIds\n ? [...new Set(routedSourceIds.map(sourceKey => parseSourceId(sourceKey).workspaceId))]\n : scopedSources\n ? [...new Set(scopedSources.map(({ source }) => source.workspaceId))]\n : await this.#candidateWorkspaceIds(undefined);\n for (const workspaceId of workspaceIds) {\n try {\n const issue = await this.#client.request<\n LinearIssue & { comments?: { nodes: LinearComment[]; pageInfo: PageInfo } }\n >(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}?include=comments`,\n );\n if (scopedSources) {\n const matching = scopedSources.filter(\n ({ source }) =>\n source.workspaceId === workspaceId &&\n (source.kind === 'team' ? issue.team.id === source.teamId : issue.project?.id === source.projectId),\n );\n const winner = matching.find(({ source }) => source.kind === 'project') ?? matching[0];\n if (!winner || (routedSourceSet && !routedSourceSet.has(winner.sourceKey))) continue;\n }\n return { workspaceId, issue };\n } catch (error) {\n if (!isNotFound(error)) throw error;\n }\n }\n return null;\n }\n\n async #resolveWorkspaceForIssue(sourceId: string | undefined, issueId: string): Promise<string | null> {\n const workspaceIds = await this.#candidateWorkspaceIds(sourceId);\n if (workspaceIds.length === 1) return workspaceIds[0]!;\n for (const workspaceId of workspaceIds) {\n try {\n await this.#client.request<LinearIssue>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}`,\n );\n return workspaceId;\n } catch (error) {\n if (!isNotFound(error)) throw error;\n }\n }\n return null;\n }\n\n async #listWorkflowStates(workspaceId: string, teamId: string): Promise<LinearWorkflowState[]> {\n const cacheKey = `${workspaceId}:${teamId}`;\n const cached = this.#workflowStatesByTeam.get(cacheKey);\n if (cached) return cached;\n const result = await this.#client.request<{ workflowStates: LinearWorkflowState[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/workflow-states?teamId=${encodeURIComponent(teamId)}&first=100`,\n );\n this.#workflowStatesByTeam.set(cacheKey, result.workflowStates);\n return result.workflowStates;\n }\n\n async #candidateWorkspaceIds(sourceId: string | undefined): Promise<string[]> {\n if (sourceId) return [parseSourceId(sourceId).workspaceId];\n return (await this.#listWorkspaces()).map(workspace => workspace.linearWorkspaceId);\n }\n\n async #loadComments(\n workspaceId: string,\n issueId: string,\n embedded: { nodes: LinearComment[]; pageInfo: PageInfo } | undefined,\n ): Promise<LinearComment[]> {\n const comments = [...(embedded?.nodes ?? [])];\n let pageInfo = embedded?.pageInfo;\n let page = 0;\n while (pageInfo?.hasNextPage && pageInfo.endCursor && page < MAX_COMMENT_PAGES) {\n const result = await this.#client.request<{ comments: LinearComment[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}/comments?first=200&after=${encodeURIComponent(pageInfo.endCursor)}`,\n );\n comments.push(...result.comments);\n if (result.pageInfo.hasNextPage && result.pageInfo.endCursor === pageInfo.endCursor) throw invalidLinearCursor();\n pageInfo = result.pageInfo;\n page += 1;\n }\n return comments;\n }\n}\n\nfunction parseIssue(issue: LinearIssue): IntakeIssue {\n return {\n id: issue.id,\n identifier: issue.identifier,\n title: issue.title,\n url: issue.url,\n author: issue.creator?.displayName ?? issue.creator?.name ?? null,\n state: issue.state.name,\n stateType: issue.state.type,\n priority: issue.priorityLabel,\n assignee: issue.assignee?.displayName ?? issue.assignee?.name ?? null,\n source: issue.team.key,\n labels: issue.labels.map(label => label.name),\n commentCount: null,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n };\n}\n\nfunction parseIssueDetail(issue: LinearIssue, comments: LinearComment[]): IntakeIssueDetail {\n return {\n ...parseIssue(issue),\n commentCount: comments.length,\n description: issue.description?.trim() ? issue.description : null,\n comments: comments.map(comment => ({\n author: comment.user?.displayName ?? comment.user?.name ?? null,\n body: comment.body,\n createdAt: comment.createdAt,\n })),\n };\n}\n\n/**\n * Deduplicate issues that surfaced from more than one selected source (a team\n * source and one of its projects both select the same issue). Keeps one entry\n * per Linear issue UUID.\n *\n * Tie-breaker — MOST-SPECIFIC-WINS: a project source beats a team source, so an\n * issue that belongs to a selected project is attributed to that project's\n * source (and therefore routes to the project's board). The team source covers\n * only the remainder — projectless issues and issues in projects that were not\n * separately selected. `selectionOrder` breaks a same-kind tie deterministically\n * by the order the sources were selected.\n *\n * This function is the single precedence point; change the comparison here to\n * change the routing policy.\n */\nfunction dedupeIssuesBySource<T extends { issue: { id: string }; sourceId: string }>(\n entries: T[],\n selectionOrder: string[],\n): T[] {\n const rank = new Map(selectionOrder.map((id, index) => [id, index]));\n const specificity = (sourceId: string): number => (parseSourceId(sourceId).kind === 'project' ? 0 : 1);\n const winners = new Map<string, T>();\n for (const entry of entries) {\n const existing = winners.get(entry.issue.id);\n if (!existing) {\n winners.set(entry.issue.id, entry);\n continue;\n }\n const bySpecificity = specificity(entry.sourceId) - specificity(existing.sourceId);\n const better =\n bySpecificity < 0 ||\n (bySpecificity === 0 &&\n (rank.get(entry.sourceId) ?? Number.MAX_SAFE_INTEGER) <\n (rank.get(existing.sourceId) ?? Number.MAX_SAFE_INTEGER));\n if (better) winners.set(entry.issue.id, entry);\n }\n // Preserve first-seen order of the surviving issues.\n const seen = new Set<string>();\n const ordered: T[] = [];\n for (const entry of entries) {\n if (seen.has(entry.issue.id)) continue;\n seen.add(entry.issue.id);\n ordered.push(winners.get(entry.issue.id)!);\n }\n return ordered;\n}\n\nexport function encodeSourceId(workspaceId: string, projectId: string): string {\n return `linear-project:${Buffer.from(JSON.stringify({ workspaceId, projectId })).toString('base64url')}`;\n}\n\nfunction decodeSourceId(sourceId: string): { workspaceId: string; projectId: string } {\n if (!sourceId.startsWith('linear-project:')) throw new Error('Linear project source id is invalid.');\n try {\n const parsed = JSON.parse(Buffer.from(sourceId.slice('linear-project:'.length), 'base64url').toString('utf8')) as {\n workspaceId?: unknown;\n projectId?: unknown;\n };\n if (typeof parsed.workspaceId !== 'string' || !parsed.workspaceId) throw new Error();\n if (typeof parsed.projectId !== 'string' || !parsed.projectId) throw new Error();\n return { workspaceId: parsed.workspaceId, projectId: parsed.projectId };\n } catch {\n throw new Error('Linear project source id is invalid.');\n }\n}\n\nconst TEAM_SOURCE_PREFIX = 'linear-team:';\n\nexport function encodeTeamSourceId(workspaceId: string, teamId: string): string {\n return `${TEAM_SOURCE_PREFIX}${Buffer.from(JSON.stringify({ workspaceId, teamId })).toString('base64url')}`;\n}\n\nexport function decodeTeamSourceId(sourceId: string): { workspaceId: string; teamId: string } {\n if (!sourceId.startsWith(TEAM_SOURCE_PREFIX)) throw new Error('Linear team source id is invalid.');\n try {\n const parsed = JSON.parse(Buffer.from(sourceId.slice(TEAM_SOURCE_PREFIX.length), 'base64url').toString('utf8')) as {\n workspaceId?: unknown;\n teamId?: unknown;\n };\n if (typeof parsed.workspaceId !== 'string' || !parsed.workspaceId) throw new Error();\n if (typeof parsed.teamId !== 'string' || !parsed.teamId) throw new Error();\n return { workspaceId: parsed.workspaceId, teamId: parsed.teamId };\n } catch {\n throw new Error('Linear team source id is invalid.');\n }\n}\n\n/**\n * A decoded intake source: either a Linear project or a whole Linear team.\n * Downstream code discriminates on `kind` to build the right issue-listing\n * filter and to apply most-specific-wins routing (project beats team).\n */\nexport type DecodedSource =\n { kind: 'project'; workspaceId: string; projectId: string } | { kind: 'team'; workspaceId: string; teamId: string };\n\n/** Discriminate any Linear source id by its prefix and decode it. */\nexport function parseSourceId(sourceId: string): DecodedSource {\n if (sourceId.startsWith(TEAM_SOURCE_PREFIX)) {\n return { kind: 'team', ...decodeTeamSourceId(sourceId) };\n }\n return { kind: 'project', ...decodeSourceId(sourceId) };\n}\n\nfunction normalizeLabels(labels: string[] | undefined): string[] {\n return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];\n}\n\ntype PlatformListCursor = { v: 1; sourceSet: string; cursors: Array<string | null> };\n\nfunction canonicalSourceIds(sourceIds: string[]): string[] {\n return [...new Set(sourceIds)].sort();\n}\n\nfunction linearSourceSetFingerprint(sourceIds: string[], attributionSourceIds: string[]): string {\n const scope = {\n sourceIds: canonicalSourceIds(sourceIds),\n attributionSourceIds: canonicalSourceIds(attributionSourceIds),\n };\n return createHash('sha256').update(JSON.stringify(scope)).digest('base64url');\n}\n\nfunction invalidLinearCursor(): Error {\n return Object.assign(new Error('Linear cursor is invalid or stale.'), { code: 'invalid_cursor' as const });\n}\n\nfunction decodeCursor(\n cursor: string | undefined,\n sourceIds: string[],\n attributionSourceIds: string[],\n): Record<string, string | null | undefined> {\n if (!cursor) return {};\n try {\n const parsed = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8')) as Partial<PlatformListCursor>;\n const canonical = canonicalSourceIds(sourceIds);\n if (\n parsed.v !== 1 ||\n parsed.sourceSet !== linearSourceSetFingerprint(sourceIds, attributionSourceIds) ||\n !Array.isArray(parsed.cursors) ||\n parsed.cursors.length !== canonical.length ||\n !parsed.cursors.every(value => value === null || typeof value === 'string')\n ) {\n throw invalidLinearCursor();\n }\n return Object.fromEntries(canonical.map((sourceId, index) => [sourceId, parsed.cursors![index]]));\n } catch {\n throw invalidLinearCursor();\n }\n}\n\nfunction encodeCursor(\n state: Record<string, string | null>,\n sourceIds: string[],\n attributionSourceIds: string[],\n): string {\n const canonical = canonicalSourceIds(sourceIds);\n const cursor: PlatformListCursor = {\n v: 1,\n sourceSet: linearSourceSetFingerprint(sourceIds, attributionSourceIds),\n cursors: canonical.map(sourceId => state[sourceId] ?? null),\n };\n return Buffer.from(JSON.stringify(cursor)).toString('base64url');\n}\n\nfunction requireLinearConnection(connection: IntegrationConnection): void {\n if (connection.type !== 'oauth') {\n throw new Error('Linear capabilities require an OAuth connection.');\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return error instanceof PlatformApiError && error.status === 404;\n}\n\nfunction optionalPositiveIntegerEnv(name: string): number | undefined {\n const value = process.env[name]?.trim();\n if (!value) return undefined;\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed) || parsed <= 0) {\n throw new Error(`${name} must be a positive integer.`);\n }\n return parsed;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"integration.js","names":["#client","#endpointHost","#workflowStatesByTeam","#resolveIntakeDispatch","#listProjectSources","#listTeamSources","#listIssues","#findIssue","#loadComments","#resolveWorkspaceForIssue","#listWorkflowStates","#rules","#projects","#auth","#listWorkspaces","#connectRoute","#candidateWorkspaceIds"],"sources":["../../../../src/integrations/platform/linear/integration.ts"],"sourcesContent":["import type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\nimport type { Context } from 'hono';\n\nimport type { IntegrationConnection } from '../../../capabilities/connection.js';\nimport type { Intake, IntakeIssue, IntakeIssueDetail, UpdateIntakeIssueInput } from '../../../capabilities/intake.js';\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../../../storage/domains/projects/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';\nimport { buildLinearAgentTools } from '../../linear/agent-tools.js';\nimport type { LinearEventRules, LinearRuleOverrides } from '../../linear/default-rules.js';\nimport { resolveLinearRules } from '../../linear/default-rules.js';\nimport type {\n LinearConnectionCheck,\n LinearIntegration,\n LinearIssueDetail as LinearRouteIssueDetail,\n} from '../../linear/integration.js';\nimport { attachLinearIssueReconciler } from '../../linear/issue-reconciler.js';\nimport {\n linearIssueReconciliationEnabled,\n linearIssueReconciliationInterval,\n} from '../../linear/reconciliation-config.js';\nimport { buildLinearRoutes } from '../../linear/routes.js';\nimport { attachLinearRules } from '../../linear/rules.js';\nimport type { LinearConnectionData, LinearConnectionRow, LinearStorageHandle } from '../../linear/storage.js';\nimport {\n logPlatformInfo,\n logPlatformWarn,\n PlatformApiClient,\n PlatformApiError,\n platformApiClientConfigFromEnv,\n} from '../api-client.js';\nimport { PlatformLinearEventWorker } from './event-worker.js';\nimport type { PlatformLinearEventStorage } from './event-worker.js';\n\ntype PageInfo = { hasNextPage: boolean; endCursor: string | null };\ntype LinearUser = {\n id: string;\n name: string;\n displayName: string;\n email: string | null;\n avatarUrl: string | null;\n};\ntype LinearIssue = {\n id: string;\n identifier: string;\n number: number;\n title: string;\n description: string | null;\n url: string;\n priority: number;\n priorityLabel: string;\n labels: Array<{ id: string; name: string }>;\n state: { id: string; name: string; type: string };\n team: { id: string; key: string; name: string };\n project: { id: string } | null;\n assignee: LinearUser | null;\n creator: LinearUser | null;\n createdAt: string;\n updatedAt: string;\n archivedAt: string | null;\n};\ntype LinearComment = {\n id: string;\n body: string;\n url: string;\n issue: { id: string; identifier: string };\n user: LinearUser | null;\n parent: { id: string } | null;\n createdAt: string;\n updatedAt: string;\n};\ntype LinearWorkspace = {\n linearWorkspaceId: string;\n linearWorkspaceName: string;\n urlKey: string | null;\n connected: boolean;\n};\ntype LinearProject = {\n id: string;\n name: string;\n state: string;\n teams: Array<{ id: string; key: string; name: string }>;\n};\ntype LinearTeam = { id: string; key: string; name: string };\ntype ProjectSource = { workspace: LinearWorkspace; project: LinearProject };\ntype TeamSource = { workspace: LinearWorkspace; team: LinearTeam };\ntype LinearWorkflowState = {\n id: string;\n name: string;\n type: string;\n position: number;\n teamId: string;\n};\n\nconst API_PREFIX = '/v1/server/linear';\nconst PAGE_SIZE = 30;\nconst MAX_REFERENCE_PAGES = 20;\nconst MAX_COMMENT_PAGES = 20;\nconst PLATFORM_MANAGED_CONNECTION_TOKEN = 'platform-managed';\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction routeBaseUrl(ctx: IntegrationContext, requestUrl: string): string {\n return (ctx.baseUrl || new URL(requestUrl).origin).replace(/\\/+$/, '');\n}\n\nexport class PlatformLinearIntegration implements FactoryIntegration {\n readonly id = 'linear';\n readonly #client: PlatformApiClient;\n readonly #endpointHost: string;\n #projects: FactoryProjectsStorage | undefined;\n #auth: RouteAuth | undefined;\n /**\n * Per-instance workflow-state cache keyed by `${workspaceId}:${teamId}`. Scoped to the process\n * lifetime; not shared across requests intentionally to keep failure modes simple (stale states\n * clear on process restart). Populated lazily on first `updateIssue` per team.\n */\n readonly #workflowStatesByTeam = new Map<string, LinearWorkflowState[]>();\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: async () => {\n const [projectSources, teamSources] = await Promise.all([this.#listProjectSources(), this.#listTeamSources()]);\n const projects = projectSources.map(({ workspace, project }) => ({\n id: encodeSourceId(workspace.linearWorkspaceId, project.id),\n name: project.name,\n type: 'project' as const,\n metadata: {\n workspaceId: workspace.linearWorkspaceId,\n workspaceName: workspace.linearWorkspaceName,\n workspaceUrlKey: workspace.urlKey,\n state: project.state,\n teams: project.teams,\n },\n }));\n const teams = teamSources.map(({ workspace, team }) => ({\n id: encodeTeamSourceId(workspace.linearWorkspaceId, team.id),\n name: team.name,\n type: 'team' as const,\n metadata: {\n workspaceId: workspace.linearWorkspaceId,\n workspaceName: workspace.linearWorkspaceName,\n workspaceUrlKey: workspace.urlKey,\n teamKey: team.key,\n },\n }));\n return [...projects, ...teams];\n },\n listItems: async ({ sourceIds, attributionSourceIds, cursor }) => {\n const result = await this.#listIssues(sourceIds, cursor, undefined, attributionSourceIds);\n return {\n items: result.issues.map(({ issue, sourceId, workspace }) => ({\n source: { type: 'issue', externalId: issue.id, url: issue.url },\n sourceId,\n title: issue.title,\n status: issue.state.name,\n labels: issue.labels.map(label => label.name),\n assignee: issue.assignee?.displayName ?? issue.assignee?.name ?? null,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: {\n identifier: issue.identifier,\n workspaceId: workspace.linearWorkspaceId,\n workspaceName: workspace.linearWorkspaceName,\n projectId: issue.project?.id ?? null,\n team: issue.team.key,\n priority: issue.priorityLabel,\n },\n })),\n nextCursor: result.nextCursor,\n };\n },\n listIssues: async ({ connection, sourceIds, attributionSourceIds, labels, cursor }) => {\n requireLinearConnection(connection);\n const result = await this.#listIssues(sourceIds, cursor, labels, attributionSourceIds);\n return {\n issues: result.issues.map(({ issue, sourceId }) => ({\n ...parseIssue(issue),\n sourceId,\n })),\n nextCursor: result.nextCursor,\n };\n },\n getIssue: async ({ connection, sourceId, issueId }) => {\n requireLinearConnection(connection);\n const located = await this.#findIssue(sourceId, issueId);\n if (!located) return null;\n const comments = await this.#loadComments(located.workspaceId, issueId, located.issue.comments);\n return parseIssueDetail(located.issue, comments);\n },\n createComment: async ({ connection, sourceId, issueId, body }) => {\n requireLinearConnection(connection);\n const workspaceId = await this.#resolveWorkspaceForIssue(sourceId, issueId);\n if (!workspaceId) return null;\n try {\n const comment = await this.#client.request<LinearComment>(\n 'POST',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}/comments`,\n { body },\n );\n return { id: comment.id, url: comment.url };\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n },\n updateIssue: async (input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> => {\n requireLinearConnection(input.connection);\n const located = await this.#findIssue(input.sourceId, input.issueId);\n if (!located) return null;\n const { workspaceId, issue } = located;\n\n const target = input.state;\n // Idempotency: skip the write entirely if the issue is already at the target state.\n if (target.kind === 'byType' && issue.state.type === target.stateType) {\n return parseIssue(issue);\n }\n if (target.kind === 'byName' && issue.state.name.toLowerCase() === target.name.toLowerCase()) {\n return parseIssue(issue);\n }\n\n let states: LinearWorkflowState[];\n try {\n states = await this.#listWorkflowStates(workspaceId, issue.team.id);\n } catch (error) {\n if (isNotFound(error)) {\n // Platform companion endpoint not deployed yet — degrade to policy skip so PR 1\n // is standalone-mergeable ahead of the platform-side workflow-states route landing.\n logPlatformWarn('Platform Linear: workflow-states endpoint not available; skipping updateIssue.', {\n workspaceId,\n teamId: issue.team.id,\n });\n return null;\n }\n throw error;\n }\n let matched: LinearWorkflowState | undefined;\n if (target.kind === 'byType') {\n matched = states\n .slice()\n .sort((a, b) => a.position - b.position)\n .find(s => s.type === target.stateType);\n } else {\n const wanted = target.name.toLowerCase();\n matched = states.find(s => s.name.toLowerCase() === wanted);\n }\n if (!matched) {\n logPlatformWarn('Platform Linear: no workflow state matched target; skipping updateIssue.', {\n workspaceId,\n teamId: issue.team.id,\n target,\n });\n return null;\n }\n\n try {\n await this.#client.request<LinearIssue>(\n 'PATCH',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(input.issueId)}`,\n { stateId: matched.id },\n );\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n\n const refreshed = await this.#findIssue(input.sourceId, input.issueId);\n return refreshed ? parseIssue(refreshed.issue) : null;\n },\n };\n\n readonly #rules: LinearEventRules;\n\n get rules(): LinearEventRules {\n return this.#rules;\n }\n\n constructor({ rules }: { rules?: LinearRuleOverrides } = {}) {\n this.#rules = resolveLinearRules(rules);\n const config = platformApiClientConfigFromEnv();\n this.#client = new PlatformApiClient(config);\n this.#endpointHost = new URL(config.baseUrl).host;\n }\n\n get storage(): LinearStorageHandle {\n const now = new Date();\n return {\n integrationId: this.id,\n connections: {\n get: async (orgId: string) => ({\n id: `platform-linear:${orgId}`,\n orgId,\n userId: null,\n data: {\n accessToken: PLATFORM_MANAGED_CONNECTION_TOKEN,\n refreshToken: null,\n expiresAtMs: null,\n scope: 'read,comments:create',\n workspaceName: null,\n workspaceUrlKey: null,\n } satisfies LinearConnectionData,\n metadata: {},\n createdAt: now,\n updatedAt: now,\n }),\n },\n } as unknown as LinearStorageHandle;\n }\n\n get projects(): FactoryProjectsStorage {\n if (!this.#projects) throw new Error('PlatformLinearIntegration projects storage has not been initialized.');\n return this.#projects;\n }\n\n initialize({ projects, auth }: { projects: FactoryProjectsStorage; auth?: RouteAuth }): void {\n this.#projects = projects;\n this.#auth = auth;\n logPlatformInfo('Platform Linear integration initialized', { endpointHost: this.#endpointHost });\n }\n\n get authEnabled(): boolean {\n return this.#auth?.enabled() ?? false;\n }\n\n async resolveOrgId(resourceId: string): Promise<string | null> {\n try {\n const project = await this.projects.getById({ id: resourceId });\n return project?.orgId ?? null;\n } catch {\n return null;\n }\n }\n\n async loadConnection(orgId: string): Promise<LinearConnectionRow | null> {\n const workspace = (await this.#listWorkspaces())[0];\n if (!workspace) return null;\n const now = new Date();\n return {\n id: `platform-linear:${orgId}`,\n orgId,\n userId: null,\n accessToken: PLATFORM_MANAGED_CONNECTION_TOKEN,\n scope: 'read,comments:create',\n refreshToken: null,\n expiresAt: null,\n workspaceName: workspace.linearWorkspaceName,\n workspaceUrlKey: workspace.urlKey,\n createdAt: now,\n updatedAt: now,\n };\n }\n\n async getFreshAccessToken(_connection: LinearConnectionRow): Promise<string> {\n return PLATFORM_MANAGED_CONNECTION_TOKEN;\n }\n\n /**\n * Background-dispatch context: platform-managed connection token when the\n * org has a connected workspace. Linear work items store the issue UUID\n * directly as `externalId`.\n */\n async #resolveIntakeDispatch({\n orgId,\n externalSource,\n }: {\n orgId: string;\n externalSource: { type: string; externalId: string };\n }): Promise<{ connection: IntegrationConnection; issueId: string } | null> {\n if (externalSource.type !== 'issue') return null;\n const connection = await this.loadConnection(orgId);\n if (!connection) return null;\n return {\n connection: { type: 'oauth', accessToken: PLATFORM_MANAGED_CONNECTION_TOKEN },\n issueId: externalSource.externalId,\n };\n }\n\n canPostComments(connection: LinearConnectionRow): boolean {\n const scopes = (connection.scope ?? '').split(/[\\s,]+/).filter(Boolean);\n return scopes.some(scope => scope === 'comments:create' || scope === 'write' || scope === 'admin');\n }\n\n async checkConnection(orgId: string): Promise<LinearConnectionCheck> {\n const connection = await this.loadConnection(orgId);\n return {\n connected: connection !== null,\n canComment: connection !== null && this.canPostComments(connection),\n checkedAt: Date.now(),\n };\n }\n\n workers(ctx: IntegrationContext): MastraWorker[] {\n const pollingEnabled = process.env.MASTRACODE_PLATFORM_LINEAR_POLLING_ENABLED?.trim().toLowerCase() !== 'false';\n const reconcileEnabled = linearIssueReconciliationEnabled();\n if (!pollingEnabled && !reconcileEnabled) return [];\n\n const ingest = attachLinearRules(this, ctx);\n const reconcile = reconcileEnabled ? attachLinearIssueReconciler(this, ctx) : undefined;\n const workItems = ctx.runtime?.workItems;\n if (!workItems) return [];\n if (!ingest && !reconcile) return [];\n\n const pollIntervalMs = optionalPositiveIntegerEnv('MASTRACODE_PLATFORM_LINEAR_POLLING_INTERVAL_MS');\n const reconcileIntervalMs = linearIssueReconciliationInterval();\n\n return [\n new PlatformLinearEventWorker({\n client: this.#client,\n linear: { listWorkspaces: () => this.listWorkspaces() },\n storage: ctx.storage.generic as unknown as PlatformLinearEventStorage,\n projects: ctx.storage.projects,\n workItems,\n ...(ingest ? { ingestFactoryIssue: ingest } : {}),\n ...(reconcile ? { reconcileFactoryState: reconcile } : {}),\n pollEventsEnabled: pollingEnabled,\n ...(pollIntervalMs !== undefined ? { intervalMs: pollIntervalMs } : {}),\n ...(reconcileIntervalMs !== undefined ? { reconcileIntervalMs } : {}),\n }),\n ];\n }\n\n routes(ctx: IntegrationContext): ApiRoute[] {\n return [\n this.#connectRoute(ctx),\n ...buildLinearRoutes({\n auth: ctx.auth,\n linear: this as unknown as LinearIntegration,\n stateSigner: ctx.stateSigner,\n baseUrl: ctx.baseUrl,\n intake: ctx.storage.intake,\n projects: ctx.storage.projects,\n ingestFactoryIssues: attachLinearRules(this, ctx),\n workItems: ctx.runtime?.workItems,\n boards: ctx.runtime?.boards,\n }).filter(route => !route.path.startsWith('/auth/linear/')),\n ];\n }\n\n #connectRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/auth/linear/connect', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const returnTo = c.req.query('return_to') || '/';\n const originator = routeBaseUrl(ctx, c.req.url);\n logPlatformInfo('Starting Platform Linear connect flow', {\n orgId: tenant.orgId,\n returnTo,\n originator,\n });\n const query = new URLSearchParams({ return_to: returnTo, originator });\n const location = await this.#client.requestRedirect('GET', `${API_PREFIX}/authorize?${query}`);\n return c.redirect(location);\n },\n });\n }\n\n async agentTools({ requestContext }: { requestContext: RequestContext }): Promise<IntegrationTools> {\n return buildLinearAgentTools({ requestContext, linear: this as unknown as LinearIntegration });\n }\n\n diagnostics(): Record<string, unknown> {\n return { mode: 'platform', endpointHost: this.#endpointHost };\n }\n\n async listProjects(): Promise<Array<LinearProject & { workspaceId: string }>> {\n return (await this.#listProjectSources()).map(({ workspace, project }) => ({\n ...project,\n id: encodeSourceId(workspace.linearWorkspaceId, project.id),\n workspaceId: workspace.linearWorkspaceId,\n }));\n }\n\n async listTeams(_accessToken: string): Promise<Array<LinearTeam & { workspaceId: string; sourceId: string }>> {\n return (await this.#listTeamSources()).map(({ workspace, team }) => ({\n ...team,\n workspaceId: workspace.linearWorkspaceId,\n sourceId: encodeTeamSourceId(workspace.linearWorkspaceId, team.id),\n }));\n }\n\n async fetchIssueDetail(\n _accessToken: string,\n idOrIdentifier: string,\n sourceIds?: string[],\n routedSourceIds?: string[],\n ): Promise<LinearRouteIssueDetail | null> {\n const located = await this.#findIssue(undefined, idOrIdentifier, sourceIds, routedSourceIds);\n if (!located) return null;\n const comments = await this.#loadComments(located.workspaceId, located.issue.id, located.issue.comments);\n const issue = located.issue;\n return {\n id: issue.id,\n projectId: issue.project?.id ?? null,\n workspaceId: located.workspaceId,\n teamId: issue.team.id,\n identifier: issue.identifier,\n title: issue.title,\n description: issue.description?.trim() ? issue.description : null,\n url: issue.url,\n state: issue.state.name,\n stateType: issue.state.type,\n priorityLabel: issue.priorityLabel,\n assignee: issue.assignee?.displayName ?? issue.assignee?.name ?? null,\n creator: issue.creator?.displayName ?? issue.creator?.name ?? null,\n team: issue.team.key,\n labels: issue.labels.map(label => label.name),\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n comments: comments.map(comment => ({\n author: comment.user?.displayName ?? comment.user?.name ?? null,\n body: comment.body,\n createdAt: comment.createdAt,\n })),\n };\n }\n\n sourceMatchesIssue(\n sourceId: string,\n issue: Pick<LinearRouteIssueDetail, 'workspaceId' | 'projectId' | 'teamId'>,\n ): boolean {\n const source = parseSourceId(sourceId);\n if (issue.workspaceId !== source.workspaceId) return false;\n return source.kind === 'team' ? issue.teamId === source.teamId : issue.projectId === source.projectId;\n }\n\n async #listProjectSources(workspaceIds?: ReadonlySet<string>): Promise<ProjectSource[]> {\n const workspaces = await this.#listWorkspaces();\n const scopedWorkspaces = workspaceIds\n ? workspaces.filter(workspace => workspaceIds.has(workspace.linearWorkspaceId))\n : workspaces;\n const projectGroups = await Promise.all(\n scopedWorkspaces.map(async workspace => {\n const projects: LinearProject[] = [];\n let after: string | undefined;\n for (let page = 0; page < MAX_REFERENCE_PAGES; page += 1) {\n const query = new URLSearchParams({ first: '200' });\n if (after) query.set('after', after);\n const result = await this.#client.request<{ projects: LinearProject[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspace.linearWorkspaceId)}/projects?${query}`,\n );\n projects.push(...result.projects);\n if (!result.pageInfo.hasNextPage || !result.pageInfo.endCursor) break;\n // A page that hands back the cursor it was asked for would replay forever.\n if (result.pageInfo.endCursor === after) throw invalidLinearCursor();\n after = result.pageInfo.endCursor;\n }\n return projects.map(project => ({ workspace, project }));\n }),\n );\n return projectGroups.flat();\n }\n\n async #listTeamSources(workspaceIds?: ReadonlySet<string>): Promise<TeamSource[]> {\n const workspaces = await this.#listWorkspaces();\n const scopedWorkspaces = workspaceIds\n ? workspaces.filter(workspace => workspaceIds.has(workspace.linearWorkspaceId))\n : workspaces;\n const teamGroups = await Promise.all(\n scopedWorkspaces.map(async workspace => {\n const teams: LinearTeam[] = [];\n let after: string | undefined;\n for (let page = 0; page < MAX_REFERENCE_PAGES; page += 1) {\n const query = new URLSearchParams({ first: '200' });\n if (after) query.set('after', after);\n const result = await this.#client.request<{ teams: LinearTeam[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspace.linearWorkspaceId)}/teams?${query}`,\n );\n teams.push(...result.teams);\n if (!result.pageInfo.hasNextPage || !result.pageInfo.endCursor) break;\n // A page that hands back the cursor it was asked for would replay forever.\n if (result.pageInfo.endCursor === after) throw invalidLinearCursor();\n after = result.pageInfo.endCursor;\n }\n return teams.map(team => ({ workspace, team }));\n }),\n );\n return teamGroups.flat();\n }\n\n async listWorkspaces(): Promise<LinearWorkspace[]> {\n return this.#listWorkspaces();\n }\n\n async #listWorkspaces(): Promise<LinearWorkspace[]> {\n const result = await this.#client.request<{ workspaces: LinearWorkspace[] }>('GET', `${API_PREFIX}/workspaces`);\n return result.workspaces.filter(workspace => workspace.connected);\n }\n\n async #listIssues(sourceIds: string[], cursor?: string, labels?: string[], attributionSourceIds = sourceIds) {\n type ListedIssue = { issue: LinearIssue; sourceId: string; workspace: LinearWorkspace };\n if (sourceIds.length === 0) return { issues: [] as ListedIssue[], nextCursor: null };\n\n // Resolve every selected source to a concrete listing descriptor. Project\n // and team sources are listed separately: a project source filters by\n // `projectIds`, a team source filters by `teamId` (and returns projectless\n // issues too). Filters are never combined on one request.\n const parsedSources = sourceIds.map(sourceId => parseSourceId(sourceId));\n const projectWorkspaceIds = new Set(\n parsedSources.flatMap(source => (source.kind === 'project' ? [source.workspaceId] : [])),\n );\n const teamWorkspaceIds = new Set(\n parsedSources.flatMap(source => (source.kind === 'team' ? [source.workspaceId] : [])),\n );\n const [projectSources, teamSources] = await Promise.all([\n projectWorkspaceIds.size > 0\n ? this.#listProjectSources(projectWorkspaceIds)\n : Promise.resolve([] as ProjectSource[]),\n teamWorkspaceIds.size > 0 ? this.#listTeamSources(teamWorkspaceIds) : Promise.resolve([] as TeamSource[]),\n ]);\n const projectMap = new Map(\n projectSources.map(source => [encodeSourceId(source.workspace.linearWorkspaceId, source.project.id), source]),\n );\n const teamMap = new Map(\n teamSources.map(source => [encodeTeamSourceId(source.workspace.linearWorkspaceId, source.team.id), source]),\n );\n\n type Descriptor = {\n kind: 'project' | 'team';\n sourceId: string;\n workspace: LinearWorkspace;\n query: URLSearchParams;\n };\n const descriptors: Descriptor[] = [];\n const selectedProjectIdsByWorkspace = new Map<string, Set<string>>();\n for (const attributionSourceId of attributionSourceIds) {\n const source = parseSourceId(attributionSourceId);\n if (source.kind !== 'project') continue;\n const selectedProjectIds = selectedProjectIdsByWorkspace.get(source.workspaceId) ?? new Set<string>();\n selectedProjectIds.add(source.projectId);\n selectedProjectIdsByWorkspace.set(source.workspaceId, selectedProjectIds);\n }\n for (const sourceId of sourceIds) {\n const projectSource = projectMap.get(sourceId);\n if (projectSource) {\n const query = new URLSearchParams({\n first: String(PAGE_SIZE),\n projectIds: projectSource.project.id,\n stateType: 'triage,backlog,unstarted,started',\n orderBy: 'updatedAt',\n });\n const workspaceId = projectSource.workspace.linearWorkspaceId;\n const selectedProjectIds = selectedProjectIdsByWorkspace.get(workspaceId) ?? new Set<string>();\n selectedProjectIds.add(projectSource.project.id);\n selectedProjectIdsByWorkspace.set(workspaceId, selectedProjectIds);\n descriptors.push({ kind: 'project', sourceId, workspace: projectSource.workspace, query });\n continue;\n }\n const teamSource = teamMap.get(sourceId);\n if (teamSource) {\n const query = new URLSearchParams({\n first: String(PAGE_SIZE),\n teamId: teamSource.team.id,\n stateType: 'triage,backlog,unstarted,started',\n orderBy: 'updatedAt',\n });\n descriptors.push({ kind: 'team', sourceId, workspace: teamSource.workspace, query });\n }\n }\n\n const cursors = await decodeCursor(cursor, sourceIds, attributionSourceIds);\n const normalizedLabels = normalizeLabels(labels);\n const nextState: Record<string, string | null> = {};\n let hasNextPage = false;\n const pages = await Promise.all(\n descriptors.map(async ({ kind, sourceId, workspace, query }) => {\n if (cursors[sourceId] === null) {\n nextState[sourceId] = null;\n return [] as ListedIssue[];\n }\n const after = cursors[sourceId];\n if (after) query.set('after', after);\n const result = await this.#client.request<{ issues: LinearIssue[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspace.linearWorkspaceId)}/issues?${query}`,\n );\n const next = result.pageInfo.hasNextPage ? result.pageInfo.endCursor : null;\n // A page that hands back the cursor it was asked for would replay forever.\n if (next !== null && next === after) throw invalidLinearCursor();\n nextState[sourceId] = next;\n hasNextPage ||= next !== null;\n return result.issues\n .filter(\n issue => normalizedLabels.length === 0 || issue.labels.some(label => normalizedLabels.includes(label.name)),\n )\n .filter(\n issue =>\n kind === 'project' ||\n issue.project === null ||\n !selectedProjectIdsByWorkspace.get(workspace.linearWorkspaceId)?.has(issue.project.id),\n )\n .map(issue => ({ issue, sourceId, workspace }));\n }),\n );\n return {\n issues: dedupeIssuesBySource(pages.flat(), sourceIds),\n nextCursor: hasNextPage ? await encodeCursor(nextState, sourceIds, attributionSourceIds) : null,\n };\n }\n\n async #findIssue(\n sourceId: string | undefined,\n issueId: string,\n sourceIds?: string[],\n routedSourceIds?: string[],\n ): Promise<{\n workspaceId: string;\n issue: LinearIssue & { comments?: { nodes: LinearComment[]; pageInfo: PageInfo } };\n } | null> {\n const scopedSourceIds = sourceIds ?? (sourceId ? [sourceId] : undefined);\n const scopedSources = scopedSourceIds?.map(sourceKey => ({\n sourceKey,\n source: parseSourceId(sourceKey),\n }));\n const routedSourceSet = routedSourceIds ? new Set(routedSourceIds) : undefined;\n const workspaceIds = routedSourceIds\n ? [...new Set(routedSourceIds.map(sourceKey => parseSourceId(sourceKey).workspaceId))]\n : scopedSources\n ? [...new Set(scopedSources.map(({ source }) => source.workspaceId))]\n : await this.#candidateWorkspaceIds(undefined);\n for (const workspaceId of workspaceIds) {\n try {\n const issue = await this.#client.request<\n LinearIssue & { comments?: { nodes: LinearComment[]; pageInfo: PageInfo } }\n >(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}?include=comments`,\n );\n if (scopedSources) {\n const matching = scopedSources.filter(\n ({ source }) =>\n source.workspaceId === workspaceId &&\n (source.kind === 'team' ? issue.team.id === source.teamId : issue.project?.id === source.projectId),\n );\n const winner = matching.find(({ source }) => source.kind === 'project') ?? matching[0];\n if (!winner || (routedSourceSet && !routedSourceSet.has(winner.sourceKey))) continue;\n }\n return { workspaceId, issue };\n } catch (error) {\n if (!isNotFound(error)) throw error;\n }\n }\n return null;\n }\n\n async #resolveWorkspaceForIssue(sourceId: string | undefined, issueId: string): Promise<string | null> {\n const workspaceIds = await this.#candidateWorkspaceIds(sourceId);\n if (workspaceIds.length === 1) return workspaceIds[0]!;\n for (const workspaceId of workspaceIds) {\n try {\n await this.#client.request<LinearIssue>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}`,\n );\n return workspaceId;\n } catch (error) {\n if (!isNotFound(error)) throw error;\n }\n }\n return null;\n }\n\n async #listWorkflowStates(workspaceId: string, teamId: string): Promise<LinearWorkflowState[]> {\n const cacheKey = `${workspaceId}:${teamId}`;\n const cached = this.#workflowStatesByTeam.get(cacheKey);\n if (cached) return cached;\n const result = await this.#client.request<{ workflowStates: LinearWorkflowState[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/workflow-states?teamId=${encodeURIComponent(teamId)}&first=100`,\n );\n this.#workflowStatesByTeam.set(cacheKey, result.workflowStates);\n return result.workflowStates;\n }\n\n async #candidateWorkspaceIds(sourceId: string | undefined): Promise<string[]> {\n if (sourceId) return [parseSourceId(sourceId).workspaceId];\n return (await this.#listWorkspaces()).map(workspace => workspace.linearWorkspaceId);\n }\n\n async #loadComments(\n workspaceId: string,\n issueId: string,\n embedded: { nodes: LinearComment[]; pageInfo: PageInfo } | undefined,\n ): Promise<LinearComment[]> {\n const comments = [...(embedded?.nodes ?? [])];\n let pageInfo = embedded?.pageInfo;\n let page = 0;\n while (pageInfo?.hasNextPage && pageInfo.endCursor && page < MAX_COMMENT_PAGES) {\n const result = await this.#client.request<{ comments: LinearComment[]; pageInfo: PageInfo }>(\n 'GET',\n `${API_PREFIX}/workspaces/${encodeURIComponent(workspaceId)}/issues/${encodeURIComponent(issueId)}/comments?first=200&after=${encodeURIComponent(pageInfo.endCursor)}`,\n );\n comments.push(...result.comments);\n if (result.pageInfo.hasNextPage && result.pageInfo.endCursor === pageInfo.endCursor) throw invalidLinearCursor();\n pageInfo = result.pageInfo;\n page += 1;\n }\n return comments;\n }\n}\n\nfunction parseIssue(issue: LinearIssue): IntakeIssue {\n return {\n id: issue.id,\n identifier: issue.identifier,\n title: issue.title,\n url: issue.url,\n author: issue.creator?.displayName ?? issue.creator?.name ?? null,\n state: issue.state.name,\n stateType: issue.state.type,\n priority: issue.priorityLabel,\n assignee: issue.assignee?.displayName ?? issue.assignee?.name ?? null,\n source: issue.team.key,\n labels: issue.labels.map(label => label.name),\n commentCount: null,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n };\n}\n\nfunction parseIssueDetail(issue: LinearIssue, comments: LinearComment[]): IntakeIssueDetail {\n return {\n ...parseIssue(issue),\n commentCount: comments.length,\n description: issue.description?.trim() ? issue.description : null,\n comments: comments.map(comment => ({\n author: comment.user?.displayName ?? comment.user?.name ?? null,\n body: comment.body,\n createdAt: comment.createdAt,\n })),\n };\n}\n\n/**\n * Deduplicate issues that surfaced from more than one selected source (a team\n * source and one of its projects both select the same issue). Keeps one entry\n * per Linear issue UUID.\n *\n * Tie-breaker — MOST-SPECIFIC-WINS: a project source beats a team source, so an\n * issue that belongs to a selected project is attributed to that project's\n * source (and therefore routes to the project's board). The team source covers\n * only the remainder — projectless issues and issues in projects that were not\n * separately selected. `selectionOrder` breaks a same-kind tie deterministically\n * by the order the sources were selected.\n *\n * This function is the single precedence point; change the comparison here to\n * change the routing policy.\n */\nfunction dedupeIssuesBySource<T extends { issue: { id: string }; sourceId: string }>(\n entries: T[],\n selectionOrder: string[],\n): T[] {\n const rank = new Map(selectionOrder.map((id, index) => [id, index]));\n const specificity = (sourceId: string): number => (parseSourceId(sourceId).kind === 'project' ? 0 : 1);\n const winners = new Map<string, T>();\n for (const entry of entries) {\n const existing = winners.get(entry.issue.id);\n if (!existing) {\n winners.set(entry.issue.id, entry);\n continue;\n }\n const bySpecificity = specificity(entry.sourceId) - specificity(existing.sourceId);\n const better =\n bySpecificity < 0 ||\n (bySpecificity === 0 &&\n (rank.get(entry.sourceId) ?? Number.MAX_SAFE_INTEGER) <\n (rank.get(existing.sourceId) ?? Number.MAX_SAFE_INTEGER));\n if (better) winners.set(entry.issue.id, entry);\n }\n // Preserve first-seen order of the surviving issues.\n const seen = new Set<string>();\n const ordered: T[] = [];\n for (const entry of entries) {\n if (seen.has(entry.issue.id)) continue;\n seen.add(entry.issue.id);\n ordered.push(winners.get(entry.issue.id)!);\n }\n return ordered;\n}\n\nexport function encodeSourceId(workspaceId: string, projectId: string): string {\n return `linear-project:${Buffer.from(JSON.stringify({ workspaceId, projectId })).toString('base64url')}`;\n}\n\nfunction decodeSourceId(sourceId: string): { workspaceId: string; projectId: string } {\n if (!sourceId.startsWith('linear-project:')) throw new Error('Linear project source id is invalid.');\n try {\n const parsed = JSON.parse(Buffer.from(sourceId.slice('linear-project:'.length), 'base64url').toString('utf8')) as {\n workspaceId?: unknown;\n projectId?: unknown;\n };\n if (typeof parsed.workspaceId !== 'string' || !parsed.workspaceId) throw new Error();\n if (typeof parsed.projectId !== 'string' || !parsed.projectId) throw new Error();\n return { workspaceId: parsed.workspaceId, projectId: parsed.projectId };\n } catch {\n throw new Error('Linear project source id is invalid.');\n }\n}\n\nconst TEAM_SOURCE_PREFIX = 'linear-team:';\n\nexport function encodeTeamSourceId(workspaceId: string, teamId: string): string {\n return `${TEAM_SOURCE_PREFIX}${Buffer.from(JSON.stringify({ workspaceId, teamId })).toString('base64url')}`;\n}\n\nexport function decodeTeamSourceId(sourceId: string): { workspaceId: string; teamId: string } {\n if (!sourceId.startsWith(TEAM_SOURCE_PREFIX)) throw new Error('Linear team source id is invalid.');\n try {\n const parsed = JSON.parse(Buffer.from(sourceId.slice(TEAM_SOURCE_PREFIX.length), 'base64url').toString('utf8')) as {\n workspaceId?: unknown;\n teamId?: unknown;\n };\n if (typeof parsed.workspaceId !== 'string' || !parsed.workspaceId) throw new Error();\n if (typeof parsed.teamId !== 'string' || !parsed.teamId) throw new Error();\n return { workspaceId: parsed.workspaceId, teamId: parsed.teamId };\n } catch {\n throw new Error('Linear team source id is invalid.');\n }\n}\n\n/**\n * A decoded intake source: either a Linear project or a whole Linear team.\n * Downstream code discriminates on `kind` to build the right issue-listing\n * filter and to apply most-specific-wins routing (project beats team).\n */\nexport type DecodedSource =\n { kind: 'project'; workspaceId: string; projectId: string } | { kind: 'team'; workspaceId: string; teamId: string };\n\n/** Discriminate any Linear source id by its prefix and decode it. */\nexport function parseSourceId(sourceId: string): DecodedSource {\n if (sourceId.startsWith(TEAM_SOURCE_PREFIX)) {\n return { kind: 'team', ...decodeTeamSourceId(sourceId) };\n }\n return { kind: 'project', ...decodeSourceId(sourceId) };\n}\n\nfunction normalizeLabels(labels: string[] | undefined): string[] {\n return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];\n}\n\ntype PlatformListCursor = { v: 1; sourceSet: string; cursors: Array<string | null> };\n\nfunction canonicalSourceIds(sourceIds: string[]): string[] {\n return [...new Set(sourceIds)].sort();\n}\n\nasync function linearSourceSetFingerprint(sourceIds: string[], attributionSourceIds: string[]): Promise<string> {\n const scope = {\n sourceIds: canonicalSourceIds(sourceIds),\n attributionSourceIds: canonicalSourceIds(attributionSourceIds),\n };\n const bytes = new TextEncoder().encode(JSON.stringify(scope));\n return Buffer.from(await globalThis.crypto.subtle.digest('SHA-256', bytes)).toString('base64url');\n}\n\nfunction invalidLinearCursor(): Error {\n return Object.assign(new Error('Linear cursor is invalid or stale.'), { code: 'invalid_cursor' as const });\n}\n\nasync function decodeCursor(\n cursor: string | undefined,\n sourceIds: string[],\n attributionSourceIds: string[],\n): Promise<Record<string, string | null | undefined>> {\n if (!cursor) return {};\n try {\n const parsed = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8')) as Partial<PlatformListCursor>;\n const canonical = canonicalSourceIds(sourceIds);\n if (\n parsed.v !== 1 ||\n parsed.sourceSet !== (await linearSourceSetFingerprint(sourceIds, attributionSourceIds)) ||\n !Array.isArray(parsed.cursors) ||\n parsed.cursors.length !== canonical.length ||\n !parsed.cursors.every(value => value === null || typeof value === 'string')\n ) {\n throw invalidLinearCursor();\n }\n return Object.fromEntries(canonical.map((sourceId, index) => [sourceId, parsed.cursors![index]]));\n } catch {\n throw invalidLinearCursor();\n }\n}\n\nasync function encodeCursor(\n state: Record<string, string | null>,\n sourceIds: string[],\n attributionSourceIds: string[],\n): Promise<string> {\n const canonical = canonicalSourceIds(sourceIds);\n const cursor: PlatformListCursor = {\n v: 1,\n sourceSet: await linearSourceSetFingerprint(sourceIds, attributionSourceIds),\n cursors: canonical.map(sourceId => state[sourceId] ?? null),\n };\n return Buffer.from(JSON.stringify(cursor)).toString('base64url');\n}\n\nfunction requireLinearConnection(connection: IntegrationConnection): void {\n if (connection.type !== 'oauth') {\n throw new Error('Linear capabilities require an OAuth connection.');\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return error instanceof PlatformApiError && error.status === 404;\n}\n\nfunction optionalPositiveIntegerEnv(name: string): number | undefined {\n const value = process.env[name]?.trim();\n if (!value) return undefined;\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed) || parsed <= 0) {\n throw new Error(`${name} must be a positive integer.`);\n }\n return parsed;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/slack/slack.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/slack/slack.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,6 @@ import { FactorySourceControlConflictError, createSourceControlSessionLookup, hy
|
|
|
6
6
|
import { resolveEmojiShortcodes } from "./emoji.js";
|
|
7
7
|
import { slackCommentSource } from "./feed-publisher.js";
|
|
8
8
|
import { ChannelSessionRejectedError } from "@mastra/core/channels";
|
|
9
|
-
import { randomUUID } from "crypto";
|
|
10
9
|
import { createSlackAdapter } from "@mastra/slack";
|
|
11
10
|
import { Actions, Card, CardText, LinkButton } from "chat";
|
|
12
11
|
//#region src/integrations/slack/slack.ts
|
|
@@ -239,7 +238,7 @@ function createChannelResourceIdResolver(deps) {
|
|
|
239
238
|
});
|
|
240
239
|
if (existing) return existing.sessionId;
|
|
241
240
|
return (await sourceControl.sessions.create({
|
|
242
|
-
sessionId: randomUUID(),
|
|
241
|
+
sessionId: globalThis.crypto.randomUUID(),
|
|
243
242
|
projectRepositoryId: repo.projectRepositoryId,
|
|
244
243
|
orgId,
|
|
245
244
|
userId: link.userId,
|