@stoneforge/quarry 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli/commands/auto-link-helper.d.ts +33 -0
- package/dist/cli/commands/auto-link-helper.d.ts.map +1 -0
- package/dist/cli/commands/auto-link-helper.js +73 -0
- package/dist/cli/commands/auto-link-helper.js.map +1 -0
- package/dist/cli/commands/crud.d.ts +1 -0
- package/dist/cli/commands/crud.d.ts.map +1 -1
- package/dist/cli/commands/crud.js +44 -5
- package/dist/cli/commands/crud.js.map +1 -1
- package/dist/cli/commands/external-sync.d.ts +17 -0
- package/dist/cli/commands/external-sync.d.ts.map +1 -0
- package/dist/cli/commands/external-sync.js +1647 -0
- package/dist/cli/commands/external-sync.js.map +1 -0
- package/dist/cli/runner.d.ts.map +1 -1
- package/dist/cli/runner.js +3 -0
- package/dist/cli/runner.js.map +1 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +28 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/defaults.d.ts +13 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +21 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/file.d.ts.map +1 -1
- package/dist/config/file.js +61 -0
- package/dist/config/file.js.map +1 -1
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.js.map +1 -1
- package/dist/config/merge.d.ts.map +1 -1
- package/dist/config/merge.js +46 -1
- package/dist/config/merge.js.map +1 -1
- package/dist/config/types.d.ts +63 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +30 -0
- package/dist/config/types.js.map +1 -1
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +51 -1
- package/dist/config/validation.js.map +1 -1
- package/dist/external-sync/adapters/task-sync-adapter.d.ts +177 -0
- package/dist/external-sync/adapters/task-sync-adapter.d.ts.map +1 -0
- package/dist/external-sync/adapters/task-sync-adapter.js +353 -0
- package/dist/external-sync/adapters/task-sync-adapter.js.map +1 -0
- package/dist/external-sync/auto-link.d.ts +66 -0
- package/dist/external-sync/auto-link.d.ts.map +1 -0
- package/dist/external-sync/auto-link.js +98 -0
- package/dist/external-sync/auto-link.js.map +1 -0
- package/dist/external-sync/conflict-resolver.d.ts +170 -0
- package/dist/external-sync/conflict-resolver.d.ts.map +1 -0
- package/dist/external-sync/conflict-resolver.js +580 -0
- package/dist/external-sync/conflict-resolver.js.map +1 -0
- package/dist/external-sync/index.d.ts +20 -0
- package/dist/external-sync/index.d.ts.map +1 -0
- package/dist/external-sync/index.js +20 -0
- package/dist/external-sync/index.js.map +1 -0
- package/dist/external-sync/provider-registry.d.ts +109 -0
- package/dist/external-sync/provider-registry.d.ts.map +1 -0
- package/dist/external-sync/provider-registry.js +188 -0
- package/dist/external-sync/provider-registry.js.map +1 -0
- package/dist/external-sync/providers/github/github-api.d.ts +271 -0
- package/dist/external-sync/providers/github/github-api.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-api.js +366 -0
- package/dist/external-sync/providers/github/github-api.js.map +1 -0
- package/dist/external-sync/providers/github/github-field-map.d.ts +76 -0
- package/dist/external-sync/providers/github/github-field-map.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-field-map.js +157 -0
- package/dist/external-sync/providers/github/github-field-map.js.map +1 -0
- package/dist/external-sync/providers/github/github-provider.d.ts +36 -0
- package/dist/external-sync/providers/github/github-provider.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-provider.js +212 -0
- package/dist/external-sync/providers/github/github-provider.js.map +1 -0
- package/dist/external-sync/providers/github/github-task-adapter.d.ts +135 -0
- package/dist/external-sync/providers/github/github-task-adapter.d.ts.map +1 -0
- package/dist/external-sync/providers/github/github-task-adapter.js +374 -0
- package/dist/external-sync/providers/github/github-task-adapter.js.map +1 -0
- package/dist/external-sync/providers/github/index.d.ts +12 -0
- package/dist/external-sync/providers/github/index.d.ts.map +1 -0
- package/dist/external-sync/providers/github/index.js +15 -0
- package/dist/external-sync/providers/github/index.js.map +1 -0
- package/dist/external-sync/providers/index.d.ts +9 -0
- package/dist/external-sync/providers/index.d.ts.map +1 -0
- package/dist/external-sync/providers/index.js +10 -0
- package/dist/external-sync/providers/index.js.map +1 -0
- package/dist/external-sync/providers/linear/index.d.ts +19 -0
- package/dist/external-sync/providers/linear/index.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/index.js +19 -0
- package/dist/external-sync/providers/linear/index.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-api.d.ts +252 -0
- package/dist/external-sync/providers/linear/linear-api.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-api.js +522 -0
- package/dist/external-sync/providers/linear/linear-api.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-field-map.d.ts +135 -0
- package/dist/external-sync/providers/linear/linear-field-map.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-field-map.js +338 -0
- package/dist/external-sync/providers/linear/linear-field-map.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-provider.d.ts +52 -0
- package/dist/external-sync/providers/linear/linear-provider.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-provider.js +169 -0
- package/dist/external-sync/providers/linear/linear-provider.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.d.ts +190 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.js +521 -0
- package/dist/external-sync/providers/linear/linear-task-adapter.js.map +1 -0
- package/dist/external-sync/providers/linear/linear-types.d.ts +114 -0
- package/dist/external-sync/providers/linear/linear-types.d.ts.map +1 -0
- package/dist/external-sync/providers/linear/linear-types.js +10 -0
- package/dist/external-sync/providers/linear/linear-types.js.map +1 -0
- package/dist/external-sync/sync-engine.d.ts +298 -0
- package/dist/external-sync/sync-engine.d.ts.map +1 -0
- package/dist/external-sync/sync-engine.js +785 -0
- package/dist/external-sync/sync-engine.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/services/inbox.js +1 -1
- package/dist/sync/hash.d.ts +5 -0
- package/dist/sync/hash.d.ts.map +1 -1
- package/dist/sync/hash.js +21 -2
- package/dist/sync/hash.js.map +1 -1
- package/package.json +11 -5
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear Task Sync Adapter
|
|
3
|
+
*
|
|
4
|
+
* Implements the TaskSyncAdapter interface for Linear issue operations.
|
|
5
|
+
* Maps between Stoneforge ExternalTask/ExternalTaskInput and Linear's
|
|
6
|
+
* GraphQL API using the LinearApiClient.
|
|
7
|
+
*
|
|
8
|
+
* Key design points:
|
|
9
|
+
* - Caches workflow states per team (fetched on first use)
|
|
10
|
+
* - Builds bidirectional lookup maps: stateTypeToStateId and stateIdToType
|
|
11
|
+
* - Refreshes state cache when a stateId lookup fails
|
|
12
|
+
* - Uses native Linear priority (0-4) instead of label-based priority
|
|
13
|
+
* - Maps status via workflow state TYPE, not state name
|
|
14
|
+
*/
|
|
15
|
+
import { createLinearFieldMapConfig, linearPriorityToStoneforge, stoneforgePriorityToLinear, linearStateTypeToStatusLabel, } from './linear-field-map.js';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Constants
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* The label name used to indicate a blocked task on Linear.
|
|
21
|
+
* Linear has no native blocked state — this label is added/removed
|
|
22
|
+
* by the adapter to signal blocked status.
|
|
23
|
+
*
|
|
24
|
+
* Added to ExternalTaskInput.labels by buildExternalLabels() when a task
|
|
25
|
+
* has status=blocked and the provider has no statusLabels config.
|
|
26
|
+
*/
|
|
27
|
+
const BLOCKED_LABEL = 'blocked';
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// LinearTaskAdapter
|
|
30
|
+
// ============================================================================
|
|
31
|
+
/**
|
|
32
|
+
* TaskSyncAdapter implementation for Linear.
|
|
33
|
+
*
|
|
34
|
+
* Provides bidirectional sync between Stoneforge tasks and Linear issues.
|
|
35
|
+
* Uses workflow state caching for efficient status mapping and handles
|
|
36
|
+
* Linear's native priority field directly (no label convention needed).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const client = new LinearApiClient({ apiKey: 'lin_api_...' });
|
|
41
|
+
* const adapter = new LinearTaskAdapter(client);
|
|
42
|
+
*
|
|
43
|
+
* // Fetch a single issue
|
|
44
|
+
* const issue = await adapter.getIssue('ENG', 'uuid-here');
|
|
45
|
+
*
|
|
46
|
+
* // List recent changes
|
|
47
|
+
* const issues = await adapter.listIssuesSince('ENG', '2024-01-01T00:00:00Z');
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export class LinearTaskAdapter {
|
|
51
|
+
api;
|
|
52
|
+
/** Cached workflow states keyed by team ID */
|
|
53
|
+
stateCacheByTeam = new Map();
|
|
54
|
+
/** Cached team lookups keyed by team key (e.g., "ENG") */
|
|
55
|
+
teamByKey = new Map();
|
|
56
|
+
/** Cached label name→ID lookup (workspace-level) */
|
|
57
|
+
labelsByName = new Map();
|
|
58
|
+
/** Whether labels have been fetched from the API */
|
|
59
|
+
labelsCached = false;
|
|
60
|
+
constructor(api) {
|
|
61
|
+
this.api = api;
|
|
62
|
+
}
|
|
63
|
+
// --------------------------------------------------------------------------
|
|
64
|
+
// TaskSyncAdapter Implementation
|
|
65
|
+
// --------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* Fetch a single Linear issue by external ID (UUID) and convert to ExternalTask.
|
|
68
|
+
*
|
|
69
|
+
* @param project - Team key (e.g., "ENG")
|
|
70
|
+
* @param externalId - Linear issue UUID
|
|
71
|
+
* @returns ExternalTask or null if not found
|
|
72
|
+
*/
|
|
73
|
+
async getIssue(project, externalId) {
|
|
74
|
+
const issue = await this.api.getIssue(externalId);
|
|
75
|
+
if (!issue) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return this.linearIssueToExternalTask(issue, project);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* List Linear issues updated since a given timestamp.
|
|
82
|
+
*
|
|
83
|
+
* @param project - Team key (e.g., "ENG")
|
|
84
|
+
* @param since - ISO 8601 timestamp
|
|
85
|
+
* @returns Array of ExternalTask
|
|
86
|
+
*/
|
|
87
|
+
async listIssuesSince(project, since) {
|
|
88
|
+
const issues = await this.api.listIssuesSince(project, since);
|
|
89
|
+
return issues.map((issue) => this.linearIssueToExternalTask(issue, project));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a new issue in Linear.
|
|
93
|
+
*
|
|
94
|
+
* Resolves the team key to a team ID, maps ExternalTaskInput fields to
|
|
95
|
+
* Linear mutation input (title, description, priority, stateId), and
|
|
96
|
+
* calls the API to create the issue.
|
|
97
|
+
*
|
|
98
|
+
* @param project - Team key (e.g., "ENG")
|
|
99
|
+
* @param issue - ExternalTaskInput with the fields to set
|
|
100
|
+
* @returns The created ExternalTask
|
|
101
|
+
*/
|
|
102
|
+
async createIssue(project, issue) {
|
|
103
|
+
// Resolve team key to team ID
|
|
104
|
+
const team = await this.resolveTeam(project);
|
|
105
|
+
// Build create input (handles state type mapping including blocked→started)
|
|
106
|
+
const input = await this.buildCreateInput(team, issue);
|
|
107
|
+
// Resolve ALL labels to Linear label IDs:
|
|
108
|
+
// - "blocked" label (special handling for blocked state)
|
|
109
|
+
// - sf:type:* labels (task type labels synced as Linear labels)
|
|
110
|
+
// - sf:priority:* labels (synced alongside native priority for lossless round-tripping)
|
|
111
|
+
// - sf:status:* labels (synced alongside native workflow states for lossless round-tripping)
|
|
112
|
+
// - User tags (non-prefixed labels synced as Linear labels)
|
|
113
|
+
const labelIds = await this.resolveInputLabelIds(team.id, issue.labels);
|
|
114
|
+
if (labelIds.length > 0) {
|
|
115
|
+
input.labelIds = labelIds;
|
|
116
|
+
}
|
|
117
|
+
// Create issue via API
|
|
118
|
+
const created = await this.api.createIssue(input);
|
|
119
|
+
return this.linearIssueToExternalTask(created, project);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Update an existing issue in Linear.
|
|
123
|
+
*
|
|
124
|
+
* Maps partial ExternalTaskInput to Linear mutation input and calls
|
|
125
|
+
* the API to update the issue.
|
|
126
|
+
*
|
|
127
|
+
* @param project - Team key (e.g., "ENG")
|
|
128
|
+
* @param externalId - Linear issue UUID
|
|
129
|
+
* @param updates - Partial ExternalTaskInput with fields to update
|
|
130
|
+
* @returns The updated ExternalTask
|
|
131
|
+
*/
|
|
132
|
+
async updateIssue(project, externalId, updates) {
|
|
133
|
+
// Resolve team for state mapping
|
|
134
|
+
const team = await this.resolveTeam(project);
|
|
135
|
+
// Build update input (handles state type mapping including blocked→started)
|
|
136
|
+
const input = await this.buildUpdateInput(team, updates);
|
|
137
|
+
// Compute the full set of label IDs for the update, comparing the desired
|
|
138
|
+
// labels against the current issue's labels. Only sends labelIds if the
|
|
139
|
+
// set actually changed (avoids unnecessary writes).
|
|
140
|
+
if (updates.labels !== undefined) {
|
|
141
|
+
const labelIds = await this.computeLabelIds(team.id, externalId, updates.labels);
|
|
142
|
+
if (labelIds !== undefined) {
|
|
143
|
+
input.labelIds = labelIds;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Update issue via API
|
|
147
|
+
const updated = await this.api.updateIssue(externalId, input);
|
|
148
|
+
return this.linearIssueToExternalTask(updated, project);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns the Linear-specific TaskFieldMapConfig.
|
|
152
|
+
*/
|
|
153
|
+
getFieldMapConfig() {
|
|
154
|
+
return createLinearFieldMapConfig();
|
|
155
|
+
}
|
|
156
|
+
// --------------------------------------------------------------------------
|
|
157
|
+
// Conversion: Linear Issue → ExternalTask
|
|
158
|
+
// --------------------------------------------------------------------------
|
|
159
|
+
/**
|
|
160
|
+
* Converts a Linear issue API response to the normalized ExternalTask format.
|
|
161
|
+
*
|
|
162
|
+
* Injects a synthetic sf:status:* label based on the workflow state type.
|
|
163
|
+
* This allows the generic field mapping system (stateToStatus) to extract
|
|
164
|
+
* granular statuses without the sync engine needing Linear-specific logic.
|
|
165
|
+
*/
|
|
166
|
+
linearIssueToExternalTask(issue, project) {
|
|
167
|
+
// Map state type to open/closed for ExternalTask's binary state
|
|
168
|
+
const stateType = issue.state.type;
|
|
169
|
+
const isCompleted = stateType === 'completed' || stateType === 'canceled';
|
|
170
|
+
// Collect labels as string names
|
|
171
|
+
const labels = issue.labels.nodes.map((label) => label.name);
|
|
172
|
+
// Inject a sf:status:* label based on workflow state type.
|
|
173
|
+
// This communicates the granular Linear state through the generic label-based
|
|
174
|
+
// field mapping system, keeping the sync engine provider-agnostic.
|
|
175
|
+
const statusLabel = linearStateTypeToStatusLabel(stateType);
|
|
176
|
+
labels.push(statusLabel);
|
|
177
|
+
// Build assignees list (Linear supports single assignee)
|
|
178
|
+
const assignees = [];
|
|
179
|
+
if (issue.assignee) {
|
|
180
|
+
assignees.push(issue.assignee.name);
|
|
181
|
+
}
|
|
182
|
+
// Store Linear-specific data in raw for lossless round-tripping
|
|
183
|
+
const raw = {
|
|
184
|
+
linearPriority: issue.priority,
|
|
185
|
+
linearStateType: stateType,
|
|
186
|
+
linearStateId: issue.state.id,
|
|
187
|
+
linearStateName: issue.state.name,
|
|
188
|
+
linearIdentifier: issue.identifier,
|
|
189
|
+
linearTeamKey: issue.team.key,
|
|
190
|
+
linearTeamId: issue.team.id,
|
|
191
|
+
};
|
|
192
|
+
// Include archived info if present
|
|
193
|
+
if (issue.archivedAt) {
|
|
194
|
+
raw.linearArchivedAt = issue.archivedAt;
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
externalId: issue.id,
|
|
198
|
+
url: issue.url,
|
|
199
|
+
provider: 'linear',
|
|
200
|
+
project,
|
|
201
|
+
title: issue.title,
|
|
202
|
+
body: issue.description ?? undefined,
|
|
203
|
+
state: isCompleted ? 'closed' : 'open',
|
|
204
|
+
labels,
|
|
205
|
+
assignees,
|
|
206
|
+
// Convert Linear native priority (0-4) to Stoneforge priority (1-5)
|
|
207
|
+
priority: linearPriorityToStoneforge(issue.priority),
|
|
208
|
+
createdAt: issue.createdAt,
|
|
209
|
+
updatedAt: issue.updatedAt,
|
|
210
|
+
closedAt: isCompleted ? issue.updatedAt : undefined,
|
|
211
|
+
raw,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// --------------------------------------------------------------------------
|
|
215
|
+
// Input Building: ExternalTaskInput → Linear API Input
|
|
216
|
+
// --------------------------------------------------------------------------
|
|
217
|
+
/**
|
|
218
|
+
* Builds a CreateIssueInput from an ExternalTaskInput.
|
|
219
|
+
*/
|
|
220
|
+
async buildCreateInput(team, issue) {
|
|
221
|
+
const input = {
|
|
222
|
+
teamId: team.id,
|
|
223
|
+
title: issue.title,
|
|
224
|
+
};
|
|
225
|
+
// Map description
|
|
226
|
+
if (issue.body) {
|
|
227
|
+
input.description = issue.body;
|
|
228
|
+
}
|
|
229
|
+
// Map state to workflow state ID.
|
|
230
|
+
// Use a richer mapping that accounts for blocked tasks: the "blocked"
|
|
231
|
+
// label in the input signals that the task is blocked and should map
|
|
232
|
+
// to the 'started' state type (not 'unstarted'), since a blocked task
|
|
233
|
+
// was actively worked on and got stuck.
|
|
234
|
+
if (issue.state) {
|
|
235
|
+
const isBlocked = issue.labels?.includes(BLOCKED_LABEL) ?? false;
|
|
236
|
+
let targetStateType;
|
|
237
|
+
if (issue.state === 'closed') {
|
|
238
|
+
targetStateType = 'completed';
|
|
239
|
+
}
|
|
240
|
+
else if (isBlocked) {
|
|
241
|
+
targetStateType = 'started';
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
targetStateType = 'unstarted';
|
|
245
|
+
}
|
|
246
|
+
const stateId = await this.resolveStateId(team.id, targetStateType);
|
|
247
|
+
if (stateId) {
|
|
248
|
+
input.stateId = stateId;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Map priority: convert Stoneforge priority (1-5) to Linear native priority (0-4).
|
|
252
|
+
// If no priority is provided, default to Linear 0 (No priority).
|
|
253
|
+
if (issue.priority !== undefined) {
|
|
254
|
+
input.priority = stoneforgePriorityToLinear(issue.priority);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
input.priority = 0; // Linear "No priority"
|
|
258
|
+
}
|
|
259
|
+
return input;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Builds an UpdateIssueInput from a partial ExternalTaskInput.
|
|
263
|
+
*/
|
|
264
|
+
async buildUpdateInput(team, updates) {
|
|
265
|
+
const input = {};
|
|
266
|
+
if (updates.title !== undefined) {
|
|
267
|
+
input.title = updates.title;
|
|
268
|
+
}
|
|
269
|
+
if (updates.body !== undefined) {
|
|
270
|
+
input.description = updates.body;
|
|
271
|
+
}
|
|
272
|
+
// Map state to workflow state ID.
|
|
273
|
+
// Use a richer mapping that accounts for blocked tasks: if the "blocked"
|
|
274
|
+
// label is in the update's labels, the task should map to 'started' state
|
|
275
|
+
// type (not 'unstarted'), since blocked tasks were in-progress and got stuck.
|
|
276
|
+
if (updates.state !== undefined) {
|
|
277
|
+
const isBlocked = updates.labels?.includes(BLOCKED_LABEL) ?? false;
|
|
278
|
+
let targetStateType;
|
|
279
|
+
if (updates.state === 'closed') {
|
|
280
|
+
targetStateType = 'completed';
|
|
281
|
+
}
|
|
282
|
+
else if (isBlocked) {
|
|
283
|
+
targetStateType = 'started';
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
targetStateType = 'unstarted';
|
|
287
|
+
}
|
|
288
|
+
const stateId = await this.resolveStateId(team.id, targetStateType);
|
|
289
|
+
if (stateId) {
|
|
290
|
+
input.stateId = stateId;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Map priority: convert Stoneforge priority (1-5) to Linear native priority (0-4)
|
|
294
|
+
if (updates.priority !== undefined) {
|
|
295
|
+
input.priority = stoneforgePriorityToLinear(updates.priority);
|
|
296
|
+
}
|
|
297
|
+
return input;
|
|
298
|
+
}
|
|
299
|
+
// --------------------------------------------------------------------------
|
|
300
|
+
// Workflow State Caching
|
|
301
|
+
// --------------------------------------------------------------------------
|
|
302
|
+
/**
|
|
303
|
+
* Resolves a team key (e.g., "ENG") to a LinearTeam object.
|
|
304
|
+
* Caches the team lookup.
|
|
305
|
+
*/
|
|
306
|
+
async resolveTeam(teamKey) {
|
|
307
|
+
// Check cache first
|
|
308
|
+
const cached = this.teamByKey.get(teamKey);
|
|
309
|
+
if (cached) {
|
|
310
|
+
return cached;
|
|
311
|
+
}
|
|
312
|
+
// Fetch all teams and find the matching one
|
|
313
|
+
const teams = await this.api.getTeams();
|
|
314
|
+
for (const team of teams) {
|
|
315
|
+
this.teamByKey.set(team.key, team);
|
|
316
|
+
}
|
|
317
|
+
const team = this.teamByKey.get(teamKey);
|
|
318
|
+
if (!team) {
|
|
319
|
+
throw new Error(`Linear team with key "${teamKey}" not found. Available teams: ${teams.map((t) => t.key).join(', ')}`);
|
|
320
|
+
}
|
|
321
|
+
return team;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Gets or creates the workflow state cache for a team.
|
|
325
|
+
* Fetches workflow states from the API on first use.
|
|
326
|
+
*/
|
|
327
|
+
async getStateCache(teamId) {
|
|
328
|
+
const cached = this.stateCacheByTeam.get(teamId);
|
|
329
|
+
if (cached) {
|
|
330
|
+
return cached;
|
|
331
|
+
}
|
|
332
|
+
return this.refreshStateCache(teamId);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Fetches workflow states from the API and rebuilds the cache.
|
|
336
|
+
*/
|
|
337
|
+
async refreshStateCache(teamId) {
|
|
338
|
+
const states = await this.api.getTeamWorkflowStates(teamId);
|
|
339
|
+
const stateTypeToStateId = new Map();
|
|
340
|
+
const stateIdToType = new Map();
|
|
341
|
+
for (const state of states) {
|
|
342
|
+
// For stateTypeToStateId, use the first state matching each type
|
|
343
|
+
if (!stateTypeToStateId.has(state.type)) {
|
|
344
|
+
stateTypeToStateId.set(state.type, state.id);
|
|
345
|
+
}
|
|
346
|
+
// For stateIdToType, map every state ID
|
|
347
|
+
stateIdToType.set(state.id, state.type);
|
|
348
|
+
}
|
|
349
|
+
const cache = {
|
|
350
|
+
teamId,
|
|
351
|
+
stateTypeToStateId,
|
|
352
|
+
stateIdToType,
|
|
353
|
+
states,
|
|
354
|
+
};
|
|
355
|
+
this.stateCacheByTeam.set(teamId, cache);
|
|
356
|
+
return cache;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Resolves a Linear workflow state type to a state ID.
|
|
360
|
+
* Uses the cached states, refreshing if the type is not found.
|
|
361
|
+
*/
|
|
362
|
+
async resolveStateId(teamId, stateType) {
|
|
363
|
+
// Try cached lookup
|
|
364
|
+
let cache = await this.getStateCache(teamId);
|
|
365
|
+
let stateId = cache.stateTypeToStateId.get(stateType);
|
|
366
|
+
if (stateId) {
|
|
367
|
+
return stateId;
|
|
368
|
+
}
|
|
369
|
+
// Cache miss — workflow states may have been modified. Refresh.
|
|
370
|
+
cache = await this.refreshStateCache(teamId);
|
|
371
|
+
stateId = cache.stateTypeToStateId.get(stateType);
|
|
372
|
+
return stateId;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Resolves a Linear state ID to a workflow state type.
|
|
376
|
+
* Uses the cached states, refreshing if the ID is not found.
|
|
377
|
+
*/
|
|
378
|
+
async resolveStateType(teamId, stateId) {
|
|
379
|
+
// Try cached lookup
|
|
380
|
+
let cache = await this.getStateCache(teamId);
|
|
381
|
+
let stateType = cache.stateIdToType.get(stateId);
|
|
382
|
+
if (stateType) {
|
|
383
|
+
return stateType;
|
|
384
|
+
}
|
|
385
|
+
// Cache miss — workflow states may have been modified. Refresh.
|
|
386
|
+
cache = await this.refreshStateCache(teamId);
|
|
387
|
+
stateType = cache.stateIdToType.get(stateId);
|
|
388
|
+
return stateType;
|
|
389
|
+
}
|
|
390
|
+
// --------------------------------------------------------------------------
|
|
391
|
+
// Label Management
|
|
392
|
+
// --------------------------------------------------------------------------
|
|
393
|
+
/**
|
|
394
|
+
* Filters input labels to only those that should be synced as Linear labels.
|
|
395
|
+
*
|
|
396
|
+
* All label types are now synced to Linear for lossless round-tripping:
|
|
397
|
+
* - sf:priority:* labels (synced alongside native priority for round-tripping)
|
|
398
|
+
* - sf:status:* labels (synced alongside native workflow states for round-tripping)
|
|
399
|
+
* - "blocked" label (synced as a Linear label)
|
|
400
|
+
* - sf:type:* labels (task type — Linear has no native type concept)
|
|
401
|
+
* - User tags (non-prefixed labels)
|
|
402
|
+
*
|
|
403
|
+
* This method exists as an extension point for future label filtering needs.
|
|
404
|
+
*/
|
|
405
|
+
filterSyncableLabels(labels) {
|
|
406
|
+
return labels.filter(() => {
|
|
407
|
+
return true;
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Resolves a label name to a Linear label ID.
|
|
412
|
+
* Uses the label cache, fetching from the API on first call.
|
|
413
|
+
* Creates the label if it doesn't exist.
|
|
414
|
+
*
|
|
415
|
+
* @param labelName - The label name to resolve
|
|
416
|
+
* @param teamId - Team ID to associate with a newly created label
|
|
417
|
+
* @returns The label ID, or undefined if resolution fails
|
|
418
|
+
*/
|
|
419
|
+
async resolveLabelId(labelName, teamId) {
|
|
420
|
+
// Check cache first
|
|
421
|
+
const cached = this.labelsByName.get(labelName);
|
|
422
|
+
if (cached) {
|
|
423
|
+
return cached;
|
|
424
|
+
}
|
|
425
|
+
// Fetch workspace labels if not already cached
|
|
426
|
+
if (!this.labelsCached) {
|
|
427
|
+
await this.refreshLabelCache();
|
|
428
|
+
}
|
|
429
|
+
// Check again after refresh
|
|
430
|
+
const labelId = this.labelsByName.get(labelName);
|
|
431
|
+
if (labelId) {
|
|
432
|
+
return labelId;
|
|
433
|
+
}
|
|
434
|
+
// Label doesn't exist — create it
|
|
435
|
+
try {
|
|
436
|
+
const created = await this.api.createLabel(labelName, teamId);
|
|
437
|
+
this.labelsByName.set(created.name, created.id);
|
|
438
|
+
return created.id;
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
// If label creation fails (e.g., permission issue), log but don't block
|
|
442
|
+
console.warn(`[LinearTaskAdapter] Failed to create "${labelName}" label in Linear.`);
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Resolves all syncable labels from an ExternalTaskInput to Linear label IDs.
|
|
448
|
+
* All labels (including sf:priority:* and sf:status:*) are synced to Linear
|
|
449
|
+
* for lossless round-tripping alongside native fields.
|
|
450
|
+
*
|
|
451
|
+
* @param teamId - Team ID for label creation
|
|
452
|
+
* @param labels - Input labels from ExternalTaskInput
|
|
453
|
+
* @returns Array of resolved Linear label IDs
|
|
454
|
+
*/
|
|
455
|
+
async resolveInputLabelIds(teamId, labels) {
|
|
456
|
+
if (!labels || labels.length === 0) {
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
const syncableLabels = this.filterSyncableLabels(labels);
|
|
460
|
+
if (syncableLabels.length === 0) {
|
|
461
|
+
return [];
|
|
462
|
+
}
|
|
463
|
+
const labelIds = [];
|
|
464
|
+
for (const labelName of syncableLabels) {
|
|
465
|
+
const labelId = await this.resolveLabelId(labelName, teamId);
|
|
466
|
+
if (labelId) {
|
|
467
|
+
labelIds.push(labelId);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return labelIds;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Computes the new labelIds for an issue update by comparing the desired
|
|
474
|
+
* labels against the current issue's labels on Linear.
|
|
475
|
+
*
|
|
476
|
+
* Handles all label types:
|
|
477
|
+
* - "blocked" label (added/removed based on blocked status)
|
|
478
|
+
* - sf:type:* labels (task type synced as Linear labels)
|
|
479
|
+
* - sf:priority:* labels (synced alongside native priority for lossless round-tripping)
|
|
480
|
+
* - sf:status:* labels (synced alongside native workflow states for lossless round-tripping)
|
|
481
|
+
* - User tags (synced as Linear labels)
|
|
482
|
+
*
|
|
483
|
+
* Returns undefined if no label change is needed (avoids unnecessary writes).
|
|
484
|
+
*
|
|
485
|
+
* @param teamId - Team ID (for label creation if needed)
|
|
486
|
+
* @param externalId - Issue UUID to fetch current labels from
|
|
487
|
+
* @param desiredLabels - The full set of desired labels from ExternalTaskInput
|
|
488
|
+
* @returns New labelIds array, or undefined if no change needed
|
|
489
|
+
*/
|
|
490
|
+
async computeLabelIds(teamId, externalId, desiredLabels) {
|
|
491
|
+
// Resolve desired labels to Linear label IDs
|
|
492
|
+
const desiredLabelIds = await this.resolveInputLabelIds(teamId, desiredLabels);
|
|
493
|
+
// Fetch current issue to get existing label IDs
|
|
494
|
+
const currentIssue = await this.api.getIssue(externalId);
|
|
495
|
+
if (!currentIssue) {
|
|
496
|
+
return desiredLabelIds.length > 0 ? desiredLabelIds : undefined;
|
|
497
|
+
}
|
|
498
|
+
const currentLabelIds = currentIssue.labels.nodes.map((l) => l.id);
|
|
499
|
+
// Compare sets: check if they're identical
|
|
500
|
+
const currentSet = new Set(currentLabelIds);
|
|
501
|
+
const desiredSet = new Set(desiredLabelIds);
|
|
502
|
+
if (currentSet.size === desiredSet.size &&
|
|
503
|
+
[...currentSet].every((id) => desiredSet.has(id))) {
|
|
504
|
+
// No change needed
|
|
505
|
+
return undefined;
|
|
506
|
+
}
|
|
507
|
+
return desiredLabelIds;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Fetches all workspace labels and populates the label cache.
|
|
511
|
+
*/
|
|
512
|
+
async refreshLabelCache() {
|
|
513
|
+
const labels = await this.api.getLabels();
|
|
514
|
+
this.labelsByName.clear();
|
|
515
|
+
for (const label of labels) {
|
|
516
|
+
this.labelsByName.set(label.name, label.id);
|
|
517
|
+
}
|
|
518
|
+
this.labelsCached = true;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
//# sourceMappingURL=linear-task-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-task-adapter.js","sourceRoot":"","sources":["../../../../src/external-sync/providers/linear/linear-task-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear API Response Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for Linear's GraphQL API responses.
|
|
5
|
+
* These types represent the subset of Linear's schema used by the sync provider.
|
|
6
|
+
*
|
|
7
|
+
* @see https://developers.linear.app/docs/graphql/working-with-the-graphql-api
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Linear issue representation matching the fields we query.
|
|
11
|
+
*
|
|
12
|
+
* Priority values:
|
|
13
|
+
* 0 = No priority
|
|
14
|
+
* 1 = Urgent
|
|
15
|
+
* 2 = High
|
|
16
|
+
* 3 = Medium
|
|
17
|
+
* 4 = Low
|
|
18
|
+
*/
|
|
19
|
+
export interface LinearIssue {
|
|
20
|
+
/** Unique UUID identifier */
|
|
21
|
+
readonly id: string;
|
|
22
|
+
/** Human-readable identifier (e.g., "ENG-123") */
|
|
23
|
+
readonly identifier: string;
|
|
24
|
+
/** Issue title */
|
|
25
|
+
readonly title: string;
|
|
26
|
+
/** Issue description (markdown) */
|
|
27
|
+
readonly description: string | null;
|
|
28
|
+
/** Priority level (0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low) */
|
|
29
|
+
readonly priority: number;
|
|
30
|
+
/** URL to view the issue in Linear */
|
|
31
|
+
readonly url: string;
|
|
32
|
+
/** Current workflow state */
|
|
33
|
+
readonly state: LinearWorkflowState;
|
|
34
|
+
/** Assigned user, or null if unassigned */
|
|
35
|
+
readonly assignee: LinearUser | null;
|
|
36
|
+
/** Team the issue belongs to */
|
|
37
|
+
readonly team: LinearTeam;
|
|
38
|
+
/** Labels attached to the issue */
|
|
39
|
+
readonly labels: {
|
|
40
|
+
readonly nodes: readonly LinearLabel[];
|
|
41
|
+
};
|
|
42
|
+
/** Creation timestamp (ISO 8601) */
|
|
43
|
+
readonly createdAt: string;
|
|
44
|
+
/** Last update timestamp (ISO 8601) */
|
|
45
|
+
readonly updatedAt: string;
|
|
46
|
+
/** Archive timestamp (ISO 8601), or null if not archived */
|
|
47
|
+
readonly archivedAt: string | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Linear workflow state.
|
|
51
|
+
*
|
|
52
|
+
* Each team has its own set of workflow states, but every state has a `type`
|
|
53
|
+
* that categorizes it into one of the standard lifecycle phases.
|
|
54
|
+
*/
|
|
55
|
+
export interface LinearWorkflowState {
|
|
56
|
+
/** Unique UUID identifier */
|
|
57
|
+
readonly id: string;
|
|
58
|
+
/** Display name (e.g., "In Progress", "Done") */
|
|
59
|
+
readonly name: string;
|
|
60
|
+
/** Workflow state category */
|
|
61
|
+
readonly type: 'triage' | 'backlog' | 'unstarted' | 'started' | 'completed' | 'canceled';
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Linear team representation.
|
|
65
|
+
*/
|
|
66
|
+
export interface LinearTeam {
|
|
67
|
+
/** Unique UUID identifier */
|
|
68
|
+
readonly id: string;
|
|
69
|
+
/** Short key used in issue identifiers (e.g., "ENG") */
|
|
70
|
+
readonly key: string;
|
|
71
|
+
/** Display name */
|
|
72
|
+
readonly name: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Linear user representation.
|
|
76
|
+
*/
|
|
77
|
+
export interface LinearUser {
|
|
78
|
+
/** Unique UUID identifier */
|
|
79
|
+
readonly id: string;
|
|
80
|
+
/** Display name */
|
|
81
|
+
readonly name: string;
|
|
82
|
+
/** Email address */
|
|
83
|
+
readonly email: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Linear label representation.
|
|
87
|
+
*/
|
|
88
|
+
export interface LinearLabel {
|
|
89
|
+
/** Unique UUID identifier */
|
|
90
|
+
readonly id: string;
|
|
91
|
+
/** Label name */
|
|
92
|
+
readonly name: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Relay-style page info for cursor pagination.
|
|
96
|
+
*/
|
|
97
|
+
export interface LinearPageInfo {
|
|
98
|
+
/** Whether there are more results after this page */
|
|
99
|
+
readonly hasNextPage: boolean;
|
|
100
|
+
/** Cursor to pass as `after` for the next page, or null if no more pages */
|
|
101
|
+
readonly endCursor: string | null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Generic Relay-style connection type for paginated results.
|
|
105
|
+
*
|
|
106
|
+
* Uses `nodes` syntax (simpler than `edges`) for direct access to items.
|
|
107
|
+
*/
|
|
108
|
+
export interface LinearConnection<T> {
|
|
109
|
+
/** The items in this page */
|
|
110
|
+
readonly nodes: readonly T[];
|
|
111
|
+
/** Pagination information */
|
|
112
|
+
readonly pageInfo: LinearPageInfo;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=linear-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-types.d.ts","sourceRoot":"","sources":["../../../../src/external-sync/providers/linear/linear-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kBAAkB;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mCAAmC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;KAAE,CAAC;IAC5D,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;CAC1F;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAMD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,6BAA6B;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;CACnC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear API Response Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for Linear's GraphQL API responses.
|
|
5
|
+
* These types represent the subset of Linear's schema used by the sync provider.
|
|
6
|
+
*
|
|
7
|
+
* @see https://developers.linear.app/docs/graphql/working-with-the-graphql-api
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=linear-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-types.js","sourceRoot":"","sources":["../../../../src/external-sync/providers/linear/linear-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|