offwatch 0.5.12 → 0.5.14
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 +132 -178
- package/bin/offwatch.js +6 -7
- package/lib/downloader.js +112 -0
- package/package.json +18 -11
- package/postinstall.js +18 -0
- package/src/__tests__/agent-jwt-env.test.ts +0 -79
- package/src/__tests__/allowed-hostname.test.ts +0 -80
- package/src/__tests__/auth-command-registration.test.ts +0 -16
- package/src/__tests__/board-auth.test.ts +0 -53
- package/src/__tests__/common.test.ts +0 -98
- package/src/__tests__/company-delete.test.ts +0 -95
- package/src/__tests__/company-import-export-e2e.test.ts +0 -502
- package/src/__tests__/company-import-url.test.ts +0 -74
- package/src/__tests__/company-import-zip.test.ts +0 -44
- package/src/__tests__/company.test.ts +0 -599
- package/src/__tests__/context.test.ts +0 -70
- package/src/__tests__/data-dir.test.ts +0 -79
- package/src/__tests__/doctor.test.ts +0 -102
- package/src/__tests__/feedback.test.ts +0 -177
- package/src/__tests__/helpers/embedded-postgres.ts +0 -6
- package/src/__tests__/helpers/zip.ts +0 -87
- package/src/__tests__/home-paths.test.ts +0 -44
- package/src/__tests__/http.test.ts +0 -106
- package/src/__tests__/network-bind.test.ts +0 -62
- package/src/__tests__/onboard.test.ts +0 -166
- package/src/__tests__/routines.test.ts +0 -249
- package/src/__tests__/telemetry.test.ts +0 -117
- package/src/__tests__/worktree-merge-history.test.ts +0 -492
- package/src/__tests__/worktree.test.ts +0 -982
- package/src/adapters/http/format-event.ts +0 -4
- package/src/adapters/http/index.ts +0 -7
- package/src/adapters/index.ts +0 -2
- package/src/adapters/process/format-event.ts +0 -4
- package/src/adapters/process/index.ts +0 -7
- package/src/adapters/registry.ts +0 -63
- package/src/checks/agent-jwt-secret-check.ts +0 -40
- package/src/checks/config-check.ts +0 -33
- package/src/checks/database-check.ts +0 -59
- package/src/checks/deployment-auth-check.ts +0 -88
- package/src/checks/index.ts +0 -18
- package/src/checks/llm-check.ts +0 -82
- package/src/checks/log-check.ts +0 -30
- package/src/checks/path-resolver.ts +0 -1
- package/src/checks/port-check.ts +0 -24
- package/src/checks/secrets-check.ts +0 -146
- package/src/checks/storage-check.ts +0 -51
- package/src/client/board-auth.ts +0 -282
- package/src/client/command-label.ts +0 -4
- package/src/client/context.ts +0 -175
- package/src/client/http.ts +0 -255
- package/src/commands/allowed-hostname.ts +0 -40
- package/src/commands/auth-bootstrap-ceo.ts +0 -138
- package/src/commands/client/activity.ts +0 -71
- package/src/commands/client/agent.ts +0 -315
- package/src/commands/client/approval.ts +0 -259
- package/src/commands/client/auth.ts +0 -113
- package/src/commands/client/common.ts +0 -221
- package/src/commands/client/company.ts +0 -1578
- package/src/commands/client/context.ts +0 -125
- package/src/commands/client/dashboard.ts +0 -34
- package/src/commands/client/feedback.ts +0 -645
- package/src/commands/client/issue.ts +0 -411
- package/src/commands/client/plugin.ts +0 -374
- package/src/commands/client/zip.ts +0 -129
- package/src/commands/configure.ts +0 -201
- package/src/commands/db-backup.ts +0 -102
- package/src/commands/doctor.ts +0 -203
- package/src/commands/env.ts +0 -411
- package/src/commands/heartbeat-run.ts +0 -344
- package/src/commands/onboard.ts +0 -692
- package/src/commands/routines.ts +0 -352
- package/src/commands/run.ts +0 -216
- package/src/commands/worktree-lib.ts +0 -279
- package/src/commands/worktree-merge-history-lib.ts +0 -764
- package/src/commands/worktree.ts +0 -2876
- package/src/config/data-dir.ts +0 -48
- package/src/config/env.ts +0 -125
- package/src/config/home.ts +0 -80
- package/src/config/hostnames.ts +0 -26
- package/src/config/schema.ts +0 -30
- package/src/config/secrets-key.ts +0 -48
- package/src/config/server-bind.ts +0 -183
- package/src/config/store.ts +0 -120
- package/src/index.ts +0 -182
- package/src/prompts/database.ts +0 -157
- package/src/prompts/llm.ts +0 -43
- package/src/prompts/logging.ts +0 -37
- package/src/prompts/secrets.ts +0 -99
- package/src/prompts/server.ts +0 -221
- package/src/prompts/storage.ts +0 -146
- package/src/telemetry.ts +0 -49
- package/src/utils/banner.ts +0 -24
- package/src/utils/net.ts +0 -18
- package/src/utils/path-resolver.ts +0 -25
- package/src/version.ts +0 -10
|
@@ -1,764 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
agents,
|
|
3
|
-
assets,
|
|
4
|
-
documentRevisions,
|
|
5
|
-
goals,
|
|
6
|
-
issueAttachments,
|
|
7
|
-
issueComments,
|
|
8
|
-
issueDocuments,
|
|
9
|
-
issues,
|
|
10
|
-
projects,
|
|
11
|
-
projectWorkspaces,
|
|
12
|
-
} from "@paperclipai/db";
|
|
13
|
-
|
|
14
|
-
type IssueRow = typeof issues.$inferSelect;
|
|
15
|
-
type CommentRow = typeof issueComments.$inferSelect;
|
|
16
|
-
type AgentRow = typeof agents.$inferSelect;
|
|
17
|
-
type ProjectRow = typeof projects.$inferSelect;
|
|
18
|
-
type ProjectWorkspaceRow = typeof projectWorkspaces.$inferSelect;
|
|
19
|
-
type GoalRow = typeof goals.$inferSelect;
|
|
20
|
-
type IssueDocumentLinkRow = typeof issueDocuments.$inferSelect;
|
|
21
|
-
type DocumentRevisionTableRow = typeof documentRevisions.$inferSelect;
|
|
22
|
-
type IssueAttachmentTableRow = typeof issueAttachments.$inferSelect;
|
|
23
|
-
type AssetRow = typeof assets.$inferSelect;
|
|
24
|
-
|
|
25
|
-
export const WORKTREE_MERGE_SCOPES = ["issues", "comments"] as const;
|
|
26
|
-
export type WorktreeMergeScope = (typeof WORKTREE_MERGE_SCOPES)[number];
|
|
27
|
-
|
|
28
|
-
export type ImportAdjustment =
|
|
29
|
-
| "clear_assignee_agent"
|
|
30
|
-
| "clear_project"
|
|
31
|
-
| "clear_project_workspace"
|
|
32
|
-
| "clear_goal"
|
|
33
|
-
| "clear_author_agent"
|
|
34
|
-
| "coerce_in_progress_to_todo"
|
|
35
|
-
| "clear_document_agent"
|
|
36
|
-
| "clear_document_revision_agent"
|
|
37
|
-
| "clear_attachment_agent";
|
|
38
|
-
|
|
39
|
-
export type IssueMergeAction = "skip_existing" | "insert";
|
|
40
|
-
export type CommentMergeAction = "skip_existing" | "skip_missing_parent" | "insert";
|
|
41
|
-
|
|
42
|
-
export type PlannedIssueInsert = {
|
|
43
|
-
source: IssueRow;
|
|
44
|
-
action: "insert";
|
|
45
|
-
previewIssueNumber: number;
|
|
46
|
-
previewIdentifier: string;
|
|
47
|
-
targetStatus: string;
|
|
48
|
-
targetAssigneeAgentId: string | null;
|
|
49
|
-
targetCreatedByAgentId: string | null;
|
|
50
|
-
targetProjectId: string | null;
|
|
51
|
-
targetProjectWorkspaceId: string | null;
|
|
52
|
-
targetGoalId: string | null;
|
|
53
|
-
projectResolution: "preserved" | "cleared" | "mapped" | "imported";
|
|
54
|
-
mappedProjectName: string | null;
|
|
55
|
-
adjustments: ImportAdjustment[];
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export type PlannedIssueSkip = {
|
|
59
|
-
source: IssueRow;
|
|
60
|
-
action: "skip_existing";
|
|
61
|
-
driftKeys: string[];
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type PlannedCommentInsert = {
|
|
65
|
-
source: CommentRow;
|
|
66
|
-
action: "insert";
|
|
67
|
-
targetAuthorAgentId: string | null;
|
|
68
|
-
adjustments: ImportAdjustment[];
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export type PlannedCommentSkip = {
|
|
72
|
-
source: CommentRow;
|
|
73
|
-
action: "skip_existing" | "skip_missing_parent";
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export type IssueDocumentRow = {
|
|
77
|
-
id: IssueDocumentLinkRow["id"];
|
|
78
|
-
companyId: IssueDocumentLinkRow["companyId"];
|
|
79
|
-
issueId: IssueDocumentLinkRow["issueId"];
|
|
80
|
-
documentId: IssueDocumentLinkRow["documentId"];
|
|
81
|
-
key: IssueDocumentLinkRow["key"];
|
|
82
|
-
linkCreatedAt: IssueDocumentLinkRow["createdAt"];
|
|
83
|
-
linkUpdatedAt: IssueDocumentLinkRow["updatedAt"];
|
|
84
|
-
title: string | null;
|
|
85
|
-
format: string;
|
|
86
|
-
latestBody: string;
|
|
87
|
-
latestRevisionId: string | null;
|
|
88
|
-
latestRevisionNumber: number;
|
|
89
|
-
createdByAgentId: string | null;
|
|
90
|
-
createdByUserId: string | null;
|
|
91
|
-
updatedByAgentId: string | null;
|
|
92
|
-
updatedByUserId: string | null;
|
|
93
|
-
documentCreatedAt: Date;
|
|
94
|
-
documentUpdatedAt: Date;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export type DocumentRevisionRow = {
|
|
98
|
-
id: DocumentRevisionTableRow["id"];
|
|
99
|
-
companyId: DocumentRevisionTableRow["companyId"];
|
|
100
|
-
documentId: DocumentRevisionTableRow["documentId"];
|
|
101
|
-
revisionNumber: DocumentRevisionTableRow["revisionNumber"];
|
|
102
|
-
body: DocumentRevisionTableRow["body"];
|
|
103
|
-
changeSummary: DocumentRevisionTableRow["changeSummary"];
|
|
104
|
-
createdByAgentId: string | null;
|
|
105
|
-
createdByUserId: string | null;
|
|
106
|
-
createdAt: Date;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
export type IssueAttachmentRow = {
|
|
110
|
-
id: IssueAttachmentTableRow["id"];
|
|
111
|
-
companyId: IssueAttachmentTableRow["companyId"];
|
|
112
|
-
issueId: IssueAttachmentTableRow["issueId"];
|
|
113
|
-
issueCommentId: IssueAttachmentTableRow["issueCommentId"];
|
|
114
|
-
assetId: IssueAttachmentTableRow["assetId"];
|
|
115
|
-
provider: AssetRow["provider"];
|
|
116
|
-
objectKey: AssetRow["objectKey"];
|
|
117
|
-
contentType: AssetRow["contentType"];
|
|
118
|
-
byteSize: AssetRow["byteSize"];
|
|
119
|
-
sha256: AssetRow["sha256"];
|
|
120
|
-
originalFilename: AssetRow["originalFilename"];
|
|
121
|
-
createdByAgentId: string | null;
|
|
122
|
-
createdByUserId: string | null;
|
|
123
|
-
assetCreatedAt: Date;
|
|
124
|
-
assetUpdatedAt: Date;
|
|
125
|
-
attachmentCreatedAt: Date;
|
|
126
|
-
attachmentUpdatedAt: Date;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
export type PlannedDocumentRevisionInsert = {
|
|
130
|
-
source: DocumentRevisionRow;
|
|
131
|
-
targetRevisionNumber: number;
|
|
132
|
-
targetCreatedByAgentId: string | null;
|
|
133
|
-
adjustments: ImportAdjustment[];
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
export type PlannedIssueDocumentInsert = {
|
|
137
|
-
source: IssueDocumentRow;
|
|
138
|
-
action: "insert";
|
|
139
|
-
targetCreatedByAgentId: string | null;
|
|
140
|
-
targetUpdatedByAgentId: string | null;
|
|
141
|
-
latestRevisionId: string | null;
|
|
142
|
-
latestRevisionNumber: number;
|
|
143
|
-
revisionsToInsert: PlannedDocumentRevisionInsert[];
|
|
144
|
-
adjustments: ImportAdjustment[];
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
export type PlannedIssueDocumentMerge = {
|
|
148
|
-
source: IssueDocumentRow;
|
|
149
|
-
action: "merge_existing";
|
|
150
|
-
targetCreatedByAgentId: string | null;
|
|
151
|
-
targetUpdatedByAgentId: string | null;
|
|
152
|
-
latestRevisionId: string | null;
|
|
153
|
-
latestRevisionNumber: number;
|
|
154
|
-
revisionsToInsert: PlannedDocumentRevisionInsert[];
|
|
155
|
-
adjustments: ImportAdjustment[];
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
export type PlannedIssueDocumentSkip = {
|
|
159
|
-
source: IssueDocumentRow;
|
|
160
|
-
action: "skip_existing" | "skip_missing_parent" | "skip_conflicting_key";
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
export type PlannedAttachmentInsert = {
|
|
164
|
-
source: IssueAttachmentRow;
|
|
165
|
-
action: "insert";
|
|
166
|
-
targetIssueCommentId: string | null;
|
|
167
|
-
targetCreatedByAgentId: string | null;
|
|
168
|
-
adjustments: ImportAdjustment[];
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
export type PlannedAttachmentSkip = {
|
|
172
|
-
source: IssueAttachmentRow;
|
|
173
|
-
action: "skip_existing" | "skip_missing_parent";
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
export type PlannedProjectImport = {
|
|
177
|
-
source: ProjectRow;
|
|
178
|
-
targetLeadAgentId: string | null;
|
|
179
|
-
targetGoalId: string | null;
|
|
180
|
-
workspaces: ProjectWorkspaceRow[];
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
export type WorktreeMergePlan = {
|
|
184
|
-
companyId: string;
|
|
185
|
-
companyName: string;
|
|
186
|
-
issuePrefix: string;
|
|
187
|
-
previewIssueCounterStart: number;
|
|
188
|
-
scopes: WorktreeMergeScope[];
|
|
189
|
-
projectImports: PlannedProjectImport[];
|
|
190
|
-
issuePlans: Array<PlannedIssueInsert | PlannedIssueSkip>;
|
|
191
|
-
commentPlans: Array<PlannedCommentInsert | PlannedCommentSkip>;
|
|
192
|
-
documentPlans: Array<PlannedIssueDocumentInsert | PlannedIssueDocumentMerge | PlannedIssueDocumentSkip>;
|
|
193
|
-
attachmentPlans: Array<PlannedAttachmentInsert | PlannedAttachmentSkip>;
|
|
194
|
-
counts: {
|
|
195
|
-
projectsToImport: number;
|
|
196
|
-
issuesToInsert: number;
|
|
197
|
-
issuesExisting: number;
|
|
198
|
-
issueDrift: number;
|
|
199
|
-
commentsToInsert: number;
|
|
200
|
-
commentsExisting: number;
|
|
201
|
-
commentsMissingParent: number;
|
|
202
|
-
documentsToInsert: number;
|
|
203
|
-
documentsToMerge: number;
|
|
204
|
-
documentsExisting: number;
|
|
205
|
-
documentsConflictingKey: number;
|
|
206
|
-
documentsMissingParent: number;
|
|
207
|
-
documentRevisionsToInsert: number;
|
|
208
|
-
attachmentsToInsert: number;
|
|
209
|
-
attachmentsExisting: number;
|
|
210
|
-
attachmentsMissingParent: number;
|
|
211
|
-
};
|
|
212
|
-
adjustments: Record<ImportAdjustment, number>;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
function compareIssueCoreFields(source: IssueRow, target: IssueRow): string[] {
|
|
216
|
-
const driftKeys: string[] = [];
|
|
217
|
-
if (source.title !== target.title) driftKeys.push("title");
|
|
218
|
-
if ((source.description ?? null) !== (target.description ?? null)) driftKeys.push("description");
|
|
219
|
-
if (source.status !== target.status) driftKeys.push("status");
|
|
220
|
-
if (source.priority !== target.priority) driftKeys.push("priority");
|
|
221
|
-
if ((source.parentId ?? null) !== (target.parentId ?? null)) driftKeys.push("parentId");
|
|
222
|
-
if ((source.projectId ?? null) !== (target.projectId ?? null)) driftKeys.push("projectId");
|
|
223
|
-
if ((source.projectWorkspaceId ?? null) !== (target.projectWorkspaceId ?? null)) driftKeys.push("projectWorkspaceId");
|
|
224
|
-
if ((source.goalId ?? null) !== (target.goalId ?? null)) driftKeys.push("goalId");
|
|
225
|
-
if ((source.assigneeAgentId ?? null) !== (target.assigneeAgentId ?? null)) driftKeys.push("assigneeAgentId");
|
|
226
|
-
if ((source.assigneeUserId ?? null) !== (target.assigneeUserId ?? null)) driftKeys.push("assigneeUserId");
|
|
227
|
-
return driftKeys;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function incrementAdjustment(
|
|
231
|
-
counts: Record<ImportAdjustment, number>,
|
|
232
|
-
adjustment: ImportAdjustment,
|
|
233
|
-
): void {
|
|
234
|
-
counts[adjustment] += 1;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function groupBy<T>(rows: T[], keyFor: (row: T) => string): Map<string, T[]> {
|
|
238
|
-
const out = new Map<string, T[]>();
|
|
239
|
-
for (const row of rows) {
|
|
240
|
-
const key = keyFor(row);
|
|
241
|
-
const existing = out.get(key);
|
|
242
|
-
if (existing) {
|
|
243
|
-
existing.push(row);
|
|
244
|
-
} else {
|
|
245
|
-
out.set(key, [row]);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return out;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function sameDate(left: Date, right: Date): boolean {
|
|
252
|
-
return left.getTime() === right.getTime();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function sortDocumentRows(rows: IssueDocumentRow[]): IssueDocumentRow[] {
|
|
256
|
-
return [...rows].sort((left, right) => {
|
|
257
|
-
const createdDelta = left.documentCreatedAt.getTime() - right.documentCreatedAt.getTime();
|
|
258
|
-
if (createdDelta !== 0) return createdDelta;
|
|
259
|
-
const linkDelta = left.linkCreatedAt.getTime() - right.linkCreatedAt.getTime();
|
|
260
|
-
if (linkDelta !== 0) return linkDelta;
|
|
261
|
-
return left.documentId.localeCompare(right.documentId);
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function sortDocumentRevisions(rows: DocumentRevisionRow[]): DocumentRevisionRow[] {
|
|
266
|
-
return [...rows].sort((left, right) => {
|
|
267
|
-
const revisionDelta = left.revisionNumber - right.revisionNumber;
|
|
268
|
-
if (revisionDelta !== 0) return revisionDelta;
|
|
269
|
-
const createdDelta = left.createdAt.getTime() - right.createdAt.getTime();
|
|
270
|
-
if (createdDelta !== 0) return createdDelta;
|
|
271
|
-
return left.id.localeCompare(right.id);
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function sortAttachments(rows: IssueAttachmentRow[]): IssueAttachmentRow[] {
|
|
276
|
-
return [...rows].sort((left, right) => {
|
|
277
|
-
const createdDelta = left.attachmentCreatedAt.getTime() - right.attachmentCreatedAt.getTime();
|
|
278
|
-
if (createdDelta !== 0) return createdDelta;
|
|
279
|
-
return left.id.localeCompare(right.id);
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function sortIssuesForImport(sourceIssues: IssueRow[]): IssueRow[] {
|
|
284
|
-
const byId = new Map(sourceIssues.map((issue) => [issue.id, issue]));
|
|
285
|
-
const memoDepth = new Map<string, number>();
|
|
286
|
-
|
|
287
|
-
const depthFor = (issue: IssueRow, stack = new Set<string>()): number => {
|
|
288
|
-
const memoized = memoDepth.get(issue.id);
|
|
289
|
-
if (memoized !== undefined) return memoized;
|
|
290
|
-
if (!issue.parentId) {
|
|
291
|
-
memoDepth.set(issue.id, 0);
|
|
292
|
-
return 0;
|
|
293
|
-
}
|
|
294
|
-
if (stack.has(issue.id)) {
|
|
295
|
-
memoDepth.set(issue.id, 0);
|
|
296
|
-
return 0;
|
|
297
|
-
}
|
|
298
|
-
const parent = byId.get(issue.parentId);
|
|
299
|
-
if (!parent) {
|
|
300
|
-
memoDepth.set(issue.id, 0);
|
|
301
|
-
return 0;
|
|
302
|
-
}
|
|
303
|
-
stack.add(issue.id);
|
|
304
|
-
const depth = depthFor(parent, stack) + 1;
|
|
305
|
-
stack.delete(issue.id);
|
|
306
|
-
memoDepth.set(issue.id, depth);
|
|
307
|
-
return depth;
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
return [...sourceIssues].sort((left, right) => {
|
|
311
|
-
const depthDelta = depthFor(left) - depthFor(right);
|
|
312
|
-
if (depthDelta !== 0) return depthDelta;
|
|
313
|
-
const createdDelta = left.createdAt.getTime() - right.createdAt.getTime();
|
|
314
|
-
if (createdDelta !== 0) return createdDelta;
|
|
315
|
-
return left.id.localeCompare(right.id);
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
export function parseWorktreeMergeScopes(rawValue: string | undefined): WorktreeMergeScope[] {
|
|
320
|
-
if (!rawValue || rawValue.trim().length === 0) {
|
|
321
|
-
return ["issues", "comments"];
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const parsed = rawValue
|
|
325
|
-
.split(",")
|
|
326
|
-
.map((value) => value.trim().toLowerCase())
|
|
327
|
-
.filter((value): value is WorktreeMergeScope =>
|
|
328
|
-
(WORKTREE_MERGE_SCOPES as readonly string[]).includes(value),
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
if (parsed.length === 0) {
|
|
332
|
-
throw new Error(
|
|
333
|
-
`Invalid scope "${rawValue}". Expected a comma-separated list of: ${WORKTREE_MERGE_SCOPES.join(", ")}.`,
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return [...new Set(parsed)];
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export function buildWorktreeMergePlan(input: {
|
|
341
|
-
companyId: string;
|
|
342
|
-
companyName: string;
|
|
343
|
-
issuePrefix: string;
|
|
344
|
-
previewIssueCounterStart: number;
|
|
345
|
-
scopes: WorktreeMergeScope[];
|
|
346
|
-
sourceIssues: IssueRow[];
|
|
347
|
-
targetIssues: IssueRow[];
|
|
348
|
-
sourceComments: CommentRow[];
|
|
349
|
-
targetComments: CommentRow[];
|
|
350
|
-
sourceProjects?: ProjectRow[];
|
|
351
|
-
sourceProjectWorkspaces?: ProjectWorkspaceRow[];
|
|
352
|
-
sourceDocuments?: IssueDocumentRow[];
|
|
353
|
-
targetDocuments?: IssueDocumentRow[];
|
|
354
|
-
sourceDocumentRevisions?: DocumentRevisionRow[];
|
|
355
|
-
targetDocumentRevisions?: DocumentRevisionRow[];
|
|
356
|
-
sourceAttachments?: IssueAttachmentRow[];
|
|
357
|
-
targetAttachments?: IssueAttachmentRow[];
|
|
358
|
-
targetAgents: AgentRow[];
|
|
359
|
-
targetProjects: ProjectRow[];
|
|
360
|
-
targetProjectWorkspaces: ProjectWorkspaceRow[];
|
|
361
|
-
targetGoals: GoalRow[];
|
|
362
|
-
importProjectIds?: Iterable<string>;
|
|
363
|
-
projectIdOverrides?: Record<string, string | null | undefined>;
|
|
364
|
-
}): WorktreeMergePlan {
|
|
365
|
-
const targetIssuesById = new Map(input.targetIssues.map((issue) => [issue.id, issue]));
|
|
366
|
-
const targetCommentIds = new Set(input.targetComments.map((comment) => comment.id));
|
|
367
|
-
const targetAgentIds = new Set(input.targetAgents.map((agent) => agent.id));
|
|
368
|
-
const targetProjectIds = new Set(input.targetProjects.map((project) => project.id));
|
|
369
|
-
const targetProjectsById = new Map(input.targetProjects.map((project) => [project.id, project]));
|
|
370
|
-
const targetProjectWorkspaceIds = new Set(input.targetProjectWorkspaces.map((workspace) => workspace.id));
|
|
371
|
-
const targetGoalIds = new Set(input.targetGoals.map((goal) => goal.id));
|
|
372
|
-
const sourceProjectsById = new Map((input.sourceProjects ?? []).map((project) => [project.id, project]));
|
|
373
|
-
const sourceProjectWorkspaces = input.sourceProjectWorkspaces ?? [];
|
|
374
|
-
const sourceProjectWorkspacesByProjectId = groupBy(sourceProjectWorkspaces, (workspace) => workspace.projectId);
|
|
375
|
-
const importProjectIds = new Set(input.importProjectIds ?? []);
|
|
376
|
-
const scopes = new Set(input.scopes);
|
|
377
|
-
|
|
378
|
-
const adjustmentCounts: Record<ImportAdjustment, number> = {
|
|
379
|
-
clear_assignee_agent: 0,
|
|
380
|
-
clear_project: 0,
|
|
381
|
-
clear_project_workspace: 0,
|
|
382
|
-
clear_goal: 0,
|
|
383
|
-
clear_author_agent: 0,
|
|
384
|
-
coerce_in_progress_to_todo: 0,
|
|
385
|
-
clear_document_agent: 0,
|
|
386
|
-
clear_document_revision_agent: 0,
|
|
387
|
-
clear_attachment_agent: 0,
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
const projectImports: PlannedProjectImport[] = [];
|
|
391
|
-
for (const projectId of importProjectIds) {
|
|
392
|
-
if (targetProjectIds.has(projectId)) continue;
|
|
393
|
-
const sourceProject = sourceProjectsById.get(projectId);
|
|
394
|
-
if (!sourceProject) continue;
|
|
395
|
-
projectImports.push({
|
|
396
|
-
source: sourceProject,
|
|
397
|
-
targetLeadAgentId:
|
|
398
|
-
sourceProject.leadAgentId && targetAgentIds.has(sourceProject.leadAgentId)
|
|
399
|
-
? sourceProject.leadAgentId
|
|
400
|
-
: null,
|
|
401
|
-
targetGoalId:
|
|
402
|
-
sourceProject.goalId && targetGoalIds.has(sourceProject.goalId)
|
|
403
|
-
? sourceProject.goalId
|
|
404
|
-
: null,
|
|
405
|
-
workspaces: [...(sourceProjectWorkspacesByProjectId.get(projectId) ?? [])].sort((left, right) => {
|
|
406
|
-
const primaryDelta = Number(right.isPrimary) - Number(left.isPrimary);
|
|
407
|
-
if (primaryDelta !== 0) return primaryDelta;
|
|
408
|
-
const createdDelta = left.createdAt.getTime() - right.createdAt.getTime();
|
|
409
|
-
if (createdDelta !== 0) return createdDelta;
|
|
410
|
-
return left.id.localeCompare(right.id);
|
|
411
|
-
}),
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
const importedProjectWorkspaceIds = new Set(
|
|
415
|
-
projectImports.flatMap((project) => project.workspaces.map((workspace) => workspace.id)),
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
const issuePlans: Array<PlannedIssueInsert | PlannedIssueSkip> = [];
|
|
419
|
-
let nextPreviewIssueNumber = input.previewIssueCounterStart;
|
|
420
|
-
for (const issue of sortIssuesForImport(input.sourceIssues)) {
|
|
421
|
-
const existing = targetIssuesById.get(issue.id);
|
|
422
|
-
if (existing) {
|
|
423
|
-
issuePlans.push({
|
|
424
|
-
source: issue,
|
|
425
|
-
action: "skip_existing",
|
|
426
|
-
driftKeys: compareIssueCoreFields(issue, existing),
|
|
427
|
-
});
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
nextPreviewIssueNumber += 1;
|
|
432
|
-
const adjustments: ImportAdjustment[] = [];
|
|
433
|
-
const targetAssigneeAgentId =
|
|
434
|
-
issue.assigneeAgentId && targetAgentIds.has(issue.assigneeAgentId) ? issue.assigneeAgentId : null;
|
|
435
|
-
if (issue.assigneeAgentId && !targetAssigneeAgentId) {
|
|
436
|
-
adjustments.push("clear_assignee_agent");
|
|
437
|
-
incrementAdjustment(adjustmentCounts, "clear_assignee_agent");
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
const targetCreatedByAgentId =
|
|
441
|
-
issue.createdByAgentId && targetAgentIds.has(issue.createdByAgentId) ? issue.createdByAgentId : null;
|
|
442
|
-
|
|
443
|
-
let targetProjectId =
|
|
444
|
-
issue.projectId && targetProjectIds.has(issue.projectId) ? issue.projectId : null;
|
|
445
|
-
let projectResolution: PlannedIssueInsert["projectResolution"] = targetProjectId ? "preserved" : "cleared";
|
|
446
|
-
let mappedProjectName: string | null = null;
|
|
447
|
-
const overrideProjectId =
|
|
448
|
-
issue.projectId && input.projectIdOverrides
|
|
449
|
-
? input.projectIdOverrides[issue.projectId] ?? null
|
|
450
|
-
: null;
|
|
451
|
-
if (!targetProjectId && overrideProjectId && targetProjectIds.has(overrideProjectId)) {
|
|
452
|
-
targetProjectId = overrideProjectId;
|
|
453
|
-
projectResolution = "mapped";
|
|
454
|
-
mappedProjectName = targetProjectsById.get(overrideProjectId)?.name ?? null;
|
|
455
|
-
}
|
|
456
|
-
if (!targetProjectId && issue.projectId && importProjectIds.has(issue.projectId)) {
|
|
457
|
-
const sourceProject = sourceProjectsById.get(issue.projectId);
|
|
458
|
-
if (sourceProject) {
|
|
459
|
-
targetProjectId = sourceProject.id;
|
|
460
|
-
projectResolution = "imported";
|
|
461
|
-
mappedProjectName = sourceProject.name;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
if (issue.projectId && !targetProjectId) {
|
|
465
|
-
adjustments.push("clear_project");
|
|
466
|
-
incrementAdjustment(adjustmentCounts, "clear_project");
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const targetProjectWorkspaceId =
|
|
470
|
-
targetProjectId
|
|
471
|
-
&& targetProjectId === issue.projectId
|
|
472
|
-
&& issue.projectWorkspaceId
|
|
473
|
-
&& (targetProjectWorkspaceIds.has(issue.projectWorkspaceId)
|
|
474
|
-
|| importedProjectWorkspaceIds.has(issue.projectWorkspaceId))
|
|
475
|
-
? issue.projectWorkspaceId
|
|
476
|
-
: null;
|
|
477
|
-
if (issue.projectWorkspaceId && !targetProjectWorkspaceId) {
|
|
478
|
-
adjustments.push("clear_project_workspace");
|
|
479
|
-
incrementAdjustment(adjustmentCounts, "clear_project_workspace");
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const targetGoalId =
|
|
483
|
-
issue.goalId && targetGoalIds.has(issue.goalId) ? issue.goalId : null;
|
|
484
|
-
if (issue.goalId && !targetGoalId) {
|
|
485
|
-
adjustments.push("clear_goal");
|
|
486
|
-
incrementAdjustment(adjustmentCounts, "clear_goal");
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
let targetStatus = issue.status;
|
|
490
|
-
if (
|
|
491
|
-
targetStatus === "in_progress"
|
|
492
|
-
&& !targetAssigneeAgentId
|
|
493
|
-
&& !(issue.assigneeUserId && issue.assigneeUserId.trim().length > 0)
|
|
494
|
-
) {
|
|
495
|
-
targetStatus = "todo";
|
|
496
|
-
adjustments.push("coerce_in_progress_to_todo");
|
|
497
|
-
incrementAdjustment(adjustmentCounts, "coerce_in_progress_to_todo");
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
issuePlans.push({
|
|
501
|
-
source: issue,
|
|
502
|
-
action: "insert",
|
|
503
|
-
previewIssueNumber: nextPreviewIssueNumber,
|
|
504
|
-
previewIdentifier: `${input.issuePrefix}-${nextPreviewIssueNumber}`,
|
|
505
|
-
targetStatus,
|
|
506
|
-
targetAssigneeAgentId,
|
|
507
|
-
targetCreatedByAgentId,
|
|
508
|
-
targetProjectId,
|
|
509
|
-
targetProjectWorkspaceId,
|
|
510
|
-
targetGoalId,
|
|
511
|
-
projectResolution,
|
|
512
|
-
mappedProjectName,
|
|
513
|
-
adjustments,
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const issueIdsAvailableAfterImport = new Set<string>([
|
|
518
|
-
...input.targetIssues.map((issue) => issue.id),
|
|
519
|
-
...issuePlans.filter((plan): plan is PlannedIssueInsert => plan.action === "insert").map((plan) => plan.source.id),
|
|
520
|
-
]);
|
|
521
|
-
|
|
522
|
-
const commentPlans: Array<PlannedCommentInsert | PlannedCommentSkip> = [];
|
|
523
|
-
if (scopes.has("comments")) {
|
|
524
|
-
const sortedComments = [...input.sourceComments].sort((left, right) => {
|
|
525
|
-
const createdDelta = left.createdAt.getTime() - right.createdAt.getTime();
|
|
526
|
-
if (createdDelta !== 0) return createdDelta;
|
|
527
|
-
return left.id.localeCompare(right.id);
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
for (const comment of sortedComments) {
|
|
531
|
-
if (targetCommentIds.has(comment.id)) {
|
|
532
|
-
commentPlans.push({ source: comment, action: "skip_existing" });
|
|
533
|
-
continue;
|
|
534
|
-
}
|
|
535
|
-
if (!issueIdsAvailableAfterImport.has(comment.issueId)) {
|
|
536
|
-
commentPlans.push({ source: comment, action: "skip_missing_parent" });
|
|
537
|
-
continue;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const adjustments: ImportAdjustment[] = [];
|
|
541
|
-
const targetAuthorAgentId =
|
|
542
|
-
comment.authorAgentId && targetAgentIds.has(comment.authorAgentId) ? comment.authorAgentId : null;
|
|
543
|
-
if (comment.authorAgentId && !targetAuthorAgentId) {
|
|
544
|
-
adjustments.push("clear_author_agent");
|
|
545
|
-
incrementAdjustment(adjustmentCounts, "clear_author_agent");
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
commentPlans.push({
|
|
549
|
-
source: comment,
|
|
550
|
-
action: "insert",
|
|
551
|
-
targetAuthorAgentId,
|
|
552
|
-
adjustments,
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
const sourceDocuments = input.sourceDocuments ?? [];
|
|
558
|
-
const targetDocuments = input.targetDocuments ?? [];
|
|
559
|
-
const sourceDocumentRevisions = input.sourceDocumentRevisions ?? [];
|
|
560
|
-
const targetDocumentRevisions = input.targetDocumentRevisions ?? [];
|
|
561
|
-
|
|
562
|
-
const targetDocumentsById = new Map(targetDocuments.map((document) => [document.documentId, document]));
|
|
563
|
-
const targetDocumentsByIssueKey = new Map(targetDocuments.map((document) => [`${document.issueId}:${document.key}`, document]));
|
|
564
|
-
const sourceRevisionsByDocumentId = groupBy(sourceDocumentRevisions, (revision) => revision.documentId);
|
|
565
|
-
const targetRevisionsByDocumentId = groupBy(targetDocumentRevisions, (revision) => revision.documentId);
|
|
566
|
-
const commentIdsAvailableAfterImport = new Set<string>([
|
|
567
|
-
...input.targetComments.map((comment) => comment.id),
|
|
568
|
-
...commentPlans.filter((plan): plan is PlannedCommentInsert => plan.action === "insert").map((plan) => plan.source.id),
|
|
569
|
-
]);
|
|
570
|
-
|
|
571
|
-
const documentPlans: Array<PlannedIssueDocumentInsert | PlannedIssueDocumentMerge | PlannedIssueDocumentSkip> = [];
|
|
572
|
-
for (const document of sortDocumentRows(sourceDocuments)) {
|
|
573
|
-
if (!issueIdsAvailableAfterImport.has(document.issueId)) {
|
|
574
|
-
documentPlans.push({ source: document, action: "skip_missing_parent" });
|
|
575
|
-
continue;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
const existingDocument = targetDocumentsById.get(document.documentId);
|
|
579
|
-
const conflictingIssueKeyDocument = targetDocumentsByIssueKey.get(`${document.issueId}:${document.key}`);
|
|
580
|
-
if (!existingDocument && conflictingIssueKeyDocument && conflictingIssueKeyDocument.documentId !== document.documentId) {
|
|
581
|
-
documentPlans.push({ source: document, action: "skip_conflicting_key" });
|
|
582
|
-
continue;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
const adjustments: ImportAdjustment[] = [];
|
|
586
|
-
const targetCreatedByAgentId =
|
|
587
|
-
document.createdByAgentId && targetAgentIds.has(document.createdByAgentId) ? document.createdByAgentId : null;
|
|
588
|
-
const targetUpdatedByAgentId =
|
|
589
|
-
document.updatedByAgentId && targetAgentIds.has(document.updatedByAgentId) ? document.updatedByAgentId : null;
|
|
590
|
-
if (
|
|
591
|
-
(document.createdByAgentId && !targetCreatedByAgentId)
|
|
592
|
-
|| (document.updatedByAgentId && !targetUpdatedByAgentId)
|
|
593
|
-
) {
|
|
594
|
-
adjustments.push("clear_document_agent");
|
|
595
|
-
incrementAdjustment(adjustmentCounts, "clear_document_agent");
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const sourceRevisions = sortDocumentRevisions(sourceRevisionsByDocumentId.get(document.documentId) ?? []);
|
|
599
|
-
const targetRevisions = sortDocumentRevisions(targetRevisionsByDocumentId.get(document.documentId) ?? []);
|
|
600
|
-
const existingRevisionIds = new Set(targetRevisions.map((revision) => revision.id));
|
|
601
|
-
const usedRevisionNumbers = new Set(targetRevisions.map((revision) => revision.revisionNumber));
|
|
602
|
-
let nextRevisionNumber = targetRevisions.reduce(
|
|
603
|
-
(maxValue, revision) => Math.max(maxValue, revision.revisionNumber),
|
|
604
|
-
0,
|
|
605
|
-
) + 1;
|
|
606
|
-
|
|
607
|
-
const targetRevisionNumberById = new Map<string, number>(
|
|
608
|
-
targetRevisions.map((revision) => [revision.id, revision.revisionNumber]),
|
|
609
|
-
);
|
|
610
|
-
const revisionsToInsert: PlannedDocumentRevisionInsert[] = [];
|
|
611
|
-
|
|
612
|
-
for (const revision of sourceRevisions) {
|
|
613
|
-
if (existingRevisionIds.has(revision.id)) continue;
|
|
614
|
-
let targetRevisionNumber = revision.revisionNumber;
|
|
615
|
-
if (usedRevisionNumbers.has(targetRevisionNumber)) {
|
|
616
|
-
while (usedRevisionNumbers.has(nextRevisionNumber)) {
|
|
617
|
-
nextRevisionNumber += 1;
|
|
618
|
-
}
|
|
619
|
-
targetRevisionNumber = nextRevisionNumber;
|
|
620
|
-
nextRevisionNumber += 1;
|
|
621
|
-
}
|
|
622
|
-
usedRevisionNumbers.add(targetRevisionNumber);
|
|
623
|
-
targetRevisionNumberById.set(revision.id, targetRevisionNumber);
|
|
624
|
-
|
|
625
|
-
const revisionAdjustments: ImportAdjustment[] = [];
|
|
626
|
-
const targetCreatedByAgentId =
|
|
627
|
-
revision.createdByAgentId && targetAgentIds.has(revision.createdByAgentId) ? revision.createdByAgentId : null;
|
|
628
|
-
if (revision.createdByAgentId && !targetCreatedByAgentId) {
|
|
629
|
-
revisionAdjustments.push("clear_document_revision_agent");
|
|
630
|
-
incrementAdjustment(adjustmentCounts, "clear_document_revision_agent");
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
revisionsToInsert.push({
|
|
634
|
-
source: revision,
|
|
635
|
-
targetRevisionNumber,
|
|
636
|
-
targetCreatedByAgentId,
|
|
637
|
-
adjustments: revisionAdjustments,
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const latestRevisionId = document.latestRevisionId ?? existingDocument?.latestRevisionId ?? null;
|
|
642
|
-
const latestRevisionNumber =
|
|
643
|
-
(latestRevisionId ? targetRevisionNumberById.get(latestRevisionId) : undefined)
|
|
644
|
-
?? document.latestRevisionNumber
|
|
645
|
-
?? existingDocument?.latestRevisionNumber
|
|
646
|
-
?? 0;
|
|
647
|
-
|
|
648
|
-
if (!existingDocument) {
|
|
649
|
-
documentPlans.push({
|
|
650
|
-
source: document,
|
|
651
|
-
action: "insert",
|
|
652
|
-
targetCreatedByAgentId,
|
|
653
|
-
targetUpdatedByAgentId,
|
|
654
|
-
latestRevisionId,
|
|
655
|
-
latestRevisionNumber,
|
|
656
|
-
revisionsToInsert,
|
|
657
|
-
adjustments,
|
|
658
|
-
});
|
|
659
|
-
continue;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
const documentAlreadyMatches =
|
|
663
|
-
existingDocument.key === document.key
|
|
664
|
-
&& existingDocument.title === document.title
|
|
665
|
-
&& existingDocument.format === document.format
|
|
666
|
-
&& existingDocument.latestBody === document.latestBody
|
|
667
|
-
&& (existingDocument.latestRevisionId ?? null) === latestRevisionId
|
|
668
|
-
&& existingDocument.latestRevisionNumber === latestRevisionNumber
|
|
669
|
-
&& (existingDocument.updatedByAgentId ?? null) === targetUpdatedByAgentId
|
|
670
|
-
&& (existingDocument.updatedByUserId ?? null) === (document.updatedByUserId ?? null)
|
|
671
|
-
&& sameDate(existingDocument.documentUpdatedAt, document.documentUpdatedAt)
|
|
672
|
-
&& sameDate(existingDocument.linkUpdatedAt, document.linkUpdatedAt)
|
|
673
|
-
&& revisionsToInsert.length === 0;
|
|
674
|
-
|
|
675
|
-
if (documentAlreadyMatches) {
|
|
676
|
-
documentPlans.push({ source: document, action: "skip_existing" });
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
documentPlans.push({
|
|
681
|
-
source: document,
|
|
682
|
-
action: "merge_existing",
|
|
683
|
-
targetCreatedByAgentId,
|
|
684
|
-
targetUpdatedByAgentId,
|
|
685
|
-
latestRevisionId,
|
|
686
|
-
latestRevisionNumber,
|
|
687
|
-
revisionsToInsert,
|
|
688
|
-
adjustments,
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
const sourceAttachments = input.sourceAttachments ?? [];
|
|
693
|
-
const targetAttachmentIds = new Set((input.targetAttachments ?? []).map((attachment) => attachment.id));
|
|
694
|
-
const attachmentPlans: Array<PlannedAttachmentInsert | PlannedAttachmentSkip> = [];
|
|
695
|
-
for (const attachment of sortAttachments(sourceAttachments)) {
|
|
696
|
-
if (targetAttachmentIds.has(attachment.id)) {
|
|
697
|
-
attachmentPlans.push({ source: attachment, action: "skip_existing" });
|
|
698
|
-
continue;
|
|
699
|
-
}
|
|
700
|
-
if (!issueIdsAvailableAfterImport.has(attachment.issueId)) {
|
|
701
|
-
attachmentPlans.push({ source: attachment, action: "skip_missing_parent" });
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
const adjustments: ImportAdjustment[] = [];
|
|
706
|
-
const targetCreatedByAgentId =
|
|
707
|
-
attachment.createdByAgentId && targetAgentIds.has(attachment.createdByAgentId)
|
|
708
|
-
? attachment.createdByAgentId
|
|
709
|
-
: null;
|
|
710
|
-
if (attachment.createdByAgentId && !targetCreatedByAgentId) {
|
|
711
|
-
adjustments.push("clear_attachment_agent");
|
|
712
|
-
incrementAdjustment(adjustmentCounts, "clear_attachment_agent");
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
attachmentPlans.push({
|
|
716
|
-
source: attachment,
|
|
717
|
-
action: "insert",
|
|
718
|
-
targetIssueCommentId:
|
|
719
|
-
attachment.issueCommentId && commentIdsAvailableAfterImport.has(attachment.issueCommentId)
|
|
720
|
-
? attachment.issueCommentId
|
|
721
|
-
: null,
|
|
722
|
-
targetCreatedByAgentId,
|
|
723
|
-
adjustments,
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
const counts = {
|
|
728
|
-
projectsToImport: projectImports.length,
|
|
729
|
-
issuesToInsert: issuePlans.filter((plan) => plan.action === "insert").length,
|
|
730
|
-
issuesExisting: issuePlans.filter((plan) => plan.action === "skip_existing").length,
|
|
731
|
-
issueDrift: issuePlans.filter((plan) => plan.action === "skip_existing" && plan.driftKeys.length > 0).length,
|
|
732
|
-
commentsToInsert: commentPlans.filter((plan) => plan.action === "insert").length,
|
|
733
|
-
commentsExisting: commentPlans.filter((plan) => plan.action === "skip_existing").length,
|
|
734
|
-
commentsMissingParent: commentPlans.filter((plan) => plan.action === "skip_missing_parent").length,
|
|
735
|
-
documentsToInsert: documentPlans.filter((plan) => plan.action === "insert").length,
|
|
736
|
-
documentsToMerge: documentPlans.filter((plan) => plan.action === "merge_existing").length,
|
|
737
|
-
documentsExisting: documentPlans.filter((plan) => plan.action === "skip_existing").length,
|
|
738
|
-
documentsConflictingKey: documentPlans.filter((plan) => plan.action === "skip_conflicting_key").length,
|
|
739
|
-
documentsMissingParent: documentPlans.filter((plan) => plan.action === "skip_missing_parent").length,
|
|
740
|
-
documentRevisionsToInsert: documentPlans.reduce(
|
|
741
|
-
(sum, plan) =>
|
|
742
|
-
sum + (plan.action === "insert" || plan.action === "merge_existing" ? plan.revisionsToInsert.length : 0),
|
|
743
|
-
0,
|
|
744
|
-
),
|
|
745
|
-
attachmentsToInsert: attachmentPlans.filter((plan) => plan.action === "insert").length,
|
|
746
|
-
attachmentsExisting: attachmentPlans.filter((plan) => plan.action === "skip_existing").length,
|
|
747
|
-
attachmentsMissingParent: attachmentPlans.filter((plan) => plan.action === "skip_missing_parent").length,
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
return {
|
|
751
|
-
companyId: input.companyId,
|
|
752
|
-
companyName: input.companyName,
|
|
753
|
-
issuePrefix: input.issuePrefix,
|
|
754
|
-
previewIssueCounterStart: input.previewIssueCounterStart,
|
|
755
|
-
scopes: input.scopes,
|
|
756
|
-
projectImports,
|
|
757
|
-
issuePlans,
|
|
758
|
-
commentPlans,
|
|
759
|
-
documentPlans,
|
|
760
|
-
attachmentPlans,
|
|
761
|
-
counts,
|
|
762
|
-
adjustments: adjustmentCounts,
|
|
763
|
-
};
|
|
764
|
-
}
|