offwatch 0.5.12 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +132 -178
  2. package/bin/offwatch.js +6 -7
  3. package/lib/downloader.js +112 -0
  4. package/package.json +18 -11
  5. package/postinstall.js +21 -0
  6. package/src/__tests__/agent-jwt-env.test.ts +0 -79
  7. package/src/__tests__/allowed-hostname.test.ts +0 -80
  8. package/src/__tests__/auth-command-registration.test.ts +0 -16
  9. package/src/__tests__/board-auth.test.ts +0 -53
  10. package/src/__tests__/common.test.ts +0 -98
  11. package/src/__tests__/company-delete.test.ts +0 -95
  12. package/src/__tests__/company-import-export-e2e.test.ts +0 -502
  13. package/src/__tests__/company-import-url.test.ts +0 -74
  14. package/src/__tests__/company-import-zip.test.ts +0 -44
  15. package/src/__tests__/company.test.ts +0 -599
  16. package/src/__tests__/context.test.ts +0 -70
  17. package/src/__tests__/data-dir.test.ts +0 -79
  18. package/src/__tests__/doctor.test.ts +0 -102
  19. package/src/__tests__/feedback.test.ts +0 -177
  20. package/src/__tests__/helpers/embedded-postgres.ts +0 -6
  21. package/src/__tests__/helpers/zip.ts +0 -87
  22. package/src/__tests__/home-paths.test.ts +0 -44
  23. package/src/__tests__/http.test.ts +0 -106
  24. package/src/__tests__/network-bind.test.ts +0 -62
  25. package/src/__tests__/onboard.test.ts +0 -166
  26. package/src/__tests__/routines.test.ts +0 -249
  27. package/src/__tests__/telemetry.test.ts +0 -117
  28. package/src/__tests__/worktree-merge-history.test.ts +0 -492
  29. package/src/__tests__/worktree.test.ts +0 -982
  30. package/src/adapters/http/format-event.ts +0 -4
  31. package/src/adapters/http/index.ts +0 -7
  32. package/src/adapters/index.ts +0 -2
  33. package/src/adapters/process/format-event.ts +0 -4
  34. package/src/adapters/process/index.ts +0 -7
  35. package/src/adapters/registry.ts +0 -63
  36. package/src/checks/agent-jwt-secret-check.ts +0 -40
  37. package/src/checks/config-check.ts +0 -33
  38. package/src/checks/database-check.ts +0 -59
  39. package/src/checks/deployment-auth-check.ts +0 -88
  40. package/src/checks/index.ts +0 -18
  41. package/src/checks/llm-check.ts +0 -82
  42. package/src/checks/log-check.ts +0 -30
  43. package/src/checks/path-resolver.ts +0 -1
  44. package/src/checks/port-check.ts +0 -24
  45. package/src/checks/secrets-check.ts +0 -146
  46. package/src/checks/storage-check.ts +0 -51
  47. package/src/client/board-auth.ts +0 -282
  48. package/src/client/command-label.ts +0 -4
  49. package/src/client/context.ts +0 -175
  50. package/src/client/http.ts +0 -255
  51. package/src/commands/allowed-hostname.ts +0 -40
  52. package/src/commands/auth-bootstrap-ceo.ts +0 -138
  53. package/src/commands/client/activity.ts +0 -71
  54. package/src/commands/client/agent.ts +0 -315
  55. package/src/commands/client/approval.ts +0 -259
  56. package/src/commands/client/auth.ts +0 -113
  57. package/src/commands/client/common.ts +0 -221
  58. package/src/commands/client/company.ts +0 -1578
  59. package/src/commands/client/context.ts +0 -125
  60. package/src/commands/client/dashboard.ts +0 -34
  61. package/src/commands/client/feedback.ts +0 -645
  62. package/src/commands/client/issue.ts +0 -411
  63. package/src/commands/client/plugin.ts +0 -374
  64. package/src/commands/client/zip.ts +0 -129
  65. package/src/commands/configure.ts +0 -201
  66. package/src/commands/db-backup.ts +0 -102
  67. package/src/commands/doctor.ts +0 -203
  68. package/src/commands/env.ts +0 -411
  69. package/src/commands/heartbeat-run.ts +0 -344
  70. package/src/commands/onboard.ts +0 -692
  71. package/src/commands/routines.ts +0 -352
  72. package/src/commands/run.ts +0 -216
  73. package/src/commands/worktree-lib.ts +0 -279
  74. package/src/commands/worktree-merge-history-lib.ts +0 -764
  75. package/src/commands/worktree.ts +0 -2876
  76. package/src/config/data-dir.ts +0 -48
  77. package/src/config/env.ts +0 -125
  78. package/src/config/home.ts +0 -80
  79. package/src/config/hostnames.ts +0 -26
  80. package/src/config/schema.ts +0 -30
  81. package/src/config/secrets-key.ts +0 -48
  82. package/src/config/server-bind.ts +0 -183
  83. package/src/config/store.ts +0 -120
  84. package/src/index.ts +0 -182
  85. package/src/prompts/database.ts +0 -157
  86. package/src/prompts/llm.ts +0 -43
  87. package/src/prompts/logging.ts +0 -37
  88. package/src/prompts/secrets.ts +0 -99
  89. package/src/prompts/server.ts +0 -221
  90. package/src/prompts/storage.ts +0 -146
  91. package/src/telemetry.ts +0 -49
  92. package/src/utils/banner.ts +0 -24
  93. package/src/utils/net.ts +0 -18
  94. package/src/utils/path-resolver.ts +0 -25
  95. package/src/version.ts +0 -10
@@ -1,492 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { buildWorktreeMergePlan, parseWorktreeMergeScopes } from "../commands/worktree-merge-history-lib.js";
3
-
4
- function makeIssue(overrides: Record<string, unknown> = {}) {
5
- return {
6
- id: "issue-1",
7
- companyId: "company-1",
8
- projectId: null,
9
- projectWorkspaceId: null,
10
- goalId: "goal-1",
11
- parentId: null,
12
- title: "Issue",
13
- description: null,
14
- status: "todo",
15
- priority: "medium",
16
- assigneeAgentId: null,
17
- assigneeUserId: null,
18
- checkoutRunId: null,
19
- executionRunId: null,
20
- executionAgentNameKey: null,
21
- executionLockedAt: null,
22
- createdByAgentId: null,
23
- createdByUserId: "local-board",
24
- issueNumber: 1,
25
- identifier: "PAP-1",
26
- requestDepth: 0,
27
- billingCode: null,
28
- assigneeAdapterOverrides: null,
29
- executionWorkspaceId: null,
30
- executionWorkspacePreference: null,
31
- executionWorkspaceSettings: null,
32
- startedAt: null,
33
- completedAt: null,
34
- cancelledAt: null,
35
- hiddenAt: null,
36
- createdAt: new Date("2026-03-20T00:00:00.000Z"),
37
- updatedAt: new Date("2026-03-20T00:00:00.000Z"),
38
- ...overrides,
39
- } as any;
40
- }
41
-
42
- function makeComment(overrides: Record<string, unknown> = {}) {
43
- return {
44
- id: "comment-1",
45
- companyId: "company-1",
46
- issueId: "issue-1",
47
- authorAgentId: null,
48
- authorUserId: "local-board",
49
- body: "hello",
50
- createdAt: new Date("2026-03-20T00:00:00.000Z"),
51
- updatedAt: new Date("2026-03-20T00:00:00.000Z"),
52
- ...overrides,
53
- } as any;
54
- }
55
-
56
- function makeIssueDocument(overrides: Record<string, unknown> = {}) {
57
- return {
58
- id: "issue-document-1",
59
- companyId: "company-1",
60
- issueId: "issue-1",
61
- documentId: "document-1",
62
- key: "plan",
63
- linkCreatedAt: new Date("2026-03-20T00:00:00.000Z"),
64
- linkUpdatedAt: new Date("2026-03-20T00:00:00.000Z"),
65
- title: "Plan",
66
- format: "markdown",
67
- latestBody: "# Plan",
68
- latestRevisionId: "revision-1",
69
- latestRevisionNumber: 1,
70
- createdByAgentId: null,
71
- createdByUserId: "local-board",
72
- updatedByAgentId: null,
73
- updatedByUserId: "local-board",
74
- documentCreatedAt: new Date("2026-03-20T00:00:00.000Z"),
75
- documentUpdatedAt: new Date("2026-03-20T00:00:00.000Z"),
76
- ...overrides,
77
- } as any;
78
- }
79
-
80
- function makeDocumentRevision(overrides: Record<string, unknown> = {}) {
81
- return {
82
- id: "revision-1",
83
- companyId: "company-1",
84
- documentId: "document-1",
85
- revisionNumber: 1,
86
- body: "# Plan",
87
- changeSummary: null,
88
- createdByAgentId: null,
89
- createdByUserId: "local-board",
90
- createdAt: new Date("2026-03-20T00:00:00.000Z"),
91
- ...overrides,
92
- } as any;
93
- }
94
-
95
- function makeAttachment(overrides: Record<string, unknown> = {}) {
96
- return {
97
- id: "attachment-1",
98
- companyId: "company-1",
99
- issueId: "issue-1",
100
- issueCommentId: null,
101
- assetId: "asset-1",
102
- provider: "local_disk",
103
- objectKey: "company-1/issues/issue-1/2026/03/20/asset.png",
104
- contentType: "image/png",
105
- byteSize: 12,
106
- sha256: "deadbeef",
107
- originalFilename: "asset.png",
108
- createdByAgentId: null,
109
- createdByUserId: "local-board",
110
- assetCreatedAt: new Date("2026-03-20T00:00:00.000Z"),
111
- assetUpdatedAt: new Date("2026-03-20T00:00:00.000Z"),
112
- attachmentCreatedAt: new Date("2026-03-20T00:00:00.000Z"),
113
- attachmentUpdatedAt: new Date("2026-03-20T00:00:00.000Z"),
114
- ...overrides,
115
- } as any;
116
- }
117
-
118
- function makeProject(overrides: Record<string, unknown> = {}) {
119
- return {
120
- id: "project-1",
121
- companyId: "company-1",
122
- goalId: null,
123
- name: "Project",
124
- description: null,
125
- status: "in_progress",
126
- leadAgentId: null,
127
- targetDate: null,
128
- color: "#22c55e",
129
- pauseReason: null,
130
- pausedAt: null,
131
- executionWorkspacePolicy: null,
132
- archivedAt: null,
133
- createdAt: new Date("2026-03-20T00:00:00.000Z"),
134
- updatedAt: new Date("2026-03-20T00:00:00.000Z"),
135
- ...overrides,
136
- } as any;
137
- }
138
-
139
- function makeProjectWorkspace(overrides: Record<string, unknown> = {}) {
140
- return {
141
- id: "workspace-1",
142
- companyId: "company-1",
143
- projectId: "project-1",
144
- name: "Workspace",
145
- sourceType: "local_path",
146
- cwd: "/tmp/project",
147
- repoUrl: "https://github.com/example/project.git",
148
- repoRef: "main",
149
- defaultRef: "main",
150
- visibility: "default",
151
- setupCommand: null,
152
- cleanupCommand: null,
153
- remoteProvider: null,
154
- remoteWorkspaceRef: null,
155
- sharedWorkspaceKey: null,
156
- metadata: null,
157
- isPrimary: true,
158
- createdAt: new Date("2026-03-20T00:00:00.000Z"),
159
- updatedAt: new Date("2026-03-20T00:00:00.000Z"),
160
- ...overrides,
161
- } as any;
162
- }
163
-
164
- describe("worktree merge history planner", () => {
165
- it("parses default scopes", () => {
166
- expect(parseWorktreeMergeScopes(undefined)).toEqual(["issues", "comments"]);
167
- expect(parseWorktreeMergeScopes("issues")).toEqual(["issues"]);
168
- });
169
-
170
- it("dedupes nested worktree issues by preserved source uuid", () => {
171
- const sharedIssue = makeIssue({ id: "issue-a", identifier: "PAP-10", title: "Shared" });
172
- const branchOneIssue = makeIssue({
173
- id: "issue-b",
174
- identifier: "PAP-22",
175
- title: "Branch one issue",
176
- createdAt: new Date("2026-03-20T01:00:00.000Z"),
177
- });
178
- const branchTwoIssue = makeIssue({
179
- id: "issue-c",
180
- identifier: "PAP-23",
181
- title: "Branch two issue",
182
- createdAt: new Date("2026-03-20T02:00:00.000Z"),
183
- });
184
-
185
- const plan = buildWorktreeMergePlan({
186
- companyId: "company-1",
187
- companyName: "Paperclip",
188
- issuePrefix: "PAP",
189
- previewIssueCounterStart: 500,
190
- scopes: ["issues", "comments"],
191
- sourceIssues: [sharedIssue, branchOneIssue, branchTwoIssue],
192
- targetIssues: [sharedIssue, branchOneIssue],
193
- sourceComments: [],
194
- targetComments: [],
195
- targetAgents: [],
196
- targetProjects: [],
197
- targetProjectWorkspaces: [],
198
- targetGoals: [{ id: "goal-1" }] as any,
199
- });
200
-
201
- expect(plan.counts.issuesToInsert).toBe(1);
202
- expect(plan.issuePlans.filter((item) => item.action === "insert").map((item) => item.source.id)).toEqual(["issue-c"]);
203
- expect(plan.issuePlans.find((item) => item.source.id === "issue-c" && item.action === "insert")).toMatchObject({
204
- previewIdentifier: "PAP-501",
205
- });
206
- });
207
-
208
- it("clears missing references and coerces in_progress without an assignee", () => {
209
- const plan = buildWorktreeMergePlan({
210
- companyId: "company-1",
211
- companyName: "Paperclip",
212
- issuePrefix: "PAP",
213
- previewIssueCounterStart: 10,
214
- scopes: ["issues"],
215
- sourceIssues: [
216
- makeIssue({
217
- id: "issue-x",
218
- identifier: "PAP-99",
219
- status: "in_progress",
220
- assigneeAgentId: "agent-missing",
221
- projectId: "project-missing",
222
- projectWorkspaceId: "workspace-missing",
223
- goalId: "goal-missing",
224
- }),
225
- ],
226
- targetIssues: [],
227
- sourceComments: [],
228
- targetComments: [],
229
- targetAgents: [],
230
- targetProjects: [],
231
- targetProjectWorkspaces: [],
232
- targetGoals: [],
233
- });
234
-
235
- const insert = plan.issuePlans[0] as any;
236
- expect(insert.targetStatus).toBe("todo");
237
- expect(insert.targetAssigneeAgentId).toBeNull();
238
- expect(insert.targetProjectId).toBeNull();
239
- expect(insert.targetProjectWorkspaceId).toBeNull();
240
- expect(insert.targetGoalId).toBeNull();
241
- expect(insert.adjustments).toEqual([
242
- "clear_assignee_agent",
243
- "clear_project",
244
- "clear_project_workspace",
245
- "clear_goal",
246
- "coerce_in_progress_to_todo",
247
- ]);
248
- });
249
-
250
- it("applies an explicit project mapping override instead of clearing the project", () => {
251
- const plan = buildWorktreeMergePlan({
252
- companyId: "company-1",
253
- companyName: "Paperclip",
254
- issuePrefix: "PAP",
255
- previewIssueCounterStart: 10,
256
- scopes: ["issues"],
257
- sourceIssues: [
258
- makeIssue({
259
- id: "issue-project-map",
260
- identifier: "PAP-77",
261
- projectId: "source-project-1",
262
- projectWorkspaceId: "source-workspace-1",
263
- }),
264
- ],
265
- targetIssues: [],
266
- sourceComments: [],
267
- targetComments: [],
268
- targetAgents: [],
269
- targetProjects: [{ id: "target-project-1", name: "Mapped project", status: "in_progress" }] as any,
270
- targetProjectWorkspaces: [],
271
- targetGoals: [{ id: "goal-1" }] as any,
272
- projectIdOverrides: {
273
- "source-project-1": "target-project-1",
274
- },
275
- });
276
-
277
- const insert = plan.issuePlans[0] as any;
278
- expect(insert.targetProjectId).toBe("target-project-1");
279
- expect(insert.projectResolution).toBe("mapped");
280
- expect(insert.mappedProjectName).toBe("Mapped project");
281
- expect(insert.targetProjectWorkspaceId).toBeNull();
282
- expect(insert.adjustments).toEqual(["clear_project_workspace"]);
283
- });
284
-
285
- it("plans selected project imports and preserves project workspace links", () => {
286
- const sourceProject = makeProject({
287
- id: "source-project-1",
288
- name: "Paperclip Evals",
289
- goalId: "goal-1",
290
- });
291
- const sourceWorkspace = makeProjectWorkspace({
292
- id: "source-workspace-1",
293
- projectId: "source-project-1",
294
- cwd: "/Users/dotta/paperclip-evals",
295
- repoUrl: "https://github.com/paperclipai/paperclip-evals.git",
296
- });
297
-
298
- const plan = buildWorktreeMergePlan({
299
- companyId: "company-1",
300
- companyName: "Paperclip",
301
- issuePrefix: "PAP",
302
- previewIssueCounterStart: 10,
303
- scopes: ["issues"],
304
- sourceIssues: [
305
- makeIssue({
306
- id: "issue-project-import",
307
- identifier: "PAP-88",
308
- projectId: "source-project-1",
309
- projectWorkspaceId: "source-workspace-1",
310
- }),
311
- ],
312
- targetIssues: [],
313
- sourceComments: [],
314
- targetComments: [],
315
- sourceProjects: [sourceProject],
316
- sourceProjectWorkspaces: [sourceWorkspace],
317
- targetAgents: [],
318
- targetProjects: [],
319
- targetProjectWorkspaces: [],
320
- targetGoals: [{ id: "goal-1" }] as any,
321
- importProjectIds: ["source-project-1"],
322
- });
323
-
324
- expect(plan.counts.projectsToImport).toBe(1);
325
- expect(plan.projectImports[0]).toMatchObject({
326
- source: { id: "source-project-1", name: "Paperclip Evals" },
327
- targetGoalId: "goal-1",
328
- workspaces: [{ id: "source-workspace-1" }],
329
- });
330
-
331
- const insert = plan.issuePlans[0] as any;
332
- expect(insert.targetProjectId).toBe("source-project-1");
333
- expect(insert.targetProjectWorkspaceId).toBe("source-workspace-1");
334
- expect(insert.projectResolution).toBe("imported");
335
- expect(insert.mappedProjectName).toBe("Paperclip Evals");
336
- expect(insert.adjustments).toEqual([]);
337
- });
338
-
339
- it("imports comments onto shared or newly imported issues while skipping existing comments", () => {
340
- const sharedIssue = makeIssue({ id: "issue-a", identifier: "PAP-10" });
341
- const newIssue = makeIssue({
342
- id: "issue-b",
343
- identifier: "PAP-11",
344
- createdAt: new Date("2026-03-20T01:00:00.000Z"),
345
- });
346
- const existingComment = makeComment({ id: "comment-existing", issueId: "issue-a" });
347
- const sharedIssueComment = makeComment({ id: "comment-shared", issueId: "issue-a" });
348
- const newIssueComment = makeComment({
349
- id: "comment-new-issue",
350
- issueId: "issue-b",
351
- authorAgentId: "missing-agent",
352
- createdAt: new Date("2026-03-20T01:05:00.000Z"),
353
- });
354
-
355
- const plan = buildWorktreeMergePlan({
356
- companyId: "company-1",
357
- companyName: "Paperclip",
358
- issuePrefix: "PAP",
359
- previewIssueCounterStart: 10,
360
- scopes: ["issues", "comments"],
361
- sourceIssues: [sharedIssue, newIssue],
362
- targetIssues: [sharedIssue],
363
- sourceComments: [existingComment, sharedIssueComment, newIssueComment],
364
- targetComments: [existingComment],
365
- targetAgents: [],
366
- targetProjects: [],
367
- targetProjectWorkspaces: [],
368
- targetGoals: [{ id: "goal-1" }] as any,
369
- });
370
-
371
- expect(plan.counts.commentsToInsert).toBe(2);
372
- expect(plan.counts.commentsExisting).toBe(1);
373
- expect(plan.commentPlans.filter((item) => item.action === "insert").map((item) => item.source.id)).toEqual([
374
- "comment-shared",
375
- "comment-new-issue",
376
- ]);
377
- expect(plan.adjustments.clear_author_agent).toBe(1);
378
- });
379
-
380
- it("merges document revisions onto an existing shared document and renumbers conflicts", () => {
381
- const sharedIssue = makeIssue({ id: "issue-a", identifier: "PAP-10" });
382
- const sourceDocument = makeIssueDocument({
383
- issueId: "issue-a",
384
- documentId: "document-a",
385
- latestBody: "# Branch plan",
386
- latestRevisionId: "revision-branch-2",
387
- latestRevisionNumber: 2,
388
- documentUpdatedAt: new Date("2026-03-20T02:00:00.000Z"),
389
- linkUpdatedAt: new Date("2026-03-20T02:00:00.000Z"),
390
- });
391
- const targetDocument = makeIssueDocument({
392
- issueId: "issue-a",
393
- documentId: "document-a",
394
- latestBody: "# Main plan",
395
- latestRevisionId: "revision-main-2",
396
- latestRevisionNumber: 2,
397
- documentUpdatedAt: new Date("2026-03-20T01:00:00.000Z"),
398
- linkUpdatedAt: new Date("2026-03-20T01:00:00.000Z"),
399
- });
400
- const sourceRevisionOne = makeDocumentRevision({ documentId: "document-a", id: "revision-1" });
401
- const sourceRevisionTwo = makeDocumentRevision({
402
- documentId: "document-a",
403
- id: "revision-branch-2",
404
- revisionNumber: 2,
405
- body: "# Branch plan",
406
- createdAt: new Date("2026-03-20T02:00:00.000Z"),
407
- });
408
- const targetRevisionOne = makeDocumentRevision({ documentId: "document-a", id: "revision-1" });
409
- const targetRevisionTwo = makeDocumentRevision({
410
- documentId: "document-a",
411
- id: "revision-main-2",
412
- revisionNumber: 2,
413
- body: "# Main plan",
414
- createdAt: new Date("2026-03-20T01:00:00.000Z"),
415
- });
416
-
417
- const plan = buildWorktreeMergePlan({
418
- companyId: "company-1",
419
- companyName: "Paperclip",
420
- issuePrefix: "PAP",
421
- previewIssueCounterStart: 10,
422
- scopes: ["issues", "comments"],
423
- sourceIssues: [sharedIssue],
424
- targetIssues: [sharedIssue],
425
- sourceComments: [],
426
- targetComments: [],
427
- sourceDocuments: [sourceDocument],
428
- targetDocuments: [targetDocument],
429
- sourceDocumentRevisions: [sourceRevisionOne, sourceRevisionTwo],
430
- targetDocumentRevisions: [targetRevisionOne, targetRevisionTwo],
431
- sourceAttachments: [],
432
- targetAttachments: [],
433
- targetAgents: [],
434
- targetProjects: [],
435
- targetProjectWorkspaces: [],
436
- targetGoals: [{ id: "goal-1" }] as any,
437
- });
438
-
439
- expect(plan.counts.documentsToMerge).toBe(1);
440
- expect(plan.counts.documentRevisionsToInsert).toBe(1);
441
- expect(plan.documentPlans[0]).toMatchObject({
442
- action: "merge_existing",
443
- latestRevisionId: "revision-branch-2",
444
- latestRevisionNumber: 3,
445
- });
446
- const mergePlan = plan.documentPlans[0] as any;
447
- expect(mergePlan.revisionsToInsert).toHaveLength(1);
448
- expect(mergePlan.revisionsToInsert[0]).toMatchObject({
449
- source: { id: "revision-branch-2" },
450
- targetRevisionNumber: 3,
451
- });
452
- });
453
-
454
- it("imports attachments while clearing missing comment and author references", () => {
455
- const sharedIssue = makeIssue({ id: "issue-a", identifier: "PAP-10" });
456
- const attachment = makeAttachment({
457
- issueId: "issue-a",
458
- issueCommentId: "comment-missing",
459
- createdByAgentId: "agent-missing",
460
- });
461
-
462
- const plan = buildWorktreeMergePlan({
463
- companyId: "company-1",
464
- companyName: "Paperclip",
465
- issuePrefix: "PAP",
466
- previewIssueCounterStart: 10,
467
- scopes: ["issues"],
468
- sourceIssues: [sharedIssue],
469
- targetIssues: [sharedIssue],
470
- sourceComments: [],
471
- targetComments: [],
472
- sourceDocuments: [],
473
- targetDocuments: [],
474
- sourceDocumentRevisions: [],
475
- targetDocumentRevisions: [],
476
- sourceAttachments: [attachment],
477
- targetAttachments: [],
478
- targetAgents: [],
479
- targetProjects: [],
480
- targetProjectWorkspaces: [],
481
- targetGoals: [{ id: "goal-1" }] as any,
482
- });
483
-
484
- expect(plan.counts.attachmentsToInsert).toBe(1);
485
- expect(plan.adjustments.clear_attachment_agent).toBe(1);
486
- expect(plan.attachmentPlans[0]).toMatchObject({
487
- action: "insert",
488
- targetIssueCommentId: null,
489
- targetCreatedByAgentId: null,
490
- });
491
- });
492
- });