@task-boards/mcp-server 0.22.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/cli.js CHANGED
@@ -43,7 +43,10 @@ var require_agent_runs_api = __commonJS({
43
43
  retryAgentRun: (id) => `${exports.AGENT_RUNS_PREFIX}/${id}/retry`,
44
44
  acknowledgeAgentRun: (id) => `${exports.AGENT_RUNS_PREFIX}/${id}/acknowledge`,
45
45
  setAgentRunAttention: (id) => `${exports.AGENT_RUNS_PREFIX}/${id}/attention`,
46
- completeAgentRun: (id) => `${exports.AGENT_RUNS_PREFIX}/${id}/complete`
46
+ completeAgentRun: (id) => `${exports.AGENT_RUNS_PREFIX}/${id}/complete`,
47
+ registerAgentRunProcess: (agentRunId) => `${exports.AGENT_RUNS_PREFIX}/${agentRunId}/process-registration`,
48
+ getAgentRunProcessRegistration: (agentRunId) => `${exports.AGENT_RUNS_PREFIX}/${agentRunId}/process-registration`,
49
+ unregisterAgentRunProcess: (agentRunId) => `${exports.AGENT_RUNS_PREFIX}/${agentRunId}/process-registration`
47
50
  };
48
51
  }
49
52
  });
@@ -656,7 +659,8 @@ var require_work_items_api = __commonJS({
656
659
  updateWorkItem: (id) => `${exports.WORK_ITEMS_PREFIX}/${id}`,
657
660
  deleteWorkItem: (id) => `${exports.WORK_ITEMS_PREFIX}/${id}`,
658
661
  getDeletePreview: (id) => `${exports.WORK_ITEMS_PREFIX}/${id}/delete-preview`,
659
- moveWorkItem: (id) => `${exports.WORK_ITEMS_PREFIX}/${id}/move`
662
+ moveWorkItem: (id) => `${exports.WORK_ITEMS_PREFIX}/${id}/move`,
663
+ stopWorkItemAgent: (workItemId) => `${exports.WORK_ITEMS_PREFIX}/${workItemId}/stop-agent`
660
664
  };
661
665
  }
662
666
  });
@@ -829,13 +833,24 @@ var require_feedback_enum = __commonJS({
829
833
  "../api/build/feedback/feedback.enum.js"(exports) {
830
834
  "use strict";
831
835
  Object.defineProperty(exports, "__esModule", { value: true });
832
- exports.FEEDBACK_TYPE = void 0;
836
+ exports.FEEDBACK_PULSE_ACTIVE_VIEW_VALUES = exports.FEEDBACK_PULSE_ACTIVE_VIEW = exports.FEEDBACK_INTERFACE_MODE = exports.FEEDBACK_TYPE = void 0;
833
837
  exports.FEEDBACK_TYPE = {
834
838
  BUG: "BUG",
835
839
  IMPROVEMENT: "IMPROVEMENT",
836
840
  QUESTION: "QUESTION",
837
841
  OTHER: "OTHER"
838
842
  };
843
+ exports.FEEDBACK_INTERFACE_MODE = {
844
+ PULSE: "pulse",
845
+ LEGACY: "legacy"
846
+ };
847
+ exports.FEEDBACK_PULSE_ACTIVE_VIEW = {
848
+ LIST: "list",
849
+ BOARD: "board",
850
+ TIMELINE: "timeline",
851
+ AGENTS: "agents"
852
+ };
853
+ exports.FEEDBACK_PULSE_ACTIVE_VIEW_VALUES = Object.values(exports.FEEDBACK_PULSE_ACTIVE_VIEW);
839
854
  }
840
855
  });
841
856
 
@@ -902,7 +917,9 @@ var require_notifications_enum = __commonJS({
902
917
  AGENT_NEEDS_CLARIFICATION: "AGENT_NEEDS_CLARIFICATION",
903
918
  AGENT_RUN_FAILED: "AGENT_RUN_FAILED",
904
919
  AGENT_QA_HAS_BUGS: "AGENT_QA_HAS_BUGS",
905
- AGENT_BATCH_COMPLETED: "AGENT_BATCH_COMPLETED"
920
+ AGENT_BATCH_COMPLETED: "AGENT_BATCH_COMPLETED",
921
+ WORK_ITEM_COMMENT: "WORK_ITEM_COMMENT",
922
+ WORK_ITEM_STATUS_CHANGE: "WORK_ITEM_STATUS_CHANGE"
906
923
  };
907
924
  }
908
925
  });
@@ -942,6 +959,74 @@ var require_notifications = __commonJS({
942
959
  }
943
960
  });
944
961
 
962
+ // ../api/build/activity-feed/activity-feed.api.js
963
+ var require_activity_feed_api = __commonJS({
964
+ "../api/build/activity-feed/activity-feed.api.js"(exports) {
965
+ "use strict";
966
+ Object.defineProperty(exports, "__esModule", { value: true });
967
+ exports.ACTIVITY_FEED_ROUTES = exports.ACTIVITY_FEED_PREFIX = void 0;
968
+ exports.ACTIVITY_FEED_PREFIX = "/activity-feed";
969
+ exports.ACTIVITY_FEED_ROUTES = {
970
+ listActivityFeed: () => exports.ACTIVITY_FEED_PREFIX,
971
+ getUnreadCount: () => `${exports.ACTIVITY_FEED_PREFIX}/unread-count`
972
+ };
973
+ }
974
+ });
975
+
976
+ // ../api/build/activity-feed/activity-feed.enum.js
977
+ var require_activity_feed_enum = __commonJS({
978
+ "../api/build/activity-feed/activity-feed.enum.js"(exports) {
979
+ "use strict";
980
+ Object.defineProperty(exports, "__esModule", { value: true });
981
+ exports.ACTIVITY_FEED_KIND_VALUES = exports.ACTIVITY_FEED_KIND = void 0;
982
+ exports.ACTIVITY_FEED_KIND = {
983
+ AGENT_IDE_ATTENTION: "AGENT_IDE_ATTENTION",
984
+ AGENT_NEEDS_CLARIFICATION: "AGENT_NEEDS_CLARIFICATION",
985
+ AGENT_RUN_FAILED: "AGENT_RUN_FAILED",
986
+ AGENT_QA_HAS_BUGS: "AGENT_QA_HAS_BUGS",
987
+ AGENT_BATCH_COMPLETED: "AGENT_BATCH_COMPLETED",
988
+ WORK_ITEM_COMMENT: "WORK_ITEM_COMMENT",
989
+ WORK_ITEM_STATUS_CHANGE: "WORK_ITEM_STATUS_CHANGE"
990
+ };
991
+ exports.ACTIVITY_FEED_KIND_VALUES = Object.values(exports.ACTIVITY_FEED_KIND);
992
+ }
993
+ });
994
+
995
+ // ../api/build/activity-feed/activity-feed.types.js
996
+ var require_activity_feed_types = __commonJS({
997
+ "../api/build/activity-feed/activity-feed.types.js"(exports) {
998
+ "use strict";
999
+ Object.defineProperty(exports, "__esModule", { value: true });
1000
+ }
1001
+ });
1002
+
1003
+ // ../api/build/activity-feed/index.js
1004
+ var require_activity_feed = __commonJS({
1005
+ "../api/build/activity-feed/index.js"(exports) {
1006
+ "use strict";
1007
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
1008
+ if (k2 === void 0) k2 = k;
1009
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1010
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1011
+ desc = { enumerable: true, get: function() {
1012
+ return m[k];
1013
+ } };
1014
+ }
1015
+ Object.defineProperty(o, k2, desc);
1016
+ }) : (function(o, m, k, k2) {
1017
+ if (k2 === void 0) k2 = k;
1018
+ o[k2] = m[k];
1019
+ }));
1020
+ var __exportStar = exports && exports.__exportStar || function(m, exports2) {
1021
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
1022
+ };
1023
+ Object.defineProperty(exports, "__esModule", { value: true });
1024
+ __exportStar(require_activity_feed_api(), exports);
1025
+ __exportStar(require_activity_feed_enum(), exports);
1026
+ __exportStar(require_activity_feed_types(), exports);
1027
+ }
1028
+ });
1029
+
945
1030
  // ../api/build/agent-runs/agent-runs.types.js
946
1031
  var require_agent_runs_types = __commonJS({
947
1032
  "../api/build/agent-runs/agent-runs.types.js"(exports) {
@@ -1007,6 +1092,7 @@ var require_build = __commonJS({
1007
1092
  __exportStar(require_comments(), exports);
1008
1093
  __exportStar(require_feedback(), exports);
1009
1094
  __exportStar(require_notifications(), exports);
1095
+ __exportStar(require_activity_feed(), exports);
1010
1096
  __exportStar(require_agent_runs_api(), exports);
1011
1097
  __exportStar(require_agent_runs_types(), exports);
1012
1098
  }
@@ -2287,6 +2373,7 @@ var require_realtime_events = __commonJS({
2287
2373
  WORK_ITEM_UPDATED: "work_item.updated",
2288
2374
  WORK_ITEM_MOVED: "work_item.moved",
2289
2375
  AGENT_RUN_STATUS_CHANGED: "agent_run.status_changed",
2376
+ AGENT_ACTIVITY: "agent.activity",
2290
2377
  COMMENT_CREATED: "comment.created",
2291
2378
  COMMENT_DELETED: "comment.deleted",
2292
2379
  WORK_ITEM_DELETED: "work_item.deleted",
@@ -3326,10 +3413,18 @@ var require_slug_util = __commonJS({
3326
3413
  "../shared/build/subagent/slug.util.js"(exports) {
3327
3414
  "use strict";
3328
3415
  Object.defineProperty(exports, "__esModule", { value: true });
3416
+ exports.isValidSubagentSlugFormat = isValidSubagentSlugFormat;
3329
3417
  exports.nameToSubagentSlug = nameToSubagentSlug;
3330
3418
  exports.resolveSlugCollision = resolveSlugCollision;
3331
3419
  var MAX_SUBAGENT_SLUG_LENGTH2 = 64;
3420
+ var SUBAGENT_SLUG_FORMAT_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3332
3421
  var FALLBACK_SLUG = "subagent";
3422
+ function isValidSubagentSlugFormat(slug) {
3423
+ if (slug.length === 0 || slug.length > MAX_SUBAGENT_SLUG_LENGTH2) {
3424
+ return false;
3425
+ }
3426
+ return SUBAGENT_SLUG_FORMAT_PATTERN.test(slug);
3427
+ }
3333
3428
  function nameToSubagentSlug(name) {
3334
3429
  const normalized = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
3335
3430
  if (normalized.length === 0) {
@@ -3432,7 +3527,7 @@ var require_subagent = __commonJS({
3432
3527
  "../shared/build/subagent/index.js"(exports) {
3433
3528
  "use strict";
3434
3529
  Object.defineProperty(exports, "__esModule", { value: true });
3435
- exports.buildSubagentFileContentFromBody = exports.buildSubagentFileContent = exports.buildSubagentDefinition = exports.buildSubagentBodyMarkdown = exports.resolveSlugCollision = exports.nameToSubagentSlug = exports.SUBAGENT_PREVIEW_MODE = exports.validateSubagentLlmBodyMarkdown = exports.validateSubagentLlmInput = exports.BUILTIN_IDE_SUBAGENT_SLUGS = void 0;
3530
+ exports.buildSubagentFileContentFromBody = exports.buildSubagentFileContent = exports.buildSubagentDefinition = exports.buildSubagentBodyMarkdown = exports.resolveSlugCollision = exports.nameToSubagentSlug = exports.isValidSubagentSlugFormat = exports.SUBAGENT_PREVIEW_MODE = exports.validateSubagentLlmBodyMarkdown = exports.validateSubagentLlmInput = exports.BUILTIN_IDE_SUBAGENT_SLUGS = void 0;
3436
3531
  var builtin_ide_subagents_const_1 = require_builtin_ide_subagents_const();
3437
3532
  Object.defineProperty(exports, "BUILTIN_IDE_SUBAGENT_SLUGS", { enumerable: true, get: function() {
3438
3533
  return builtin_ide_subagents_const_1.BUILTIN_IDE_SUBAGENT_SLUGS;
@@ -3450,6 +3545,9 @@ var require_subagent = __commonJS({
3450
3545
  return subagent_preview_mode_enum_1.SUBAGENT_PREVIEW_MODE;
3451
3546
  } });
3452
3547
  var slug_util_1 = require_slug_util();
3548
+ Object.defineProperty(exports, "isValidSubagentSlugFormat", { enumerable: true, get: function() {
3549
+ return slug_util_1.isValidSubagentSlugFormat;
3550
+ } });
3453
3551
  Object.defineProperty(exports, "nameToSubagentSlug", { enumerable: true, get: function() {
3454
3552
  return slug_util_1.nameToSubagentSlug;
3455
3553
  } });
@@ -3752,7 +3850,7 @@ var require_build2 = __commonJS({
3752
3850
  });
3753
3851
 
3754
3852
  // src/orchestrator/orchestrator-transport.ts
3755
- var import_agent_runs2 = __toESM(require_agent_runs_api(), 1);
3853
+ var import_agent_runs3 = __toESM(require_agent_runs_api(), 1);
3756
3854
  var import_shared5 = __toESM(require_build2(), 1);
3757
3855
 
3758
3856
  // src/tools/attachments.ts
@@ -3796,10 +3894,11 @@ var import_shared = __toESM(require_build2(), 1);
3796
3894
  import axios, { isAxiosError } from "axios";
3797
3895
  import FormData from "form-data";
3798
3896
  var RestClientError = class extends Error {
3799
- constructor(code, message, status) {
3897
+ constructor(code, message, status, details) {
3800
3898
  super(message);
3801
3899
  this.code = code;
3802
3900
  this.status = status;
3901
+ this.details = details;
3803
3902
  this.name = "RestClientError";
3804
3903
  }
3805
3904
  };
@@ -3859,7 +3958,7 @@ var RestClient = class {
3859
3958
  if (isAxiosError(error)) {
3860
3959
  const body = error.response?.data;
3861
3960
  if (this.isApiErrorBody(body)) {
3862
- throw new RestClientError(body.code, body.message, error.response?.status);
3961
+ throw new RestClientError(body.code, body.message, error.response?.status, body.details);
3863
3962
  }
3864
3963
  throw new RestClientError("HTTP_ERROR", this.sanitizeHttpErrorMessage(error.message), error.response?.status);
3865
3964
  }
@@ -3875,7 +3974,7 @@ var RestClient = class {
3875
3974
  if (isAxiosError(error)) {
3876
3975
  const body = error.response?.data;
3877
3976
  if (this.isApiErrorBody(body)) {
3878
- throw new RestClientError(body.code, body.message, error.response?.status);
3977
+ throw new RestClientError(body.code, body.message, error.response?.status, body.details);
3879
3978
  }
3880
3979
  throw new RestClientError("HTTP_ERROR", this.sanitizeHttpErrorMessage(error.message), error.response?.status);
3881
3980
  }
@@ -4022,21 +4121,75 @@ function shouldSanitizeResponses() {
4022
4121
  return serverConfig.sanitizeResponses !== false;
4023
4122
  }
4024
4123
 
4025
- // src/tools/tool-utils.ts
4026
- function jsonResult(data) {
4124
+ // src/tools/agent-version-stale.util.ts
4125
+ function isRecord(value) {
4126
+ return typeof value === "object" && value !== null;
4127
+ }
4128
+ function isAgentVersionStaleErrorBody(value) {
4129
+ if (!isRecord(value)) {
4130
+ return false;
4131
+ }
4132
+ return typeof value.expectedVersion === "number" && typeof value.serverVersion === "number" && typeof value.serverUpdatedAt === "string";
4133
+ }
4134
+ function extractFieldConflictsFromAgentVersionStale(details) {
4135
+ if (details === void 0 || !isAgentVersionStaleErrorBody(details)) {
4136
+ return [];
4137
+ }
4138
+ const conflictingFields = details.diffSummary?.conflictingFields;
4139
+ if (!Array.isArray(conflictingFields)) {
4140
+ return [];
4141
+ }
4142
+ return conflictingFields.filter((field) => typeof field === "string");
4143
+ }
4144
+
4145
+ // src/tools/structured-tool-result.util.ts
4146
+ function buildSuccessStructuredResult(payload, textPayload) {
4027
4147
  return {
4028
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
4148
+ content: [{ type: "text", text: JSON.stringify(textPayload, null, 2) }],
4149
+ structuredContent: payload
4029
4150
  };
4030
4151
  }
4031
- function toolError(code, message) {
4032
- const sanitizedMessage = shouldSanitizeResponses() ? (0, import_shared2.sanitizeMcpErrorMessage)(message) : message;
4152
+ function buildErrorStructuredResult(payload, textPayload) {
4033
4153
  return {
4034
4154
  isError: true,
4035
- content: [{ type: "text", text: JSON.stringify({ code, message: sanitizedMessage }) }]
4155
+ content: [{ type: "text", text: JSON.stringify(textPayload) }],
4156
+ structuredContent: payload
4157
+ };
4158
+ }
4159
+ function successStructuredPayload(data) {
4160
+ return { kind: "success", data };
4161
+ }
4162
+ function errorStructuredPayload(code, message, extras) {
4163
+ return {
4164
+ kind: "error",
4165
+ code,
4166
+ message,
4167
+ ...extras?.fieldConflicts !== void 0 ? { fieldConflicts: extras.fieldConflicts } : {}
4036
4168
  };
4037
4169
  }
4170
+
4171
+ // src/tools/tool-utils.ts
4172
+ function jsonResult(data) {
4173
+ return buildSuccessStructuredResult(successStructuredPayload(data), data);
4174
+ }
4175
+ function toolError(code, message, extras) {
4176
+ const sanitizedMessage = shouldSanitizeResponses() ? (0, import_shared2.sanitizeMcpErrorMessage)(message) : message;
4177
+ const textPayload = { code, message: sanitizedMessage };
4178
+ if (extras?.fieldConflicts !== void 0) {
4179
+ textPayload.fieldConflicts = extras.fieldConflicts;
4180
+ }
4181
+ return buildErrorStructuredResult(errorStructuredPayload(code, sanitizedMessage, extras), textPayload);
4182
+ }
4038
4183
  function toToolError(error) {
4039
- if (error instanceof RestClientError || error instanceof WorkspaceError) {
4184
+ if (error instanceof RestClientError) {
4185
+ if (error.code === "AGENT_VERSION_STALE") {
4186
+ return toolError(error.code, error.message, {
4187
+ fieldConflicts: extractFieldConflictsFromAgentVersionStale(error.details)
4188
+ });
4189
+ }
4190
+ return toolError(error.code, error.message);
4191
+ }
4192
+ if (error instanceof WorkspaceError) {
4040
4193
  return toolError(error.code, error.message);
4041
4194
  }
4042
4195
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -4281,145 +4434,11 @@ async function syncProjectSubagents(client, params) {
4281
4434
  }
4282
4435
 
4283
4436
  // src/tools/wait-for-agent-runs.ts
4284
- var import_agent_runs = __toESM(require_agent_runs_api(), 1);
4437
+ var import_agent_runs2 = __toESM(require_agent_runs_api(), 1);
4285
4438
  var import_agent_run_status = __toESM(require_agent_run_status_enum(), 1);
4286
- var DEFAULT_RETRY_BASE_MS = 500;
4287
- var DEFAULT_RETRY_MAX_MS = 3e4;
4288
- var DEFAULT_INFLIGHT_LIMIT = 10;
4289
- function sleep(ms) {
4290
- return new Promise((resolve4) => {
4291
- setTimeout(resolve4, ms);
4292
- });
4293
- }
4294
- function isTransientClaimError(error) {
4295
- if (!(error instanceof RestClientError)) {
4296
- return false;
4297
- }
4298
- if (error.status === void 0) {
4299
- return error.code === "HTTP_ERROR";
4300
- }
4301
- return error.status >= 500;
4302
- }
4303
- function computeBackoffMs(consecutiveFailures, baseMs, maxMs) {
4304
- const exponential = baseMs * 2 ** (consecutiveFailures - 1);
4305
- return Math.min(exponential, maxMs);
4306
- }
4307
- function compareInflightRuns(a, b) {
4308
- if (a.requiresAttention !== b.requiresAttention) {
4309
- return a.requiresAttention ? -1 : 1;
4310
- }
4311
- const aDispatched = a.dispatchedAt ?? "";
4312
- const bDispatched = b.dispatchedAt ?? "";
4313
- return aDispatched.localeCompare(bDispatched);
4314
- }
4315
- async function fetchInflightAgentRuns(client, options) {
4316
- const limit = options.limit ?? DEFAULT_INFLIGHT_LIMIT;
4317
- const page = await client.get(import_agent_runs.AGENT_RUNS_ROUTES.listAgentRuns(), {
4318
- projectId: options.projectId,
4319
- activeOnly: "true",
4320
- limit: String(limit)
4321
- });
4322
- const filtered = page.items.filter(
4323
- (run) => run.status === import_agent_run_status.AGENT_RUN_STATUS.DISPATCHED || run.status === import_agent_run_status.AGENT_RUN_STATUS.ACKNOWLEDGED
4324
- );
4325
- filtered.sort(compareInflightRuns);
4326
- return filtered.slice(0, limit);
4327
- }
4328
- async function pollAgentRuns(client, options, deps) {
4329
- const { projectId, timeoutMs, pollIntervalMs, limit } = options;
4330
- if (pollIntervalMs > timeoutMs) {
4331
- throw new WorkspaceError("VALIDATION_ERROR", "pollInterval must not exceed timeout");
4332
- }
4333
- const sleepFn = deps?.sleep ?? sleep;
4334
- const deadline = Date.now() + timeoutMs;
4335
- const claimLimit = limit ?? 1;
4336
- const retryBaseMs = options.retryBaseMs ?? DEFAULT_RETRY_BASE_MS;
4337
- const retryMaxMs = options.retryMaxMs ?? DEFAULT_RETRY_MAX_MS;
4338
- let consecutiveFailures = 0;
4339
- while (true) {
4340
- let response;
4341
- try {
4342
- response = await client.post(import_agent_runs.AGENT_RUNS_ROUTES.claimAgentRuns(), {
4343
- projectId,
4344
- limit: claimLimit
4345
- });
4346
- consecutiveFailures = 0;
4347
- } catch (error) {
4348
- if (!isTransientClaimError(error)) {
4349
- throw error;
4350
- }
4351
- if (Date.now() >= deadline) {
4352
- return { items: [], inflightRuns: [], timedOut: true };
4353
- }
4354
- consecutiveFailures += 1;
4355
- const backoffMs = computeBackoffMs(consecutiveFailures, retryBaseMs, retryMaxMs);
4356
- const remainingMs2 = deadline - Date.now();
4357
- await sleepFn(Math.min(backoffMs, remainingMs2));
4358
- continue;
4359
- }
4360
- if (response.items.length > 0) {
4361
- return { items: response.items, inflightRuns: [], timedOut: false };
4362
- }
4363
- const inflightRuns = await fetchInflightAgentRuns(client, { projectId, limit: claimLimit });
4364
- if (inflightRuns.length > 0) {
4365
- return { items: [], inflightRuns, timedOut: false };
4366
- }
4367
- if (Date.now() >= deadline) {
4368
- return { items: [], inflightRuns: [], timedOut: true };
4369
- }
4370
- const remainingMs = deadline - Date.now();
4371
- const waitMs = Math.min(pollIntervalMs, remainingMs);
4372
- await sleepFn(waitMs);
4373
- }
4374
- }
4375
4439
 
4376
- // src/orchestrator/orchestrator-transport.ts
4377
- var OrchestratorTransport = class {
4378
- constructor(client, options = {}) {
4379
- this.client = client;
4380
- this.options = options;
4381
- }
4382
- async claimAndPoll(options, deps) {
4383
- return pollAgentRuns(this.client, options, deps);
4384
- }
4385
- async fetchInflightRuns(projectId, limit) {
4386
- return fetchInflightAgentRuns(this.client, { projectId, limit });
4387
- }
4388
- async ackRun(agentRunId, note) {
4389
- const body = note !== void 0 ? { note } : void 0;
4390
- return this.client.patch(import_agent_runs2.AGENT_RUNS_ROUTES.acknowledgeAgentRun(agentRunId), body);
4391
- }
4392
- async setAttention(agentRunId, requiresAttention, message) {
4393
- const body = requiresAttention ? { requiresAttention: true, attentionMessage: message ?? "" } : { requiresAttention: false };
4394
- return this.client.patch(import_agent_runs2.AGENT_RUNS_ROUTES.setAgentRunAttention(agentRunId), body);
4395
- }
4396
- async completeRun(agentRunId, body) {
4397
- return this.client.post(import_agent_runs2.AGENT_RUNS_ROUTES.completeAgentRun(agentRunId), body);
4398
- }
4399
- async listAttachments(workItemId) {
4400
- return fetchAttachments(this.client, workItemId);
4401
- }
4402
- async downloadAttachments(workItemId, workspaceRoot, attachmentIds) {
4403
- return downloadWorkItemAttachments(this.client, {
4404
- workItemId,
4405
- workspaceRoot,
4406
- attachmentIds,
4407
- blockSensitiveAttachments: this.options.blockSensitiveAttachments ?? true
4408
- });
4409
- }
4410
- async syncSubagents(projectId, workspaceRoot) {
4411
- return syncProjectSubagents(this.client, { projectId, workspaceRoot });
4412
- }
4413
- async createComment(workItemId, body) {
4414
- return postComment(this.client, workItemId, body);
4415
- }
4416
- };
4417
- function createOrchestratorTransport(client, config) {
4418
- return new OrchestratorTransport(client, {
4419
- workspaceRoot: config?.workspaceRoot,
4420
- blockSensitiveAttachments: config?.blockSensitiveAttachments
4421
- });
4422
- }
4440
+ // src/agent-process/stop-signal.handler.ts
4441
+ var import_agent_runs = __toESM(require_agent_runs_api(), 1);
4423
4442
 
4424
4443
  // src/orchestrator/active-run-state.ts
4425
4444
  import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
@@ -4428,7 +4447,7 @@ var ACTIVE_RUN_STATE_RELATIVE_PATH = ".cursor/orchestrator-active-run.json";
4428
4447
  var ATTENTION_PENDING_RELATIVE_PATH = ".cursor/orchestrator-attention-pending.json";
4429
4448
  var ACTIVE_RUN_LEASE_MINUTES = 30;
4430
4449
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
4431
- function isRecord(value) {
4450
+ function isRecord2(value) {
4432
4451
  return typeof value === "object" && value !== null && !Array.isArray(value);
4433
4452
  }
4434
4453
  function isUuid(value) {
@@ -4454,7 +4473,7 @@ function ensureCursorDir(workspaceRoot) {
4454
4473
  }
4455
4474
  }
4456
4475
  function parseActiveRunState(raw) {
4457
- if (!isRecord(raw)) {
4476
+ if (!isRecord2(raw)) {
4458
4477
  return null;
4459
4478
  }
4460
4479
  const version = raw.version;
@@ -4476,7 +4495,7 @@ function parseActiveRunState(raw) {
4476
4495
  };
4477
4496
  }
4478
4497
  function parseAttentionPendingState(raw) {
4479
- if (!isRecord(raw)) {
4498
+ if (!isRecord2(raw)) {
4480
4499
  return null;
4481
4500
  }
4482
4501
  const agentRunId = raw.agentRunId;
@@ -4563,6 +4582,248 @@ function clearOrchestratorBridgeState(workspaceRoot) {
4563
4582
  clearAttentionPendingState(workspaceRoot);
4564
4583
  }
4565
4584
 
4585
+ // src/agent-process/local-process-registry.ts
4586
+ var registrations = /* @__PURE__ */ new Map();
4587
+ function registerLocalProcess(agentRunId, workItemId, pid) {
4588
+ const entry = {
4589
+ agentRunId,
4590
+ workItemId,
4591
+ pid,
4592
+ registeredAt: (/* @__PURE__ */ new Date()).toISOString()
4593
+ };
4594
+ registrations.set(agentRunId, entry);
4595
+ return entry;
4596
+ }
4597
+ function getLocalProcess(agentRunId) {
4598
+ return registrations.get(agentRunId);
4599
+ }
4600
+ function unregisterLocalProcess(agentRunId) {
4601
+ registrations.delete(agentRunId);
4602
+ }
4603
+
4604
+ // src/agent-process/stop-signal.handler.ts
4605
+ var STOP_SIGTERM_GRACE_MS = 5e3;
4606
+ function defaultSleep(ms) {
4607
+ return new Promise((resolve4) => {
4608
+ setTimeout(resolve4, ms);
4609
+ });
4610
+ }
4611
+ function resolveWorkspaceRootForConfig(config) {
4612
+ try {
4613
+ return resolveWorkspaceRoot(void 0, config.workspaceRoot);
4614
+ } catch {
4615
+ return null;
4616
+ }
4617
+ }
4618
+ async function signalProcessGracefully(pid, deps) {
4619
+ const kill = deps.kill ?? process.kill.bind(process);
4620
+ const sleep2 = deps.sleep ?? defaultSleep;
4621
+ try {
4622
+ kill(pid, "SIGINT");
4623
+ } catch (error) {
4624
+ const code = error.code;
4625
+ if (code === "ESRCH") {
4626
+ return false;
4627
+ }
4628
+ deps.logWarn?.(`stop signal SIGINT failed for pid=${pid}: ${code ?? "unknown"}`);
4629
+ return false;
4630
+ }
4631
+ await sleep2(STOP_SIGTERM_GRACE_MS);
4632
+ try {
4633
+ kill(pid, "SIGTERM");
4634
+ } catch (error) {
4635
+ const code = error.code;
4636
+ if (code === "ESRCH") {
4637
+ return true;
4638
+ }
4639
+ deps.logWarn?.(`stop signal SIGTERM failed for pid=${pid}: ${code ?? "unknown"}`);
4640
+ }
4641
+ return true;
4642
+ }
4643
+ async function applyStopSignal(client, config, agentRunId, deps = {}) {
4644
+ let registration;
4645
+ try {
4646
+ registration = await client.get(
4647
+ import_agent_runs.AGENT_RUNS_ROUTES.getAgentRunProcessRegistration(agentRunId)
4648
+ );
4649
+ } catch {
4650
+ return false;
4651
+ }
4652
+ if (!registration.stopRequested) {
4653
+ return false;
4654
+ }
4655
+ const local = getLocalProcess(agentRunId);
4656
+ const pid = local?.pid ?? registration.pid;
4657
+ const signaled = await signalProcessGracefully(pid, deps);
4658
+ const workspaceRoot = resolveWorkspaceRootForConfig(config);
4659
+ if (workspaceRoot !== null) {
4660
+ const activeState = readActiveRunState(workspaceRoot);
4661
+ if (activeState?.agentRunId === agentRunId) {
4662
+ clearOrchestratorBridgeState(workspaceRoot);
4663
+ }
4664
+ }
4665
+ try {
4666
+ await client.delete(import_agent_runs.AGENT_RUNS_ROUTES.unregisterAgentRunProcess(agentRunId));
4667
+ } catch {
4668
+ deps.logWarn?.(`failed to unregister process registration for agentRunId=${agentRunId}`);
4669
+ }
4670
+ unregisterLocalProcess(agentRunId);
4671
+ return signaled;
4672
+ }
4673
+ async function pollActiveRunStopSignal(client, config, deps = {}) {
4674
+ const workspaceRoot = resolveWorkspaceRootForConfig(config);
4675
+ if (workspaceRoot === null) {
4676
+ return false;
4677
+ }
4678
+ const activeState = readActiveRunState(workspaceRoot);
4679
+ if (activeState === null) {
4680
+ return false;
4681
+ }
4682
+ return applyStopSignal(client, config, activeState.agentRunId, deps);
4683
+ }
4684
+
4685
+ // src/tools/wait-for-agent-runs.ts
4686
+ var DEFAULT_RETRY_BASE_MS = 500;
4687
+ var DEFAULT_RETRY_MAX_MS = 3e4;
4688
+ var DEFAULT_INFLIGHT_LIMIT = 10;
4689
+ function sleep(ms) {
4690
+ return new Promise((resolve4) => {
4691
+ setTimeout(resolve4, ms);
4692
+ });
4693
+ }
4694
+ function isTransientClaimError(error) {
4695
+ if (!(error instanceof RestClientError)) {
4696
+ return false;
4697
+ }
4698
+ if (error.status === void 0) {
4699
+ return error.code === "HTTP_ERROR";
4700
+ }
4701
+ return error.status >= 500;
4702
+ }
4703
+ function computeBackoffMs(consecutiveFailures, baseMs, maxMs) {
4704
+ const exponential = baseMs * 2 ** (consecutiveFailures - 1);
4705
+ return Math.min(exponential, maxMs);
4706
+ }
4707
+ function compareInflightRuns(a, b) {
4708
+ if (a.requiresAttention !== b.requiresAttention) {
4709
+ return a.requiresAttention ? -1 : 1;
4710
+ }
4711
+ const aDispatched = a.dispatchedAt ?? "";
4712
+ const bDispatched = b.dispatchedAt ?? "";
4713
+ return aDispatched.localeCompare(bDispatched);
4714
+ }
4715
+ async function fetchInflightAgentRuns(client, options) {
4716
+ const limit = options.limit ?? DEFAULT_INFLIGHT_LIMIT;
4717
+ const page = await client.get(import_agent_runs2.AGENT_RUNS_ROUTES.listAgentRuns(), {
4718
+ projectId: options.projectId,
4719
+ activeOnly: "true",
4720
+ limit: String(limit)
4721
+ });
4722
+ const filtered = page.items.filter(
4723
+ (run) => run.status === import_agent_run_status.AGENT_RUN_STATUS.DISPATCHED || run.status === import_agent_run_status.AGENT_RUN_STATUS.ACKNOWLEDGED
4724
+ );
4725
+ filtered.sort(compareInflightRuns);
4726
+ return filtered.slice(0, limit);
4727
+ }
4728
+ async function pollAgentRuns(client, options, deps) {
4729
+ const { projectId, timeoutMs, pollIntervalMs, limit } = options;
4730
+ if (pollIntervalMs > timeoutMs) {
4731
+ throw new WorkspaceError("VALIDATION_ERROR", "pollInterval must not exceed timeout");
4732
+ }
4733
+ const sleepFn = deps?.sleep ?? sleep;
4734
+ const deadline = Date.now() + timeoutMs;
4735
+ const claimLimit = limit ?? 1;
4736
+ const retryBaseMs = options.retryBaseMs ?? DEFAULT_RETRY_BASE_MS;
4737
+ const retryMaxMs = options.retryMaxMs ?? DEFAULT_RETRY_MAX_MS;
4738
+ let consecutiveFailures = 0;
4739
+ while (true) {
4740
+ if (options.stopSignal !== void 0) {
4741
+ await pollActiveRunStopSignal(client, options.stopSignal.config);
4742
+ }
4743
+ let response;
4744
+ try {
4745
+ response = await client.post(import_agent_runs2.AGENT_RUNS_ROUTES.claimAgentRuns(), {
4746
+ projectId,
4747
+ limit: claimLimit
4748
+ });
4749
+ consecutiveFailures = 0;
4750
+ } catch (error) {
4751
+ if (!isTransientClaimError(error)) {
4752
+ throw error;
4753
+ }
4754
+ if (Date.now() >= deadline) {
4755
+ return { items: [], inflightRuns: [], timedOut: true };
4756
+ }
4757
+ consecutiveFailures += 1;
4758
+ const backoffMs = computeBackoffMs(consecutiveFailures, retryBaseMs, retryMaxMs);
4759
+ const remainingMs2 = deadline - Date.now();
4760
+ await sleepFn(Math.min(backoffMs, remainingMs2));
4761
+ continue;
4762
+ }
4763
+ if (response.items.length > 0) {
4764
+ return { items: response.items, inflightRuns: [], timedOut: false };
4765
+ }
4766
+ const inflightRuns = await fetchInflightAgentRuns(client, { projectId, limit: claimLimit });
4767
+ if (inflightRuns.length > 0) {
4768
+ return { items: [], inflightRuns, timedOut: false };
4769
+ }
4770
+ if (Date.now() >= deadline) {
4771
+ return { items: [], inflightRuns: [], timedOut: true };
4772
+ }
4773
+ const remainingMs = deadline - Date.now();
4774
+ const waitMs = Math.min(pollIntervalMs, remainingMs);
4775
+ await sleepFn(waitMs);
4776
+ }
4777
+ }
4778
+
4779
+ // src/orchestrator/orchestrator-transport.ts
4780
+ var OrchestratorTransport = class {
4781
+ constructor(client, options = {}) {
4782
+ this.client = client;
4783
+ this.options = options;
4784
+ }
4785
+ async claimAndPoll(options, deps) {
4786
+ return pollAgentRuns(this.client, options, deps);
4787
+ }
4788
+ async fetchInflightRuns(projectId, limit) {
4789
+ return fetchInflightAgentRuns(this.client, { projectId, limit });
4790
+ }
4791
+ async ackRun(agentRunId, note) {
4792
+ const body = note !== void 0 ? { note } : void 0;
4793
+ return this.client.patch(import_agent_runs3.AGENT_RUNS_ROUTES.acknowledgeAgentRun(agentRunId), body);
4794
+ }
4795
+ async setAttention(agentRunId, requiresAttention, message) {
4796
+ const body = requiresAttention ? { requiresAttention: true, attentionMessage: message ?? "" } : { requiresAttention: false };
4797
+ return this.client.patch(import_agent_runs3.AGENT_RUNS_ROUTES.setAgentRunAttention(agentRunId), body);
4798
+ }
4799
+ async completeRun(agentRunId, body) {
4800
+ return this.client.post(import_agent_runs3.AGENT_RUNS_ROUTES.completeAgentRun(agentRunId), body);
4801
+ }
4802
+ async listAttachments(workItemId) {
4803
+ return fetchAttachments(this.client, workItemId);
4804
+ }
4805
+ async downloadAttachments(workItemId, workspaceRoot, attachmentIds) {
4806
+ return downloadWorkItemAttachments(this.client, {
4807
+ workItemId,
4808
+ workspaceRoot,
4809
+ attachmentIds,
4810
+ blockSensitiveAttachments: this.options.blockSensitiveAttachments ?? true
4811
+ });
4812
+ }
4813
+ async syncSubagents(projectId, workspaceRoot) {
4814
+ return syncProjectSubagents(this.client, { projectId, workspaceRoot });
4815
+ }
4816
+ async createComment(workItemId, body) {
4817
+ return postComment(this.client, workItemId, body);
4818
+ }
4819
+ };
4820
+ function createOrchestratorTransport(client, config) {
4821
+ return new OrchestratorTransport(client, {
4822
+ workspaceRoot: config?.workspaceRoot,
4823
+ blockSensitiveAttachments: config?.blockSensitiveAttachments
4824
+ });
4825
+ }
4826
+
4566
4827
  // src/workspace/parse-task-boards-yaml.ts
4567
4828
  import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
4568
4829
  import { join as join4 } from "node:path";
@@ -4741,7 +5002,7 @@ function buildSmartModeAttentionMessage(toolName, reason) {
4741
5002
  }
4742
5003
 
4743
5004
  // src/attention/hook-payload.util.ts
4744
- function isRecord2(value) {
5005
+ function isRecord3(value) {
4745
5006
  return typeof value === "object" && value !== null && !Array.isArray(value);
4746
5007
  }
4747
5008
  function readString(record, key) {
@@ -4758,7 +5019,7 @@ function parseHookPayloadJson(raw) {
4758
5019
  }
4759
5020
  try {
4760
5021
  const parsed = JSON.parse(trimmed);
4761
- if (!isRecord2(parsed)) {
5022
+ if (!isRecord3(parsed)) {
4762
5023
  return null;
4763
5024
  }
4764
5025
  return parsed;
@@ -5514,7 +5775,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5514
5775
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5515
5776
 
5516
5777
  // src/tools/agent-runs.ts
5517
- var import_agent_runs3 = __toESM(require_agent_runs_api(), 1);
5778
+ var import_agent_runs4 = __toESM(require_agent_runs_api(), 1);
5518
5779
  var import_agent_run_outcome = __toESM(require_agent_run_outcome_enum(), 1);
5519
5780
  var import_agent_run_status4 = __toESM(require_agent_run_status_enum(), 1);
5520
5781
  import { z as z3 } from "zod";
@@ -5770,7 +6031,7 @@ function registerAgentRunTools(server, client, config) {
5770
6031
  },
5771
6032
  async ({ status, projectId }) => runTool(async () => {
5772
6033
  const effectiveStatus = status ?? import_agent_run_status4.AGENT_RUN_STATUS.PENDING;
5773
- return client.get(import_agent_runs3.AGENT_RUNS_ROUTES.listAgentRuns(), {
6034
+ return client.get(import_agent_runs4.AGENT_RUNS_ROUTES.listAgentRuns(), {
5774
6035
  status: effectiveStatus,
5775
6036
  projectId
5776
6037
  });
@@ -5792,7 +6053,8 @@ function registerAgentRunTools(server, client, config) {
5792
6053
  projectId,
5793
6054
  timeoutMs: timeout * 1e3,
5794
6055
  pollIntervalMs: pollInterval * 1e3,
5795
- limit
6056
+ limit,
6057
+ stopSignal: { config }
5796
6058
  });
5797
6059
  return enrichPollResult(pollResult.items, pollResult.inflightRuns, pollResult.timedOut);
5798
6060
  })
@@ -5808,8 +6070,13 @@ function registerAgentRunTools(server, client, config) {
5808
6070
  },
5809
6071
  async ({ agentRunId, note }) => runTool(async () => {
5810
6072
  const body = note !== void 0 ? { note } : void 0;
5811
- const response = await client.patch(import_agent_runs3.AGENT_RUNS_ROUTES.acknowledgeAgentRun(agentRunId), body);
6073
+ const response = await client.patch(import_agent_runs4.AGENT_RUNS_ROUTES.acknowledgeAgentRun(agentRunId), body);
5812
6074
  writeActiveRunFromAck(config, response);
6075
+ try {
6076
+ await client.post(import_agent_runs4.AGENT_RUNS_ROUTES.registerAgentRunProcess(agentRunId), { pid: process.pid });
6077
+ registerLocalProcess(agentRunId, response.workItemId, process.pid);
6078
+ } catch {
6079
+ }
5813
6080
  return response;
5814
6081
  })
5815
6082
  );
@@ -5827,7 +6094,7 @@ function registerAgentRunTools(server, client, config) {
5827
6094
  requiresAttention: true,
5828
6095
  attentionMessage: message
5829
6096
  };
5830
- return client.patch(import_agent_runs3.AGENT_RUNS_ROUTES.setAgentRunAttention(agentRunId), body);
6097
+ return client.patch(import_agent_runs4.AGENT_RUNS_ROUTES.setAgentRunAttention(agentRunId), body);
5831
6098
  })
5832
6099
  );
5833
6100
  server.registerTool(
@@ -5842,7 +6109,7 @@ function registerAgentRunTools(server, client, config) {
5842
6109
  const body = {
5843
6110
  requiresAttention: false
5844
6111
  };
5845
- return client.patch(import_agent_runs3.AGENT_RUNS_ROUTES.setAgentRunAttention(agentRunId), body);
6112
+ return client.patch(import_agent_runs4.AGENT_RUNS_ROUTES.setAgentRunAttention(agentRunId), body);
5846
6113
  })
5847
6114
  );
5848
6115
  server.registerTool(
@@ -5875,10 +6142,15 @@ function registerAgentRunTools(server, client, config) {
5875
6142
  }
5876
6143
  const hasBody = outcome !== void 0 || note !== void 0 || workItemPatch !== void 0 && workItemPatch !== null;
5877
6144
  const response = await client.post(
5878
- import_agent_runs3.AGENT_RUNS_ROUTES.completeAgentRun(agentRunId),
6145
+ import_agent_runs4.AGENT_RUNS_ROUTES.completeAgentRun(agentRunId),
5879
6146
  hasBody ? body : void 0
5880
6147
  );
5881
6148
  clearActiveRunAfterComplete(config);
6149
+ try {
6150
+ await client.delete(import_agent_runs4.AGENT_RUNS_ROUTES.unregisterAgentRunProcess(agentRunId));
6151
+ } catch {
6152
+ }
6153
+ unregisterLocalProcess(agentRunId);
5882
6154
  return response;
5883
6155
  })
5884
6156
  );
@@ -6088,8 +6360,12 @@ async function runOrchestratorOnce(client, options) {
6088
6360
  projectId,
6089
6361
  timeoutMs: options.timeoutMs,
6090
6362
  pollIntervalMs: options.pollIntervalMs,
6091
- limit: options.limit
6363
+ limit: options.limit,
6364
+ stopSignal: options.config !== void 0 ? { config: options.config } : void 0
6092
6365
  });
6366
+ if (options.config !== void 0) {
6367
+ await pollActiveRunStopSignal(client, options.config);
6368
+ }
6093
6369
  const enriched = enrichPollResult(pollResult.items, pollResult.inflightRuns, pollResult.timedOut);
6094
6370
  return {
6095
6371
  projectId,
@@ -6120,7 +6396,8 @@ function registerOrchestratorTools(server, client, config) {
6120
6396
  pollIntervalMs: pollInterval * 1e3,
6121
6397
  limit,
6122
6398
  workspaceRootOverride: workspaceRoot,
6123
- envWorkspaceRoot: config.workspaceRoot
6399
+ envWorkspaceRoot: config.workspaceRoot,
6400
+ config
6124
6401
  })
6125
6402
  )
6126
6403
  );
@@ -6579,6 +6856,14 @@ async function deleteWorkItem(client, workItemId) {
6579
6856
  const body = { confirmCascade: false };
6580
6857
  await client.delete(import_work_items.WORK_ITEMS_ROUTES.deleteWorkItem(workItemId), body);
6581
6858
  }
6859
+ async function patchWorkItemWithCurrentVersion(client, workItemId, fields) {
6860
+ const current = await client.get(import_work_items.WORK_ITEMS_ROUTES.getWorkItem(workItemId));
6861
+ const body = {
6862
+ ...fields,
6863
+ version: current.version
6864
+ };
6865
+ return client.patch(import_work_items.WORK_ITEMS_ROUTES.updateWorkItem(workItemId), body);
6866
+ }
6582
6867
  function registerWorkItemTools(server, client) {
6583
6868
  server.registerTool(
6584
6869
  "list_work_items",
@@ -6681,7 +6966,7 @@ function registerWorkItemTools(server, client) {
6681
6966
  server.registerTool(
6682
6967
  "update_work_item",
6683
6968
  {
6684
- description: "Update work item fields (fetches current version first).",
6969
+ description: "Update work item fields (fetches current version first). On stale version returns AGENT_VERSION_STALE with fieldConflicts \u2014 no automatic retry; re-fetch get_work_item and reconcile manually.",
6685
6970
  inputSchema: {
6686
6971
  workItemId: z11.string().uuid().describe("Work item UUID"),
6687
6972
  title: z11.string().min(1).max(512).optional().describe("Updated title"),
@@ -6714,9 +6999,8 @@ function registerWorkItemTools(server, client) {
6714
6999
  codeChangesRequired,
6715
7000
  completed,
6716
7001
  labelIds
6717
- }) => runTool(async () => {
6718
- const current = await client.get(import_work_items.WORK_ITEMS_ROUTES.getWorkItem(workItemId));
6719
- const body = {
7002
+ }) => runTool(
7003
+ async () => patchWorkItemWithCurrentVersion(client, workItemId, {
6720
7004
  title,
6721
7005
  description,
6722
7006
  acceptanceCriteria,
@@ -6728,11 +7012,9 @@ function registerWorkItemTools(server, client) {
6728
7012
  assigneeUserId,
6729
7013
  codeChangesRequired,
6730
7014
  completed,
6731
- labelIds,
6732
- version: current.version
6733
- };
6734
- return client.patch(import_work_items.WORK_ITEMS_ROUTES.updateWorkItem(workItemId), body);
6735
- })
7015
+ labelIds
7016
+ })
7017
+ )
6736
7018
  );
6737
7019
  server.registerTool(
6738
7020
  "move_work_item",