runline 0.11.3 → 0.11.4

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.
@@ -0,0 +1,313 @@
1
+ import { buildLocation, compact, extractDocumentId, hexToRgbF, runBatchUpdate, } from "./shared.js";
2
+ function range(p) {
3
+ return compact({
4
+ segmentId: p.segmentId && p.segmentId !== "body" ? p.segmentId : "",
5
+ startIndex: p.startIndex,
6
+ endIndex: p.endIndex,
7
+ tabId: p.tabId,
8
+ });
9
+ }
10
+ export function registerTextActions(rl) {
11
+ rl.registerAction("document.insertText", {
12
+ description: "Insert text at a specific index, or at the end of a segment (body/header/footer/footnote).",
13
+ inputSchema: {
14
+ document: { type: "string", required: true },
15
+ text: { type: "string", required: true },
16
+ locationKind: {
17
+ type: "string",
18
+ required: false,
19
+ description: "location (default; requires index) | endOfSegmentLocation",
20
+ },
21
+ index: {
22
+ type: "number",
23
+ required: false,
24
+ description: "Required for locationKind=location",
25
+ },
26
+ segmentId: {
27
+ type: "string",
28
+ required: false,
29
+ description: 'Segment ID, or "body" / empty for the main body',
30
+ },
31
+ tabId: { type: "string", required: false },
32
+ },
33
+ async execute(input, ctx) {
34
+ const p = (input ?? {});
35
+ const documentId = extractDocumentId(p.document);
36
+ const kind = p.locationKind ?? "location";
37
+ const locObj = buildLocation(kind, p.segmentId, p.index, p.tabId);
38
+ return runBatchUpdate(ctx, documentId, {
39
+ insertText: { text: p.text, ...locObj },
40
+ });
41
+ },
42
+ });
43
+ rl.registerAction("document.replaceAllText", {
44
+ description: "Replace every occurrence of a text string throughout the document.",
45
+ inputSchema: {
46
+ document: { type: "string", required: true },
47
+ findText: { type: "string", required: true },
48
+ replaceText: { type: "string", required: true },
49
+ matchCase: { type: "boolean", required: false },
50
+ searchByRegex: { type: "boolean", required: false },
51
+ tabIds: {
52
+ type: "array",
53
+ required: false,
54
+ description: "Optional tab IDs for tabsCriteria.",
55
+ },
56
+ },
57
+ async execute(input, ctx) {
58
+ const p = (input ?? {});
59
+ const documentId = extractDocumentId(p.document);
60
+ return runBatchUpdate(ctx, documentId, {
61
+ replaceAllText: {
62
+ replaceText: p.replaceText,
63
+ containsText: {
64
+ text: p.findText,
65
+ matchCase: p.matchCase === true,
66
+ searchByRegex: p.searchByRegex === true,
67
+ },
68
+ ...(Array.isArray(p.tabIds)
69
+ ? { tabsCriteria: { tabIds: p.tabIds } }
70
+ : {}),
71
+ },
72
+ });
73
+ },
74
+ });
75
+ rl.registerAction("document.deleteContentRange", {
76
+ description: "Delete text between two indices in a segment.",
77
+ inputSchema: {
78
+ document: { type: "string", required: true },
79
+ startIndex: { type: "number", required: true },
80
+ endIndex: { type: "number", required: true },
81
+ segmentId: { type: "string", required: false },
82
+ tabId: { type: "string", required: false },
83
+ },
84
+ async execute(input, ctx) {
85
+ const p = (input ?? {});
86
+ const documentId = extractDocumentId(p.document);
87
+ return runBatchUpdate(ctx, documentId, {
88
+ deleteContentRange: { range: range(p) },
89
+ });
90
+ },
91
+ });
92
+ rl.registerAction("document.createParagraphBullets", {
93
+ description: "Apply a bullet preset to paragraphs spanning a range. Presets: BULLET_DISC_CIRCLE_SQUARE, BULLET_DIAMONDX_ARROW3D_SQUARE, BULLET_CHECKBOX, NUMBERED_DECIMAL_ALPHA_ROMAN, NUMBERED_DECIMAL_NESTED, etc.",
94
+ inputSchema: {
95
+ document: { type: "string", required: true },
96
+ bulletPreset: { type: "string", required: true },
97
+ startIndex: { type: "number", required: true },
98
+ endIndex: { type: "number", required: true },
99
+ segmentId: { type: "string", required: false },
100
+ tabId: { type: "string", required: false },
101
+ },
102
+ async execute(input, ctx) {
103
+ const p = (input ?? {});
104
+ const documentId = extractDocumentId(p.document);
105
+ return runBatchUpdate(ctx, documentId, {
106
+ createParagraphBullets: {
107
+ bulletPreset: p.bulletPreset,
108
+ range: range(p),
109
+ },
110
+ });
111
+ },
112
+ });
113
+ rl.registerAction("document.deleteParagraphBullets", {
114
+ description: "Remove bullets from paragraphs in a range.",
115
+ inputSchema: {
116
+ document: { type: "string", required: true },
117
+ startIndex: { type: "number", required: true },
118
+ endIndex: { type: "number", required: true },
119
+ segmentId: { type: "string", required: false },
120
+ tabId: { type: "string", required: false },
121
+ },
122
+ async execute(input, ctx) {
123
+ const p = (input ?? {});
124
+ const documentId = extractDocumentId(p.document);
125
+ return runBatchUpdate(ctx, documentId, {
126
+ deleteParagraphBullets: { range: range(p) },
127
+ });
128
+ },
129
+ });
130
+ rl.registerAction("document.insertPerson", {
131
+ description: "Insert a smart chip person mention at a location or at the end of a segment.",
132
+ inputSchema: {
133
+ document: { type: "string", required: true },
134
+ personProperties: {
135
+ type: "object",
136
+ required: true,
137
+ description: "Docs API PersonProperties object.",
138
+ },
139
+ locationKind: {
140
+ type: "string",
141
+ required: false,
142
+ description: "location (default; requires index) | endOfSegmentLocation",
143
+ },
144
+ index: { type: "number", required: false },
145
+ segmentId: { type: "string", required: false },
146
+ tabId: { type: "string", required: false },
147
+ },
148
+ async execute(input, ctx) {
149
+ const p = (input ?? {});
150
+ const documentId = extractDocumentId(p.document);
151
+ const kind = p.locationKind ?? "location";
152
+ return runBatchUpdate(ctx, documentId, {
153
+ insertPerson: {
154
+ personProperties: p.personProperties,
155
+ ...buildLocation(kind, p.segmentId, p.index, p.tabId),
156
+ },
157
+ });
158
+ },
159
+ });
160
+ rl.registerAction("document.insertRichLink", {
161
+ description: "Insert a rich link smart chip at a location or at the end of a segment.",
162
+ inputSchema: {
163
+ document: { type: "string", required: true },
164
+ richLinkProperties: {
165
+ type: "object",
166
+ required: true,
167
+ description: "Docs API RichLinkProperties object.",
168
+ },
169
+ locationKind: {
170
+ type: "string",
171
+ required: false,
172
+ description: "location (default; requires index) | endOfSegmentLocation",
173
+ },
174
+ index: { type: "number", required: false },
175
+ segmentId: { type: "string", required: false },
176
+ tabId: { type: "string", required: false },
177
+ },
178
+ async execute(input, ctx) {
179
+ const p = (input ?? {});
180
+ const documentId = extractDocumentId(p.document);
181
+ const kind = p.locationKind ?? "location";
182
+ return runBatchUpdate(ctx, documentId, {
183
+ insertRichLink: {
184
+ richLinkProperties: p.richLinkProperties,
185
+ ...buildLocation(kind, p.segmentId, p.index, p.tabId),
186
+ },
187
+ });
188
+ },
189
+ });
190
+ rl.registerAction("document.insertDate", {
191
+ description: "Insert a date smart chip at a location or at the end of a segment.",
192
+ inputSchema: {
193
+ document: { type: "string", required: true },
194
+ dateElementProperties: {
195
+ type: "object",
196
+ required: false,
197
+ description: "Optional Docs API DateElementProperties object.",
198
+ },
199
+ locationKind: {
200
+ type: "string",
201
+ required: false,
202
+ description: "location (default; requires index) | endOfSegmentLocation",
203
+ },
204
+ index: { type: "number", required: false },
205
+ segmentId: { type: "string", required: false },
206
+ tabId: { type: "string", required: false },
207
+ },
208
+ async execute(input, ctx) {
209
+ const p = (input ?? {});
210
+ const documentId = extractDocumentId(p.document);
211
+ const kind = p.locationKind ?? "location";
212
+ return runBatchUpdate(ctx, documentId, {
213
+ insertDate: {
214
+ ...(p.dateElementProperties
215
+ ? { dateElementProperties: p.dateElementProperties }
216
+ : {}),
217
+ ...buildLocation(kind, p.segmentId, p.index, p.tabId),
218
+ },
219
+ });
220
+ },
221
+ });
222
+ rl.registerAction("document.updateTextStyle", {
223
+ description: "Apply text styling (bold, italic, underline, color, fontSize, fontFamily, link) to a range. Pass `fields` listing which TextStyle properties were set.",
224
+ inputSchema: {
225
+ document: { type: "string", required: true },
226
+ startIndex: { type: "number", required: true },
227
+ endIndex: { type: "number", required: true },
228
+ bold: { type: "boolean", required: false },
229
+ italic: { type: "boolean", required: false },
230
+ underline: { type: "boolean", required: false },
231
+ strikethrough: { type: "boolean", required: false },
232
+ fontSizePt: {
233
+ type: "number",
234
+ required: false,
235
+ description: "Font size in points.",
236
+ },
237
+ fontFamily: { type: "string", required: false },
238
+ foregroundColorHex: {
239
+ type: "string",
240
+ required: false,
241
+ description: "Hex color, e.g. #1A73E8",
242
+ },
243
+ backgroundColorHex: { type: "string", required: false },
244
+ link: {
245
+ type: "string",
246
+ required: false,
247
+ description: "URL for the linked range.",
248
+ },
249
+ segmentId: {
250
+ type: "string",
251
+ required: false,
252
+ description: "Header/footer/footnote id; omit for the body.",
253
+ },
254
+ tabId: { type: "string", required: false },
255
+ },
256
+ async execute(input, ctx) {
257
+ const p = (input ?? {});
258
+ const documentId = extractDocumentId(p.document);
259
+ const ts = {};
260
+ const fields = [];
261
+ if (p.bold !== undefined) {
262
+ ts.bold = p.bold;
263
+ fields.push("bold");
264
+ }
265
+ if (p.italic !== undefined) {
266
+ ts.italic = p.italic;
267
+ fields.push("italic");
268
+ }
269
+ if (p.underline !== undefined) {
270
+ ts.underline = p.underline;
271
+ fields.push("underline");
272
+ }
273
+ if (p.strikethrough !== undefined) {
274
+ ts.strikethrough = p.strikethrough;
275
+ fields.push("strikethrough");
276
+ }
277
+ if (p.fontSizePt !== undefined) {
278
+ ts.fontSize = { magnitude: p.fontSizePt, unit: "PT" };
279
+ fields.push("fontSize");
280
+ }
281
+ if (p.fontFamily) {
282
+ ts.weightedFontFamily = { fontFamily: p.fontFamily };
283
+ fields.push("weightedFontFamily");
284
+ }
285
+ if (p.foregroundColorHex) {
286
+ const c = hexToRgbF(p.foregroundColorHex);
287
+ ts.foregroundColor = { color: { rgbColor: c } };
288
+ fields.push("foregroundColor");
289
+ }
290
+ if (p.backgroundColorHex) {
291
+ const c = hexToRgbF(p.backgroundColorHex);
292
+ ts.backgroundColor = { color: { rgbColor: c } };
293
+ fields.push("backgroundColor");
294
+ }
295
+ if (p.link) {
296
+ ts.link = { url: p.link };
297
+ fields.push("link");
298
+ }
299
+ if (fields.length === 0) {
300
+ throw new Error("googleDocs.document.updateTextStyle: at least one styling property required");
301
+ }
302
+ return runBatchUpdate(ctx, documentId, [
303
+ {
304
+ updateTextStyle: {
305
+ range: range(p),
306
+ textStyle: ts,
307
+ fields: fields.join(","),
308
+ },
309
+ },
310
+ ]);
311
+ },
312
+ });
313
+ }
@@ -1,5 +1,5 @@
1
1
  import * as t from "typebox";
2
- import { ATTACHMENT_FIELDS, assertAttachmentInScope, assertIssueInScope, gql, key, requireUnscoped } from "./shared.js";
2
+ import { ATTACHMENT_FIELDS, assertAttachmentInScope, assertIssueInScope, gql, key, requireUnscoped, } from "./shared.js";
3
3
  export function registerAttachmentActions(rl) {
4
4
  rl.registerAction("attachment.list", {
5
5
  description: "List issue attachments. Disabled for scoped Linear connections.",
@@ -24,15 +24,27 @@ export function registerAttachmentActions(rl) {
24
24
  rl.registerAction("attachment.create", {
25
25
  description: "Create an attachment on an issue.",
26
26
  inputSchema: t.Object({
27
- issueId: t.String({ description: "The issue to associate the attachment with. UUID or issue identifier (e.g., 'LIN-123')" }),
27
+ issueId: t.String({
28
+ description: "The issue to associate the attachment with. UUID or issue identifier (e.g., 'LIN-123')",
29
+ }),
28
30
  title: t.String({ description: "The attachment title" }),
29
- url: t.String({ description: "Attachment location, also used as a unique identifier. Re-creating with the same url updates the existing record" }),
31
+ url: t.String({
32
+ description: "Attachment location, also used as a unique identifier. Re-creating with the same url updates the existing record",
33
+ }),
30
34
  subtitle: t.Optional(t.String({ description: "The attachment subtitle" })),
31
- iconUrl: t.Optional(t.String({ description: "An icon url to display with the attachment (jpg or png, max 1MB, ideally 20x20px)" })),
35
+ iconUrl: t.Optional(t.String({
36
+ description: "An icon url to display with the attachment (jpg or png, max 1MB, ideally 20x20px)",
37
+ })),
32
38
  commentBody: t.Optional(t.String({ description: "Create a linked comment with markdown body" })),
33
- groupBySource: t.Optional(t.Boolean({ description: "Whether attachments for the same source application should be grouped in the Linear UI" })),
34
- metadata: t.Optional(t.Object({}, { description: "Attachment metadata object with string and number values (JSONObject)" })),
35
- id: t.Optional(t.String({ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one" })),
39
+ groupBySource: t.Optional(t.Boolean({
40
+ description: "Whether attachments for the same source application should be grouped in the Linear UI",
41
+ })),
42
+ metadata: t.Optional(t.Object({}, {
43
+ description: "Attachment metadata object with string and number values (JSONObject)",
44
+ })),
45
+ id: t.Optional(t.String({
46
+ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one",
47
+ })),
36
48
  }),
37
49
  async execute(input, ctx) {
38
50
  const fields = input;
@@ -44,11 +56,15 @@ export function registerAttachmentActions(rl) {
44
56
  rl.registerAction("attachment.update", {
45
57
  description: "Update an attachment. title is required.",
46
58
  inputSchema: t.Object({
47
- id: t.String({ description: "The identifier of the attachment to update" }),
59
+ id: t.String({
60
+ description: "The identifier of the attachment to update",
61
+ }),
48
62
  title: t.String({ description: "The attachment title" }),
49
63
  subtitle: t.Optional(t.String({ description: "The attachment subtitle" })),
50
64
  iconUrl: t.Optional(t.String({ description: "An icon url to display with the attachment" })),
51
- metadata: t.Optional(t.Object({}, { description: "Attachment metadata object with string and number values (JSONObject)" })),
65
+ metadata: t.Optional(t.Object({}, {
66
+ description: "Attachment metadata object with string and number values (JSONObject)",
67
+ })),
52
68
  }),
53
69
  async execute(input, ctx) {
54
70
  const { id, ...fields } = input;
@@ -60,10 +76,14 @@ export function registerAttachmentActions(rl) {
60
76
  rl.registerAction("attachment.linkURL", {
61
77
  description: "Link any URL to an issue. If a workspace integration matches the URL (Zendesk, GitHub, Slack, etc.) a rich attachment is created; otherwise a basic one.",
62
78
  inputSchema: t.Object({
63
- issueId: t.String({ description: "The issue for which to link the url. UUID or issue identifier (e.g., 'LIN-123')" }),
79
+ issueId: t.String({
80
+ description: "The issue for which to link the url. UUID or issue identifier (e.g., 'LIN-123')",
81
+ }),
64
82
  url: t.String({ description: "The url to link" }),
65
83
  title: t.Optional(t.String({ description: "The title to use for the attachment" })),
66
- id: t.Optional(t.String({ description: "The id for the attachment (optional UUID override)" })),
84
+ id: t.Optional(t.String({
85
+ description: "The id for the attachment (optional UUID override)",
86
+ })),
67
87
  }),
68
88
  async execute(input, ctx) {
69
89
  const { issueId, url, title, id } = input;
@@ -76,7 +96,11 @@ export function registerAttachmentActions(rl) {
76
96
  });
77
97
  rl.registerAction("attachment.delete", {
78
98
  description: "Delete an attachment.",
79
- inputSchema: t.Object({ id: t.String({ description: "The identifier of the attachment to delete" }) }),
99
+ inputSchema: t.Object({
100
+ id: t.String({
101
+ description: "The identifier of the attachment to delete",
102
+ }),
103
+ }),
80
104
  async execute(input, ctx) {
81
105
  const id = input.id;
82
106
  await assertAttachmentInScope(ctx, id);
@@ -1,14 +1,22 @@
1
1
  import * as t from "typebox";
2
- import { COMMENT_FIELDS, assertCommentInScope, assertIssueInScope, gql, key, requireUnscoped } from "./shared.js";
2
+ import { assertCommentInScope, assertIssueInScope, COMMENT_FIELDS, gql, key, requireUnscoped, } from "./shared.js";
3
3
  export function registerCommentActions(rl) {
4
4
  rl.registerAction("issue.addComment", {
5
5
  description: "Add a comment to an issue. Pass parentId to nest as a reply.",
6
6
  inputSchema: t.Object({
7
- issueId: t.String({ description: "The issue to associate the comment with. UUID or issue identifier (e.g., 'LIN-123')" }),
7
+ issueId: t.String({
8
+ description: "The issue to associate the comment with. UUID or issue identifier (e.g., 'LIN-123')",
9
+ }),
8
10
  body: t.String({ description: "The comment content in markdown format" }),
9
- parentId: t.Optional(t.String({ description: "The parent comment under which to nest as a reply" })),
10
- doNotSubscribeToIssue: t.Optional(t.Boolean({ description: "Prevent auto-subscription to the issue the comment is created on" })),
11
- quotedText: t.Optional(t.String({ description: "The text that this comment references (inline comments)" })),
11
+ parentId: t.Optional(t.String({
12
+ description: "The parent comment under which to nest as a reply",
13
+ })),
14
+ doNotSubscribeToIssue: t.Optional(t.Boolean({
15
+ description: "Prevent auto-subscription to the issue the comment is created on",
16
+ })),
17
+ quotedText: t.Optional(t.String({
18
+ description: "The text that this comment references (inline comments)",
19
+ })),
12
20
  }),
13
21
  async execute(input, ctx) {
14
22
  const fields = input;
@@ -20,7 +28,9 @@ export function registerCommentActions(rl) {
20
28
  rl.registerAction("comment.list", {
21
29
  description: "List comments. Pass issueId (UUID or identifier like 'LIN-123') to list one issue's comments; without it, lists workspace-wide (unscoped connections only).",
22
30
  inputSchema: t.Object({
23
- issueId: t.Optional(t.String({ description: "Only list comments on this issue. UUID or issue identifier (e.g., 'LIN-123')" })),
31
+ issueId: t.Optional(t.String({
32
+ description: "Only list comments on this issue. UUID or issue identifier (e.g., 'LIN-123')",
33
+ })),
24
34
  limit: t.Optional(t.Number({ description: "Max results (default 50)" })),
25
35
  }, { additionalProperties: false }),
26
36
  async execute(input, ctx) {
@@ -28,7 +38,7 @@ export function registerCommentActions(rl) {
28
38
  if (issueId) {
29
39
  await assertIssueInScope(ctx, issueId);
30
40
  const data = await gql(key(ctx), `query($id: String!, $first: Int) { issue(id: $id) { comments(first: $first) { nodes { ${COMMENT_FIELDS} } pageInfo { hasNextPage endCursor } } } }`, { id: issueId, first: limit });
31
- return data.issue?.comments ?? null;
41
+ return (data.issue?.comments ?? null);
32
42
  }
33
43
  requireUnscoped(ctx, "comment.list");
34
44
  const data = await gql(key(ctx), `query($first: Int) { comments(first: $first) { nodes { ${COMMENT_FIELDS} } pageInfo { hasNextPage endCursor } } }`, { first: limit });
@@ -50,7 +60,9 @@ export function registerCommentActions(rl) {
50
60
  inputSchema: t.Object({
51
61
  id: t.String({ description: "The identifier of the comment to update" }),
52
62
  body: t.Optional(t.String({ description: "The comment content in markdown format" })),
53
- quotedText: t.Optional(t.String({ description: "The text that this comment references (inline comments)" })),
63
+ quotedText: t.Optional(t.String({
64
+ description: "The text that this comment references (inline comments)",
65
+ })),
54
66
  }),
55
67
  async execute(input, ctx) {
56
68
  const { id, ...fields } = input;
@@ -1,5 +1,5 @@
1
1
  import * as t from "typebox";
2
- import { CYCLE_FIELDS, bindGetAction, bindListAction, gql, key, requireUnscoped } from "./shared.js";
2
+ import { bindGetAction, bindListAction, CYCLE_FIELDS, gql, key, requireUnscoped, } from "./shared.js";
3
3
  export function registerCycleActions(rl) {
4
4
  const listAction = bindListAction(rl);
5
5
  const getAction = bindGetAction(rl);
@@ -9,12 +9,20 @@ export function registerCycleActions(rl) {
9
9
  description: "Create a cycle for a team.",
10
10
  inputSchema: t.Object({
11
11
  teamId: t.String({ description: "The team to associate the cycle with" }),
12
- startsAt: t.String({ description: "The start time of the cycle (DateTime, ISO 8601)" }),
13
- endsAt: t.String({ description: "The end time of the cycle (DateTime, ISO 8601)" }),
12
+ startsAt: t.String({
13
+ description: "The start time of the cycle (DateTime, ISO 8601)",
14
+ }),
15
+ endsAt: t.String({
16
+ description: "The end time of the cycle (DateTime, ISO 8601)",
17
+ }),
14
18
  name: t.Optional(t.String({ description: "The custom name of the cycle" })),
15
19
  description: t.Optional(t.String({ description: "The description of the cycle" })),
16
- completedAt: t.Optional(t.String({ description: "The completion time of the cycle (DateTime). If null, the cycle hasn't been completed" })),
17
- id: t.Optional(t.String({ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one" })),
20
+ completedAt: t.Optional(t.String({
21
+ description: "The completion time of the cycle (DateTime). If null, the cycle hasn't been completed",
22
+ })),
23
+ id: t.Optional(t.String({
24
+ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one",
25
+ })),
18
26
  }),
19
27
  async execute(input, ctx) {
20
28
  requireUnscoped(ctx, "cycles.*");
@@ -28,9 +36,15 @@ export function registerCycleActions(rl) {
28
36
  id: t.String({ description: "The identifier of the cycle to update" }),
29
37
  name: t.Optional(t.String({ description: "The custom name of the cycle" })),
30
38
  description: t.Optional(t.String({ description: "The description of the cycle" })),
31
- startsAt: t.Optional(t.String({ description: "The start time of the cycle (DateTime, ISO 8601)" })),
32
- endsAt: t.Optional(t.String({ description: "The end time of the cycle (DateTime, ISO 8601)" })),
33
- completedAt: t.Optional(t.String({ description: "The completion time of the cycle (DateTime). If null, the cycle hasn't been completed" })),
39
+ startsAt: t.Optional(t.String({
40
+ description: "The start time of the cycle (DateTime, ISO 8601)",
41
+ })),
42
+ endsAt: t.Optional(t.String({
43
+ description: "The end time of the cycle (DateTime, ISO 8601)",
44
+ })),
45
+ completedAt: t.Optional(t.String({
46
+ description: "The completion time of the cycle (DateTime). If null, the cycle hasn't been completed",
47
+ })),
34
48
  }),
35
49
  async execute(input, ctx) {
36
50
  requireUnscoped(ctx, "cycles.*");
@@ -1,5 +1,5 @@
1
1
  import * as t from "typebox";
2
- import { INITIATIVE_FIELDS, bindGetAction, bindListAction, gql, key, requireUnscoped } from "./shared.js";
2
+ import { bindGetAction, bindListAction, gql, INITIATIVE_FIELDS, key, requireUnscoped, } from "./shared.js";
3
3
  export function registerInitiativeActions(rl) {
4
4
  const listAction = bindListAction(rl);
5
5
  const getAction = bindGetAction(rl);
@@ -10,15 +10,27 @@ export function registerInitiativeActions(rl) {
10
10
  inputSchema: t.Object({
11
11
  name: t.String({ description: "The name of the initiative" }),
12
12
  description: t.Optional(t.String({ description: "The description of the initiative" })),
13
- content: t.Optional(t.String({ description: "The initiative's content in markdown format" })),
13
+ content: t.Optional(t.String({
14
+ description: "The initiative's content in markdown format",
15
+ })),
14
16
  icon: t.Optional(t.String({ description: "The initiative's icon" })),
15
17
  color: t.Optional(t.String({ description: "The initiative's color (hex)" })),
16
18
  ownerId: t.Optional(t.String({ description: "The owner of the initiative" })),
17
- status: t.Optional(t.String({ description: "The initiative's status (InitiativeStatus: Planned | Active | Completed)" })),
18
- targetDate: t.Optional(t.String({ description: "The estimated completion date of the initiative (TimelessDate, YYYY-MM-DD)" })),
19
- targetDateResolution: t.Optional(t.String({ description: "The resolution of the initiative's estimated completion date (DateResolutionType)" })),
20
- sortOrder: t.Optional(t.Number({ description: "The sort order of the initiative within the workspace (Float)" })),
21
- id: t.Optional(t.String({ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one" })),
19
+ status: t.Optional(t.String({
20
+ description: "The initiative's status (InitiativeStatus: Planned | Active | Completed)",
21
+ })),
22
+ targetDate: t.Optional(t.String({
23
+ description: "The estimated completion date of the initiative (TimelessDate, YYYY-MM-DD)",
24
+ })),
25
+ targetDateResolution: t.Optional(t.String({
26
+ description: "The resolution of the initiative's estimated completion date (DateResolutionType)",
27
+ })),
28
+ sortOrder: t.Optional(t.Number({
29
+ description: "The sort order of the initiative within the workspace (Float)",
30
+ })),
31
+ id: t.Optional(t.String({
32
+ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one",
33
+ })),
22
34
  }),
23
35
  async execute(input, ctx) {
24
36
  requireUnscoped(ctx, "initiatives.*");
@@ -29,18 +41,32 @@ export function registerInitiativeActions(rl) {
29
41
  rl.registerAction("initiative.update", {
30
42
  description: "Update an initiative.",
31
43
  inputSchema: t.Object({
32
- id: t.String({ description: "The identifier of the initiative to update" }),
44
+ id: t.String({
45
+ description: "The identifier of the initiative to update",
46
+ }),
33
47
  name: t.Optional(t.String({ description: "The name of the initiative" })),
34
48
  description: t.Optional(t.String({ description: "The description of the initiative" })),
35
- content: t.Optional(t.String({ description: "The initiative's content in markdown format" })),
49
+ content: t.Optional(t.String({
50
+ description: "The initiative's content in markdown format",
51
+ })),
36
52
  icon: t.Optional(t.String({ description: "The initiative's icon" })),
37
53
  color: t.Optional(t.String({ description: "The initiative's color (hex)" })),
38
54
  ownerId: t.Optional(t.String({ description: "The owner of the initiative" })),
39
- status: t.Optional(t.String({ description: "The initiative's status (InitiativeStatus: Planned | Active | Completed)" })),
40
- targetDate: t.Optional(t.String({ description: "The estimated completion date (TimelessDate, YYYY-MM-DD). Set to null to clear" })),
41
- targetDateResolution: t.Optional(t.String({ description: "The resolution of the initiative's estimated completion date (DateResolutionType)" })),
42
- sortOrder: t.Optional(t.Number({ description: "The sort order of the initiative within the workspace (Float)" })),
43
- trashed: t.Optional(t.Boolean({ description: "Whether the initiative has been trashed. Set to true to trash, or null to restore" })),
55
+ status: t.Optional(t.String({
56
+ description: "The initiative's status (InitiativeStatus: Planned | Active | Completed)",
57
+ })),
58
+ targetDate: t.Optional(t.String({
59
+ description: "The estimated completion date (TimelessDate, YYYY-MM-DD). Set to null to clear",
60
+ })),
61
+ targetDateResolution: t.Optional(t.String({
62
+ description: "The resolution of the initiative's estimated completion date (DateResolutionType)",
63
+ })),
64
+ sortOrder: t.Optional(t.Number({
65
+ description: "The sort order of the initiative within the workspace (Float)",
66
+ })),
67
+ trashed: t.Optional(t.Boolean({
68
+ description: "Whether the initiative has been trashed. Set to true to trash, or null to restore",
69
+ })),
44
70
  }),
45
71
  async execute(input, ctx) {
46
72
  requireUnscoped(ctx, "initiatives.*");
@@ -51,7 +77,11 @@ export function registerInitiativeActions(rl) {
51
77
  });
52
78
  rl.registerAction("initiative.delete", {
53
79
  description: "Trash an initiative.",
54
- inputSchema: t.Object({ id: t.String({ description: "The identifier of the initiative to delete" }) }),
80
+ inputSchema: t.Object({
81
+ id: t.String({
82
+ description: "The identifier of the initiative to delete",
83
+ }),
84
+ }),
55
85
  async execute(input, ctx) {
56
86
  requireUnscoped(ctx, "initiatives.*");
57
87
  const data = await gql(key(ctx), `mutation($id: String!) { initiativeDelete(id: $id) { success } }`, { id: input.id });
@@ -61,10 +91,16 @@ export function registerInitiativeActions(rl) {
61
91
  rl.registerAction("initiative.addProject", {
62
92
  description: "Associate a project with an initiative. Use this action for project-to-initiative linking; project.update does not accept initiativeId. Verify with initiative.get or the returned initiative.projects list.",
63
93
  inputSchema: t.Object({
64
- initiativeId: t.String({ description: "The identifier of the initiative" }),
94
+ initiativeId: t.String({
95
+ description: "The identifier of the initiative",
96
+ }),
65
97
  projectId: t.String({ description: "The identifier of the project" }),
66
- sortOrder: t.Optional(t.Number({ description: "The sort order for the project within the initiative (Float)" })),
67
- id: t.Optional(t.String({ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one" })),
98
+ sortOrder: t.Optional(t.Number({
99
+ description: "The sort order for the project within the initiative (Float)",
100
+ })),
101
+ id: t.Optional(t.String({
102
+ description: "The identifier in UUID v4 format. If none is provided, the backend will generate one",
103
+ })),
68
104
  }),
69
105
  async execute(input, ctx) {
70
106
  requireUnscoped(ctx, "initiatives.*");
@@ -74,7 +110,11 @@ export function registerInitiativeActions(rl) {
74
110
  });
75
111
  rl.registerAction("initiative.removeProject", {
76
112
  description: "Remove a project from an initiative. Pass the link id returned by initiative.addProject, then verify with initiative.get.",
77
- inputSchema: t.Object({ id: t.String({ description: "The identifier of the initiativeToProject to delete" }) }),
113
+ inputSchema: t.Object({
114
+ id: t.String({
115
+ description: "The identifier of the initiativeToProject to delete",
116
+ }),
117
+ }),
78
118
  async execute(input, ctx) {
79
119
  requireUnscoped(ctx, "initiatives.*");
80
120
  const data = await gql(key(ctx), `mutation($id: String!) { initiativeToProjectDelete(id: $id) { success } }`, { id: input.id });