metheus-governance-mcp-cli 0.2.199 → 0.2.200

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 (2) hide show
  1. package/cli.mjs +114 -4
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -3314,6 +3314,81 @@ function buildRunnerRootWorkItemTransitionPath(currentStatusRaw, targetStatusRaw
3314
3314
  return [];
3315
3315
  }
3316
3316
 
3317
+ function buildRunnerRequestRecoveryPatchFromRouteState(currentStateRaw, requestRaw, routeKeyHint = "") {
3318
+ const currentState = safeObject(currentStateRaw);
3319
+ const request = safeObject(requestRaw);
3320
+ const requestKey = String(request.request_key || "").trim();
3321
+ if (!requestKey) {
3322
+ return {};
3323
+ }
3324
+ const requestSourceMessageID = intFromRawAllowZero(request.last_source_message_id, 0)
3325
+ || intFromRawAllowZero(request.source_message_id, 0);
3326
+ const routeKeys = uniqueOrderedStrings(
3327
+ [
3328
+ routeKeyHint,
3329
+ String(request.claimed_by_route || "").trim(),
3330
+ ],
3331
+ (value) => String(value || "").trim(),
3332
+ ).filter(Boolean);
3333
+ for (const routeKey of routeKeys) {
3334
+ const routeState = safeObject(safeObject(currentState.routes)[routeKey]);
3335
+ if (!Object.keys(routeState).length) {
3336
+ continue;
3337
+ }
3338
+ const routeSourceMessageID = intFromRawAllowZero(routeState.last_source_message_id, 0)
3339
+ || intFromRawAllowZero(routeState.source_message_id, 0);
3340
+ if (requestSourceMessageID && routeSourceMessageID && requestSourceMessageID !== routeSourceMessageID) {
3341
+ continue;
3342
+ }
3343
+ const patch = {};
3344
+ const recoveredRootWorkItemID = firstNonEmptyString([
3345
+ routeState.active_root_work_item_id,
3346
+ routeState.last_root_work_item_id,
3347
+ ]);
3348
+ if (!String(request.root_work_item_id || "").trim() && recoveredRootWorkItemID) {
3349
+ patch.root_work_item_id = recoveredRootWorkItemID;
3350
+ patch.root_work_item_title = firstNonEmptyString([
3351
+ request.root_work_item_title,
3352
+ routeState.active_root_work_item_title,
3353
+ routeState.last_root_work_item_title,
3354
+ ]);
3355
+ patch.root_work_item_status = normalizeRunnerWorkItemStatus(
3356
+ request.root_work_item_status
3357
+ || routeState.active_root_work_item_status
3358
+ || routeState.last_root_work_item_status,
3359
+ );
3360
+ }
3361
+ const requestStatus = normalizeRunnerRequestStatus(request.status);
3362
+ if (!isFinalRunnerRequestStatus(requestStatus)) {
3363
+ const routeAction = String(routeState.last_action || "").trim().toLowerCase();
3364
+ if (routeAction === "replied") {
3365
+ patch.status = "completed";
3366
+ patch.completed_at = firstNonEmptyString([
3367
+ request.completed_at,
3368
+ request.updated_at,
3369
+ new Date().toISOString(),
3370
+ ]);
3371
+ } else if (routeAction === "error" || routeAction === "skipped" || routeAction === "closed") {
3372
+ patch.status = "closed";
3373
+ patch.closed_at = firstNonEmptyString([
3374
+ request.closed_at,
3375
+ request.updated_at,
3376
+ new Date().toISOString(),
3377
+ ]);
3378
+ patch.closed_reason = firstNonEmptyString([
3379
+ request.closed_reason,
3380
+ routeState.last_reason,
3381
+ routeAction,
3382
+ ]);
3383
+ }
3384
+ }
3385
+ if (Object.keys(patch).length) {
3386
+ return patch;
3387
+ }
3388
+ }
3389
+ return {};
3390
+ }
3391
+
3317
3392
  async function syncRunnerRequestRootWorkItemForOutcome({
3318
3393
  normalizedRoute,
3319
3394
  runtime,
@@ -3327,7 +3402,19 @@ async function syncRunnerRequestRootWorkItemForOutcome({
3327
3402
  };
3328
3403
  }
3329
3404
  const currentState = loadBotRunnerState();
3330
- const request = safeObject(normalizeBotRunnerRequests(currentState.requests)[key]);
3405
+ let request = safeObject(normalizeBotRunnerRequests(currentState.requests)[key]);
3406
+ const recoveryPatch = buildRunnerRequestRecoveryPatchFromRouteState(currentState, request);
3407
+ if (Object.keys(recoveryPatch).length) {
3408
+ const recovered = upsertRunnerRequest(currentState, key, recoveryPatch);
3409
+ request = safeObject(recovered.request);
3410
+ saveBotRunnerState({
3411
+ routes: currentState.routes,
3412
+ sharedInboxes: currentState.sharedInboxes || currentState.shared_inboxes,
3413
+ excludedComments: currentState.excludedComments || currentState.excluded_comments,
3414
+ requests: recovered.requests,
3415
+ consumedComments: currentState.consumedComments || currentState.consumed_comments,
3416
+ });
3417
+ }
3331
3418
  const rootWorkItemID = String(request.root_work_item_id || "").trim();
3332
3419
  if (!rootWorkItemID) {
3333
3420
  return {
@@ -3746,6 +3833,20 @@ function mergeRunnerRequestForServerHydration(localEntryRaw, serverEntryRaw) {
3746
3833
  preserveLocalStringWhenServerBlank("root_thread_id");
3747
3834
  preserveLocalStringWhenServerBlank("root_work_item_created_at");
3748
3835
  preserveLocalStringWhenServerBlank("root_work_item_last_error");
3836
+ const localStatus = normalizeRunnerRequestStatus(localEntry.status);
3837
+ const serverStatus = normalizeRunnerRequestStatus(serverEntry.status);
3838
+ if (isFinalRunnerRequestStatus(localStatus) && !isFinalRunnerRequestStatus(serverStatus)) {
3839
+ merged.status = localStatus;
3840
+ if (String(localEntry.completed_at || "").trim()) {
3841
+ merged.completed_at = String(localEntry.completed_at || "").trim();
3842
+ }
3843
+ if (String(localEntry.closed_at || "").trim()) {
3844
+ merged.closed_at = String(localEntry.closed_at || "").trim();
3845
+ }
3846
+ if (String(localEntry.closed_reason || "").trim()) {
3847
+ merged.closed_reason = String(localEntry.closed_reason || "").trim();
3848
+ }
3849
+ }
3749
3850
  return merged;
3750
3851
  }
3751
3852
 
@@ -3930,9 +4031,18 @@ async function syncRunnerRequestLedgerForProjectToServer({ normalizedRoute, runt
3930
4031
  const commentStates = buildProjectRunnerRequestCommentStatesForSync(state, normalizedRoute);
3931
4032
 
3932
4033
  for (const request of requests) {
4034
+ const recoveryPatch = buildRunnerRequestRecoveryPatchFromRouteState(state, request);
4035
+ const recoveredRequest = Object.keys(recoveryPatch).length
4036
+ ? normalizeBotRunnerRequests({
4037
+ [String(request.request_key || "").trim()]: {
4038
+ ...safeObject(request),
4039
+ ...recoveryPatch,
4040
+ },
4041
+ })[String(request.request_key || "").trim()]
4042
+ : request;
3933
4043
  if (
3934
- isActionableRunnerRequestIntent(request.normalized_intent)
3935
- && !String(request.root_work_item_id || "").trim()
4044
+ isActionableRunnerRequestIntent(recoveredRequest.normalized_intent)
4045
+ && !String(recoveredRequest.root_work_item_id || "").trim()
3936
4046
  ) {
3937
4047
  continue;
3938
4048
  }
@@ -3942,7 +4052,7 @@ async function syncRunnerRequestLedgerForProjectToServer({ normalizedRoute, runt
3942
4052
  token: runtime.token,
3943
4053
  timeoutSeconds: runtime.timeoutSeconds,
3944
4054
  actorUserID: runtime.actor?.user_id,
3945
- request,
4055
+ request: recoveredRequest,
3946
4056
  });
3947
4057
  }
3948
4058
  for (const commentState of commentStates) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.199",
3
+ "version": "0.2.200",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [