happy-imou-cloud 2.1.37 → 2.1.39

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 (25) hide show
  1. package/dist/{BaseReasoningProcessor-Do2r_eVW.cjs → BaseReasoningProcessor-BUTolvO5.cjs} +2 -2
  2. package/dist/{BaseReasoningProcessor-CotgApeZ.mjs → BaseReasoningProcessor-Cbp6sIDm.mjs} +2 -2
  3. package/dist/{ProviderSelectionHandler-CywTx_Df.cjs → ProviderSelectionHandler-B22eXuym.cjs} +2 -2
  4. package/dist/{ProviderSelectionHandler-CCsorkyV.mjs → ProviderSelectionHandler-DrSgStLw.mjs} +2 -2
  5. package/dist/{api-CexMNqai.cjs → api-BoeZDGwx.cjs} +121 -1
  6. package/dist/{api-CMJhY7of.mjs → api-wcqkneTg.mjs} +121 -2
  7. package/dist/{command-Ct7Eeo2F.cjs → command-CkYq_KwA.cjs} +2 -2
  8. package/dist/{command-C2YB2hE-.mjs → command-DcgK0y3F.mjs} +2 -2
  9. package/dist/{index-4t8rMnvz.mjs → index-B9mt95QV.mjs} +201 -39
  10. package/dist/{index-CQ2Yq72y.cjs → index-Cgor8CE7.cjs} +204 -42
  11. package/dist/index.cjs +2 -2
  12. package/dist/index.mjs +2 -2
  13. package/dist/lib.cjs +1 -1
  14. package/dist/lib.d.cts +94 -36
  15. package/dist/lib.d.mts +94 -36
  16. package/dist/lib.mjs +1 -1
  17. package/dist/{registerKillSessionHandler-CLFQ8bQP.mjs → registerKillSessionHandler-Buc97BEh.mjs} +246 -10
  18. package/dist/{registerKillSessionHandler-C1PIogKI.cjs → registerKillSessionHandler-DtXhn2Cd.cjs} +249 -9
  19. package/dist/{runClaude-BiFuU4AP.mjs → runClaude-BYKNCDEU.mjs} +58 -20
  20. package/dist/{runClaude-L4G4BbIJ.cjs → runClaude-CwXQwmgw.cjs} +58 -20
  21. package/dist/{runCodex-CaUoS6E4.cjs → runCodex-BkB_YKhV.cjs} +58 -10
  22. package/dist/{runCodex-C0wjgp2b.mjs → runCodex-DqAddhDE.mjs} +58 -10
  23. package/dist/{runGemini-DxQX5VhV.mjs → runGemini-3jkfOtlr.mjs} +79 -11
  24. package/dist/{runGemini-DhYi_crP.cjs → runGemini-B4uXPrue.cjs} +79 -11
  25. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import { k as initialMachineMetadata, R as RuntimeShell, f as formatDisplayMessage, l as resolveCanonicalToolNameV2, m as isTerminalReferenceOnlyPayload } from './index-4t8rMnvz.mjs';
2
- import { r as readSettings, H as HeadTailPreviewBuffer, d as HAPPY_ORG_REPLY_ACK_VERSION, e as HAPPY_ORG_TURN_REPORT_TAG, f as HAPPY_ORG_SUMMARY_MAX_LENGTH, g as HAPPY_ORG_REPEAT_THRESHOLD, l as logger } from './api-CMJhY7of.mjs';
1
+ import { k as initialMachineMetadata, R as RuntimeShell, f as formatDisplayMessage, l as resolveCanonicalToolNameV2, m as isTerminalReferenceOnlyPayload } from './index-B9mt95QV.mjs';
2
+ import { r as readSettings, H as HeadTailPreviewBuffer, d as HAPPY_ORG_REPLY_ACK_VERSION, e as HAPPY_ORG_TURN_REPORT_TAG, f as HAPPY_ORG_SUMMARY_MAX_LENGTH, g as HAPPY_ORG_REPEAT_THRESHOLD, l as logger } from './api-wcqkneTg.mjs';
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { basename } from 'node:path';
5
5
  import { createHash } from 'crypto';
@@ -115,11 +115,11 @@ function renderTerminalOutputPreview(value, opts) {
115
115
  }
116
116
 
117
117
  const DISPLAY_FRIENDLY_TOOL_FIELDS = ["stdout", "stderr", "output", "text", "message", "detail", "reason", "data"];
118
- function isRecord(value) {
118
+ function isRecord$1(value) {
119
119
  return !!value && typeof value === "object" && !Array.isArray(value);
120
120
  }
121
121
  function stripInternalToolMeta(value) {
122
- if (!isRecord(value)) {
122
+ if (!isRecord$1(value)) {
123
123
  return value;
124
124
  }
125
125
  const {
@@ -140,7 +140,7 @@ function extractNestedTextContent(value) {
140
140
  const parts = value.map((item) => extractNestedTextContent(item)).filter((item) => typeof item === "string" && item.length > 0);
141
141
  return parts.length > 0 ? parts.join("\n") : null;
142
142
  }
143
- if (!isRecord(value)) {
143
+ if (!isRecord$1(value)) {
144
144
  return null;
145
145
  }
146
146
  if (typeof value.text === "string" && value.text.trim().length > 0) {
@@ -160,7 +160,7 @@ function humanizeToolLabel(rawToolName) {
160
160
  return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
161
161
  }
162
162
  function isToolLifecycleResult(value) {
163
- if (!isRecord(value)) {
163
+ if (!isRecord$1(value)) {
164
164
  return false;
165
165
  }
166
166
  return typeof value.state === "string" && ("messages" in value || "description" in value || "createdAt" in value || "startedAt" in value || "completedAt" in value);
@@ -209,7 +209,7 @@ function normalizeCodexToolOutput(rawToolName, value) {
209
209
  if (isTerminalReferenceOnlyPayload(normalizedLifecyclePayload)) {
210
210
  return void 0;
211
211
  }
212
- if (!isRecord(normalizedLifecyclePayload)) {
212
+ if (!isRecord$1(normalizedLifecyclePayload)) {
213
213
  return normalizedLifecyclePayload;
214
214
  }
215
215
  const hasDisplayFriendlyField = DISPLAY_FRIENDLY_TOOL_FIELDS.some((field) => field in normalizedLifecyclePayload);
@@ -236,7 +236,7 @@ function truncateProviderOutputValue(value, label, seen = /* @__PURE__ */ new We
236
236
  if (Array.isArray(value)) {
237
237
  return renderOutputPreview(value, label);
238
238
  }
239
- if (!isRecord(value)) {
239
+ if (!isRecord$1(value)) {
240
240
  return value;
241
241
  }
242
242
  if (seen.has(value)) {
@@ -307,7 +307,7 @@ function hasDisplayPayload(value) {
307
307
  if (Array.isArray(sanitized)) {
308
308
  return sanitized.length > 0;
309
309
  }
310
- if (isRecord(sanitized)) {
310
+ if (isRecord$1(sanitized)) {
311
311
  return Object.keys(sanitized).length > 0;
312
312
  }
313
313
  return true;
@@ -504,6 +504,242 @@ async function syncControlledByUserState(sessionClient, controlledByUser) {
504
504
  });
505
505
  }
506
506
 
507
+ const SESSION_LABEL_MAX_LENGTH = 60;
508
+ const TITLE_MAX_LENGTH = 80;
509
+ const BODY_MAX_LENGTH = 140;
510
+ function isRecord(value) {
511
+ return !!value && typeof value === "object" && !Array.isArray(value);
512
+ }
513
+ function normalizeText(value) {
514
+ if (typeof value !== "string") {
515
+ return null;
516
+ }
517
+ const normalized = value.replace(/\s+/g, " ").trim();
518
+ return normalized.length > 0 ? normalized : null;
519
+ }
520
+ function truncateText(value, maxLength) {
521
+ if (value.length <= maxLength) {
522
+ return value;
523
+ }
524
+ return `${value.slice(0, maxLength - 1).trimEnd()}\u2026`;
525
+ }
526
+ function toProviderKey(providerLabel) {
527
+ const normalized = normalizeText(providerLabel)?.toLowerCase();
528
+ if (!normalized) {
529
+ return "unknown";
530
+ }
531
+ if (normalized === "claude" || normalized === "claude code" || normalized === "cloud code") {
532
+ return "claude";
533
+ }
534
+ if (normalized === "codex") {
535
+ return "codex";
536
+ }
537
+ if (normalized === "gemini") {
538
+ return "gemini";
539
+ }
540
+ return normalized.replace(/\s+/g, "-");
541
+ }
542
+ function deriveNotificationProviderLabel(providerLabel) {
543
+ const normalized = normalizeText(providerLabel)?.toLowerCase();
544
+ if (!normalized) {
545
+ return "Agent";
546
+ }
547
+ if (normalized === "claude" || normalized === "claude code" || normalized === "cloud code") {
548
+ return "Claude";
549
+ }
550
+ if (normalized === "codex") {
551
+ return "Codex";
552
+ }
553
+ if (normalized === "gemini") {
554
+ return "Gemini";
555
+ }
556
+ return normalizeText(providerLabel) ?? "Agent";
557
+ }
558
+ function buildNotificationTitle(sessionLabel, providerLabel, actionLabel) {
559
+ const providerDisplayLabel = deriveNotificationProviderLabel(providerLabel);
560
+ const suffix = ` \xB7 ${providerDisplayLabel} \xB7 ${actionLabel}`;
561
+ const maxSessionLength = Math.max(12, TITLE_MAX_LENGTH - suffix.length);
562
+ return `${truncateText(sessionLabel, maxSessionLength)}${suffix}`;
563
+ }
564
+ function derivePathLabel(path) {
565
+ const normalized = normalizeText(path);
566
+ if (!normalized) {
567
+ return null;
568
+ }
569
+ const segments = normalized.split(/[\\/]+/).filter(Boolean);
570
+ return segments[segments.length - 1] ?? normalized;
571
+ }
572
+ function deriveHomeLabel(homeSlug) {
573
+ const normalized = normalizeText(homeSlug);
574
+ if (!normalized) {
575
+ return null;
576
+ }
577
+ return normalized.replace(/[_-]+/g, " ");
578
+ }
579
+ function deriveNotificationSessionLabel(metadata, providerLabel) {
580
+ const label = normalizeText(metadata?.name) ?? normalizeText(metadata?.summary?.text) ?? deriveHomeLabel(metadata?.happyOrg?.specialistHome?.homeSlug) ?? derivePathLabel(metadata?.path) ?? normalizeText(providerLabel) ?? "Session";
581
+ return truncateText(label, SESSION_LABEL_MAX_LENGTH);
582
+ }
583
+ function deriveNotificationSummary(candidates, fallback, sessionLabel) {
584
+ for (const candidate of candidates) {
585
+ const normalized = normalizeText(candidate);
586
+ if (!normalized) {
587
+ continue;
588
+ }
589
+ const truncated = truncateText(normalized, BODY_MAX_LENGTH);
590
+ if (truncated.toLowerCase() !== sessionLabel.toLowerCase()) {
591
+ return truncated;
592
+ }
593
+ }
594
+ return truncateText(fallback, BODY_MAX_LENGTH);
595
+ }
596
+ function cleanExtraData(extraData) {
597
+ return Object.fromEntries(
598
+ Object.entries(extraData).filter(([, value]) => {
599
+ if (value === null || value === void 0) {
600
+ return false;
601
+ }
602
+ if (typeof value === "string") {
603
+ return value.trim().length > 0;
604
+ }
605
+ return true;
606
+ })
607
+ );
608
+ }
609
+ function buildRouteData(opts) {
610
+ const taskContext = opts.metadata?.happyOrg?.taskContext ?? null;
611
+ const routeTaskId = opts.report?.taskId ?? taskContext?.taskId ?? null;
612
+ const routePositionId = opts.report?.positionId ?? taskContext?.positionId ?? null;
613
+ const routeSessionId = normalizeText(opts.sessionId);
614
+ const data = {
615
+ notificationKind: opts.notificationKind,
616
+ provider: toProviderKey(opts.providerLabel)
617
+ };
618
+ if (opts.routePreference === "session" && routeSessionId) {
619
+ data.sessionId = routeSessionId;
620
+ } else if (routeTaskId) {
621
+ data.taskId = routeTaskId;
622
+ } else if (routeSessionId) {
623
+ data.sessionId = routeSessionId;
624
+ } else if (routePositionId) {
625
+ data.positionId = routePositionId;
626
+ }
627
+ Object.assign(data, cleanExtraData({
628
+ contextTaskId: data.taskId ? null : routeTaskId,
629
+ contextPositionId: data.positionId ? null : routePositionId,
630
+ memberAgentId: opts.report?.memberAgentId ?? taskContext?.memberAgentId ?? null,
631
+ supervisorAgentId: opts.report?.supervisorAgentId ?? taskContext?.supervisorAgentId ?? null
632
+ }));
633
+ if (opts.extraData) {
634
+ Object.assign(data, cleanExtraData(opts.extraData));
635
+ }
636
+ return data;
637
+ }
638
+ function humanizeToolName(toolName) {
639
+ const normalized = normalizeText(toolName);
640
+ if (!normalized) {
641
+ return "continue";
642
+ }
643
+ const replacements = {
644
+ bash: "run a command",
645
+ execute: "run a command",
646
+ read: "read a file",
647
+ write: "write a file",
648
+ edit: "edit a file",
649
+ multiedit: "edit files",
650
+ patch: "apply a patch",
651
+ fetch: "fetch a page",
652
+ search: "search the web"
653
+ };
654
+ const replacement = replacements[normalized.toLowerCase()];
655
+ if (replacement) {
656
+ return replacement;
657
+ }
658
+ return normalized.replace(/[_-]+/g, " ");
659
+ }
660
+ function extractPermissionRequestPushContext(message) {
661
+ const payload = isRecord(message.payload) ? message.payload : null;
662
+ const toolName = normalizeText(payload?.toolName) ?? normalizeText(message.reason);
663
+ const payloadDescription = normalizeText(payload?.description);
664
+ const reasonDescription = normalizeText(message.reason);
665
+ let description = payloadDescription;
666
+ if (!description && reasonDescription && reasonDescription.toLowerCase() !== (toolName ?? "").toLowerCase()) {
667
+ description = reasonDescription;
668
+ }
669
+ if (description && toolName && description.toLowerCase() === toolName.toLowerCase()) {
670
+ description = null;
671
+ }
672
+ return {
673
+ requestId: message.id,
674
+ toolName,
675
+ description
676
+ };
677
+ }
678
+ function buildReadyPushNotification(opts) {
679
+ const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
680
+ const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
681
+ return {
682
+ title: buildNotificationTitle(sessionLabel, opts.providerLabel, "Ready"),
683
+ body: truncateText(`${providerDisplayLabel} is waiting for your next message`, BODY_MAX_LENGTH),
684
+ data: buildRouteData({
685
+ ...opts,
686
+ notificationKind: "ready",
687
+ routePreference: "session"
688
+ })
689
+ };
690
+ }
691
+ function buildPermissionPushNotification(opts) {
692
+ const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
693
+ const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
694
+ const fallback = `${providerDisplayLabel} needs your approval to ${humanizeToolName(opts.toolName)}`;
695
+ const body = deriveNotificationSummary([opts.description], fallback, sessionLabel);
696
+ return {
697
+ title: buildNotificationTitle(sessionLabel, opts.providerLabel, "Permission needed"),
698
+ body,
699
+ data: buildRouteData({
700
+ ...opts,
701
+ notificationKind: "permission_request",
702
+ routePreference: "session",
703
+ extraData: {
704
+ requestId: opts.requestId,
705
+ tool: opts.toolName ?? null,
706
+ ...opts.extraData
707
+ }
708
+ })
709
+ };
710
+ }
711
+ function buildTurnResultPushNotification(opts) {
712
+ const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
713
+ const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
714
+ const report = opts.report ?? null;
715
+ const explicitSummary = normalizeText(report?.summary) ?? normalizeText(opts.responseText);
716
+ if (!explicitSummary) {
717
+ return null;
718
+ }
719
+ const fallback = `${providerDisplayLabel} has a new result ready`;
720
+ const body = deriveNotificationSummary(
721
+ [
722
+ explicitSummary
723
+ ],
724
+ fallback,
725
+ sessionLabel
726
+ );
727
+ const action = report?.turnStatus === "task_complete" ? "Task complete" : "New result";
728
+ return {
729
+ title: buildNotificationTitle(sessionLabel, opts.providerLabel, action),
730
+ body,
731
+ data: buildRouteData({
732
+ ...opts,
733
+ report,
734
+ notificationKind: "turn_result",
735
+ routePreference: "session",
736
+ extraData: {
737
+ turnStatus: report?.turnStatus ?? "turn_update"
738
+ }
739
+ })
740
+ };
741
+ }
742
+
507
743
  const STRUCTURED_FIELD_PATTERN = /^\s*([a-z_]+)\s*=\s*(.*?)\s*$/;
508
744
  const KEY_VALUE_LINE_PATTERN = /^([A-Za-z0-9_]+)=(.*)$/;
509
745
  const HAPPY_ORG_READ_ACK = "yes";
@@ -2486,4 +2722,4 @@ function registerKillSessionHandler(rpcHandlerManager, killThisHappy) {
2486
2722
  });
2487
2723
  }
2488
2724
 
2489
- export { BasePermissionHandler as B, ConversationHistory$1 as C, INTERACTION_SUPERSEDED_ERROR as I, MissingMachineIdError as M, INTERACTION_TIMED_OUT_ERROR as a, MessageQueue2 as b, registerKillSessionHandler as c, MessageBuffer as d, ensureManagedProviderMachine as e, buildHappyOrgTurnPrompt as f, getPendingInteractionTimeoutMs as g, hashObject as h, finalizeHappyOrgTurnWithBusinessAck as i, renderTerminalOutputPreview as j, inferToolResultError as k, launchRuntimeHandleWithFactoryResult as l, forwardAgentMessageToProviderSession as m, resolveHappyOrgQueuedTurn as r, syncControlledByUserState as s, waitForResponseCompleteWithAbort as w };
2725
+ export { BasePermissionHandler as B, ConversationHistory$1 as C, INTERACTION_SUPERSEDED_ERROR as I, MissingMachineIdError as M, INTERACTION_TIMED_OUT_ERROR as a, MessageQueue2 as b, registerKillSessionHandler as c, MessageBuffer as d, ensureManagedProviderMachine as e, buildHappyOrgTurnPrompt as f, getPendingInteractionTimeoutMs as g, hashObject as h, finalizeHappyOrgTurnWithBusinessAck as i, buildTurnResultPushNotification as j, buildReadyPushNotification as k, launchRuntimeHandleWithFactoryResult as l, extractPermissionRequestPushContext as m, buildPermissionPushNotification as n, renderTerminalOutputPreview as o, inferToolResultError as p, forwardAgentMessageToProviderSession as q, resolveHappyOrgQueuedTurn as r, syncControlledByUserState as s, waitForResponseCompleteWithAbort as w };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CQ2Yq72y.cjs');
4
- var persistence = require('./api-CexMNqai.cjs');
3
+ var index = require('./index-Cgor8CE7.cjs');
4
+ var persistence = require('./api-BoeZDGwx.cjs');
5
5
  var node_crypto = require('node:crypto');
6
6
  var path = require('node:path');
7
7
  var crypto = require('crypto');
@@ -117,11 +117,11 @@ function renderTerminalOutputPreview(value, opts) {
117
117
  }
118
118
 
119
119
  const DISPLAY_FRIENDLY_TOOL_FIELDS = ["stdout", "stderr", "output", "text", "message", "detail", "reason", "data"];
120
- function isRecord(value) {
120
+ function isRecord$1(value) {
121
121
  return !!value && typeof value === "object" && !Array.isArray(value);
122
122
  }
123
123
  function stripInternalToolMeta(value) {
124
- if (!isRecord(value)) {
124
+ if (!isRecord$1(value)) {
125
125
  return value;
126
126
  }
127
127
  const {
@@ -142,7 +142,7 @@ function extractNestedTextContent(value) {
142
142
  const parts = value.map((item) => extractNestedTextContent(item)).filter((item) => typeof item === "string" && item.length > 0);
143
143
  return parts.length > 0 ? parts.join("\n") : null;
144
144
  }
145
- if (!isRecord(value)) {
145
+ if (!isRecord$1(value)) {
146
146
  return null;
147
147
  }
148
148
  if (typeof value.text === "string" && value.text.trim().length > 0) {
@@ -162,7 +162,7 @@ function humanizeToolLabel(rawToolName) {
162
162
  return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
163
163
  }
164
164
  function isToolLifecycleResult(value) {
165
- if (!isRecord(value)) {
165
+ if (!isRecord$1(value)) {
166
166
  return false;
167
167
  }
168
168
  return typeof value.state === "string" && ("messages" in value || "description" in value || "createdAt" in value || "startedAt" in value || "completedAt" in value);
@@ -211,7 +211,7 @@ function normalizeCodexToolOutput(rawToolName, value) {
211
211
  if (index.isTerminalReferenceOnlyPayload(normalizedLifecyclePayload)) {
212
212
  return void 0;
213
213
  }
214
- if (!isRecord(normalizedLifecyclePayload)) {
214
+ if (!isRecord$1(normalizedLifecyclePayload)) {
215
215
  return normalizedLifecyclePayload;
216
216
  }
217
217
  const hasDisplayFriendlyField = DISPLAY_FRIENDLY_TOOL_FIELDS.some((field) => field in normalizedLifecyclePayload);
@@ -238,7 +238,7 @@ function truncateProviderOutputValue(value, label, seen = /* @__PURE__ */ new We
238
238
  if (Array.isArray(value)) {
239
239
  return renderOutputPreview(value, label);
240
240
  }
241
- if (!isRecord(value)) {
241
+ if (!isRecord$1(value)) {
242
242
  return value;
243
243
  }
244
244
  if (seen.has(value)) {
@@ -309,7 +309,7 @@ function hasDisplayPayload(value) {
309
309
  if (Array.isArray(sanitized)) {
310
310
  return sanitized.length > 0;
311
311
  }
312
- if (isRecord(sanitized)) {
312
+ if (isRecord$1(sanitized)) {
313
313
  return Object.keys(sanitized).length > 0;
314
314
  }
315
315
  return true;
@@ -506,6 +506,242 @@ async function syncControlledByUserState(sessionClient, controlledByUser) {
506
506
  });
507
507
  }
508
508
 
509
+ const SESSION_LABEL_MAX_LENGTH = 60;
510
+ const TITLE_MAX_LENGTH = 80;
511
+ const BODY_MAX_LENGTH = 140;
512
+ function isRecord(value) {
513
+ return !!value && typeof value === "object" && !Array.isArray(value);
514
+ }
515
+ function normalizeText(value) {
516
+ if (typeof value !== "string") {
517
+ return null;
518
+ }
519
+ const normalized = value.replace(/\s+/g, " ").trim();
520
+ return normalized.length > 0 ? normalized : null;
521
+ }
522
+ function truncateText(value, maxLength) {
523
+ if (value.length <= maxLength) {
524
+ return value;
525
+ }
526
+ return `${value.slice(0, maxLength - 1).trimEnd()}\u2026`;
527
+ }
528
+ function toProviderKey(providerLabel) {
529
+ const normalized = normalizeText(providerLabel)?.toLowerCase();
530
+ if (!normalized) {
531
+ return "unknown";
532
+ }
533
+ if (normalized === "claude" || normalized === "claude code" || normalized === "cloud code") {
534
+ return "claude";
535
+ }
536
+ if (normalized === "codex") {
537
+ return "codex";
538
+ }
539
+ if (normalized === "gemini") {
540
+ return "gemini";
541
+ }
542
+ return normalized.replace(/\s+/g, "-");
543
+ }
544
+ function deriveNotificationProviderLabel(providerLabel) {
545
+ const normalized = normalizeText(providerLabel)?.toLowerCase();
546
+ if (!normalized) {
547
+ return "Agent";
548
+ }
549
+ if (normalized === "claude" || normalized === "claude code" || normalized === "cloud code") {
550
+ return "Claude";
551
+ }
552
+ if (normalized === "codex") {
553
+ return "Codex";
554
+ }
555
+ if (normalized === "gemini") {
556
+ return "Gemini";
557
+ }
558
+ return normalizeText(providerLabel) ?? "Agent";
559
+ }
560
+ function buildNotificationTitle(sessionLabel, providerLabel, actionLabel) {
561
+ const providerDisplayLabel = deriveNotificationProviderLabel(providerLabel);
562
+ const suffix = ` \xB7 ${providerDisplayLabel} \xB7 ${actionLabel}`;
563
+ const maxSessionLength = Math.max(12, TITLE_MAX_LENGTH - suffix.length);
564
+ return `${truncateText(sessionLabel, maxSessionLength)}${suffix}`;
565
+ }
566
+ function derivePathLabel(path) {
567
+ const normalized = normalizeText(path);
568
+ if (!normalized) {
569
+ return null;
570
+ }
571
+ const segments = normalized.split(/[\\/]+/).filter(Boolean);
572
+ return segments[segments.length - 1] ?? normalized;
573
+ }
574
+ function deriveHomeLabel(homeSlug) {
575
+ const normalized = normalizeText(homeSlug);
576
+ if (!normalized) {
577
+ return null;
578
+ }
579
+ return normalized.replace(/[_-]+/g, " ");
580
+ }
581
+ function deriveNotificationSessionLabel(metadata, providerLabel) {
582
+ const label = normalizeText(metadata?.name) ?? normalizeText(metadata?.summary?.text) ?? deriveHomeLabel(metadata?.happyOrg?.specialistHome?.homeSlug) ?? derivePathLabel(metadata?.path) ?? normalizeText(providerLabel) ?? "Session";
583
+ return truncateText(label, SESSION_LABEL_MAX_LENGTH);
584
+ }
585
+ function deriveNotificationSummary(candidates, fallback, sessionLabel) {
586
+ for (const candidate of candidates) {
587
+ const normalized = normalizeText(candidate);
588
+ if (!normalized) {
589
+ continue;
590
+ }
591
+ const truncated = truncateText(normalized, BODY_MAX_LENGTH);
592
+ if (truncated.toLowerCase() !== sessionLabel.toLowerCase()) {
593
+ return truncated;
594
+ }
595
+ }
596
+ return truncateText(fallback, BODY_MAX_LENGTH);
597
+ }
598
+ function cleanExtraData(extraData) {
599
+ return Object.fromEntries(
600
+ Object.entries(extraData).filter(([, value]) => {
601
+ if (value === null || value === void 0) {
602
+ return false;
603
+ }
604
+ if (typeof value === "string") {
605
+ return value.trim().length > 0;
606
+ }
607
+ return true;
608
+ })
609
+ );
610
+ }
611
+ function buildRouteData(opts) {
612
+ const taskContext = opts.metadata?.happyOrg?.taskContext ?? null;
613
+ const routeTaskId = opts.report?.taskId ?? taskContext?.taskId ?? null;
614
+ const routePositionId = opts.report?.positionId ?? taskContext?.positionId ?? null;
615
+ const routeSessionId = normalizeText(opts.sessionId);
616
+ const data = {
617
+ notificationKind: opts.notificationKind,
618
+ provider: toProviderKey(opts.providerLabel)
619
+ };
620
+ if (opts.routePreference === "session" && routeSessionId) {
621
+ data.sessionId = routeSessionId;
622
+ } else if (routeTaskId) {
623
+ data.taskId = routeTaskId;
624
+ } else if (routeSessionId) {
625
+ data.sessionId = routeSessionId;
626
+ } else if (routePositionId) {
627
+ data.positionId = routePositionId;
628
+ }
629
+ Object.assign(data, cleanExtraData({
630
+ contextTaskId: data.taskId ? null : routeTaskId,
631
+ contextPositionId: data.positionId ? null : routePositionId,
632
+ memberAgentId: opts.report?.memberAgentId ?? taskContext?.memberAgentId ?? null,
633
+ supervisorAgentId: opts.report?.supervisorAgentId ?? taskContext?.supervisorAgentId ?? null
634
+ }));
635
+ if (opts.extraData) {
636
+ Object.assign(data, cleanExtraData(opts.extraData));
637
+ }
638
+ return data;
639
+ }
640
+ function humanizeToolName(toolName) {
641
+ const normalized = normalizeText(toolName);
642
+ if (!normalized) {
643
+ return "continue";
644
+ }
645
+ const replacements = {
646
+ bash: "run a command",
647
+ execute: "run a command",
648
+ read: "read a file",
649
+ write: "write a file",
650
+ edit: "edit a file",
651
+ multiedit: "edit files",
652
+ patch: "apply a patch",
653
+ fetch: "fetch a page",
654
+ search: "search the web"
655
+ };
656
+ const replacement = replacements[normalized.toLowerCase()];
657
+ if (replacement) {
658
+ return replacement;
659
+ }
660
+ return normalized.replace(/[_-]+/g, " ");
661
+ }
662
+ function extractPermissionRequestPushContext(message) {
663
+ const payload = isRecord(message.payload) ? message.payload : null;
664
+ const toolName = normalizeText(payload?.toolName) ?? normalizeText(message.reason);
665
+ const payloadDescription = normalizeText(payload?.description);
666
+ const reasonDescription = normalizeText(message.reason);
667
+ let description = payloadDescription;
668
+ if (!description && reasonDescription && reasonDescription.toLowerCase() !== (toolName ?? "").toLowerCase()) {
669
+ description = reasonDescription;
670
+ }
671
+ if (description && toolName && description.toLowerCase() === toolName.toLowerCase()) {
672
+ description = null;
673
+ }
674
+ return {
675
+ requestId: message.id,
676
+ toolName,
677
+ description
678
+ };
679
+ }
680
+ function buildReadyPushNotification(opts) {
681
+ const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
682
+ const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
683
+ return {
684
+ title: buildNotificationTitle(sessionLabel, opts.providerLabel, "Ready"),
685
+ body: truncateText(`${providerDisplayLabel} is waiting for your next message`, BODY_MAX_LENGTH),
686
+ data: buildRouteData({
687
+ ...opts,
688
+ notificationKind: "ready",
689
+ routePreference: "session"
690
+ })
691
+ };
692
+ }
693
+ function buildPermissionPushNotification(opts) {
694
+ const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
695
+ const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
696
+ const fallback = `${providerDisplayLabel} needs your approval to ${humanizeToolName(opts.toolName)}`;
697
+ const body = deriveNotificationSummary([opts.description], fallback, sessionLabel);
698
+ return {
699
+ title: buildNotificationTitle(sessionLabel, opts.providerLabel, "Permission needed"),
700
+ body,
701
+ data: buildRouteData({
702
+ ...opts,
703
+ notificationKind: "permission_request",
704
+ routePreference: "session",
705
+ extraData: {
706
+ requestId: opts.requestId,
707
+ tool: opts.toolName ?? null,
708
+ ...opts.extraData
709
+ }
710
+ })
711
+ };
712
+ }
713
+ function buildTurnResultPushNotification(opts) {
714
+ const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
715
+ const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
716
+ const report = opts.report ?? null;
717
+ const explicitSummary = normalizeText(report?.summary) ?? normalizeText(opts.responseText);
718
+ if (!explicitSummary) {
719
+ return null;
720
+ }
721
+ const fallback = `${providerDisplayLabel} has a new result ready`;
722
+ const body = deriveNotificationSummary(
723
+ [
724
+ explicitSummary
725
+ ],
726
+ fallback,
727
+ sessionLabel
728
+ );
729
+ const action = report?.turnStatus === "task_complete" ? "Task complete" : "New result";
730
+ return {
731
+ title: buildNotificationTitle(sessionLabel, opts.providerLabel, action),
732
+ body,
733
+ data: buildRouteData({
734
+ ...opts,
735
+ report,
736
+ notificationKind: "turn_result",
737
+ routePreference: "session",
738
+ extraData: {
739
+ turnStatus: report?.turnStatus ?? "turn_update"
740
+ }
741
+ })
742
+ };
743
+ }
744
+
509
745
  const STRUCTURED_FIELD_PATTERN = /^\s*([a-z_]+)\s*=\s*(.*?)\s*$/;
510
746
  const KEY_VALUE_LINE_PATTERN = /^([A-Za-z0-9_]+)=(.*)$/;
511
747
  const HAPPY_ORG_READ_ACK = "yes";
@@ -2496,7 +2732,11 @@ exports.MessageBuffer = MessageBuffer;
2496
2732
  exports.MessageQueue2 = MessageQueue2;
2497
2733
  exports.MissingMachineIdError = MissingMachineIdError;
2498
2734
  exports.buildHappyOrgTurnPrompt = buildHappyOrgTurnPrompt;
2735
+ exports.buildPermissionPushNotification = buildPermissionPushNotification;
2736
+ exports.buildReadyPushNotification = buildReadyPushNotification;
2737
+ exports.buildTurnResultPushNotification = buildTurnResultPushNotification;
2499
2738
  exports.ensureManagedProviderMachine = ensureManagedProviderMachine;
2739
+ exports.extractPermissionRequestPushContext = extractPermissionRequestPushContext;
2500
2740
  exports.finalizeHappyOrgTurnWithBusinessAck = finalizeHappyOrgTurnWithBusinessAck;
2501
2741
  exports.forwardAgentMessageToProviderSession = forwardAgentMessageToProviderSession;
2502
2742
  exports.getPendingInteractionTimeoutMs = getPendingInteractionTimeoutMs;