happy-imou-cloud 2.1.1 → 2.1.2

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 (44) hide show
  1. package/bin/happy-cloud.mjs +21 -21
  2. package/compat/acp-sdk-schema/index.js +27 -27
  3. package/compat/acp-sdk-schema/types.gen.js +2 -2
  4. package/compat/acp-sdk-schema/zod.gen.js +1553 -1553
  5. package/compat/ink-build/components/Cursor.d.ts +83 -83
  6. package/compat/ink-build/components/Cursor.js +52 -52
  7. package/compat/ink-build/components/CursorContext.d.ts +11 -11
  8. package/compat/ink-build/components/CursorContext.js +7 -7
  9. package/compat/ink-build/components/ErrorBoundary.d.ts +18 -18
  10. package/compat/ink-build/components/ErrorBoundary.js +22 -22
  11. package/compat/ink-build/hooks/use-cursor.d.ts +12 -12
  12. package/compat/ink-build/hooks/use-cursor.js +28 -28
  13. package/dist/{BaseReasoningProcessor-Dn9FxfxU.mjs → BaseReasoningProcessor-BaOWkVcu.mjs} +3 -3
  14. package/dist/{BaseReasoningProcessor-CBMK-8Gi.cjs → BaseReasoningProcessor-CzvqwxuY.cjs} +3 -3
  15. package/dist/ProviderSelectionHandler-Q8pl7e-d.mjs +261 -0
  16. package/dist/ProviderSelectionHandler-wwbfeK_s.cjs +265 -0
  17. package/dist/{api-DBy5lPZw.mjs → api-Cxifhw5r.mjs} +3 -3
  18. package/dist/{api-DId_j3C2.cjs → api-DZimmN4C.cjs} +2 -2
  19. package/dist/{command-CeaBwYCW.mjs → command-B6LM3Nml.mjs} +3 -3
  20. package/dist/{command-DwfUpmId.cjs → command-RcCJI1jl.cjs} +3 -3
  21. package/dist/{index-CuuYSKiv.cjs → index-Cuvs0lFS.cjs} +168 -75
  22. package/dist/{index-66vjECEd.mjs → index-Des7I5WX.mjs} +165 -72
  23. package/dist/index.cjs +3 -3
  24. package/dist/index.mjs +3 -3
  25. package/dist/lib.cjs +1 -1
  26. package/dist/lib.d.cts +36 -36
  27. package/dist/lib.d.mts +36 -36
  28. package/dist/lib.mjs +1 -1
  29. package/dist/{persistence-BOWh1NER.mjs → persistence-6d4U4Sh8.mjs} +1 -1
  30. package/dist/{persistence-Dzr6sFwD.cjs → persistence-C8-MtdQK.cjs} +1 -1
  31. package/dist/{registerKillSessionHandler-D4_wpN18.mjs → registerKillSessionHandler-BFBkz_XT.mjs} +417 -5
  32. package/dist/{registerKillSessionHandler-Dg_iRBPm.cjs → registerKillSessionHandler-BapPCRmp.cjs} +419 -4
  33. package/dist/{runClaude-B74dHAnQ.mjs → runClaude-CPV5Uap2.mjs} +34 -5
  34. package/dist/{runClaude-oIFzkfuU.cjs → runClaude-DVnqKa1q.cjs} +37 -8
  35. package/dist/{runCodex-D_9CuL6M.cjs → runCodex-Bzsp8gFO.cjs} +29 -21
  36. package/dist/{runCodex-mLHjsgVj.mjs → runCodex-CwtLSTMJ.mjs} +26 -18
  37. package/dist/{runGemini-CcWGezMt.cjs → runGemini-6Dwyk_Km.cjs} +267 -82
  38. package/dist/{runGemini-BMiho2ab.mjs → runGemini-Bmoxehlh.mjs} +267 -82
  39. package/package.json +9 -9
  40. package/scripts/build.mjs +68 -68
  41. package/scripts/ensureAcpSdkCompat.mjs +170 -172
  42. package/scripts/release-smoke.mjs +38 -35
  43. package/dist/ProviderSelectionHandler-BuXk-8ji.cjs +0 -680
  44. package/dist/ProviderSelectionHandler-CMaQThYO.mjs +0 -673
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CuuYSKiv.cjs');
4
- var persistence = require('./persistence-Dzr6sFwD.cjs');
3
+ var index = require('./index-Cuvs0lFS.cjs');
4
+ var persistence = require('./persistence-C8-MtdQK.cjs');
5
5
  var os = require('node:os');
6
6
  var path = require('node:path');
7
- var api = require('./api-DId_j3C2.cjs');
7
+ var api = require('./api-DZimmN4C.cjs');
8
8
  var node_crypto = require('node:crypto');
9
9
  var crypto = require('crypto');
10
10
  require('axios');
@@ -302,7 +302,7 @@ function createAbortError() {
302
302
  error.name = "AbortError";
303
303
  return error;
304
304
  }
305
- async function waitForResponseCompleteWithAbort(backend, signal, timeoutMs = 12e4) {
305
+ async function waitForResponseCompleteWithAbort(backend, signal, timeoutMs = 10 * 6e4) {
306
306
  if (!backend.waitForResponseComplete) {
307
307
  return;
308
308
  }
@@ -356,6 +356,418 @@ async function syncControlledByUserState(sessionClient, controlledByUser) {
356
356
  });
357
357
  }
358
358
 
359
+ function normalizeOptionalText(value) {
360
+ if (typeof value !== "string") {
361
+ return null;
362
+ }
363
+ const trimmed = value.trim();
364
+ return trimmed.length > 0 ? trimmed : null;
365
+ }
366
+ function normalizeSummaryText(value) {
367
+ const normalized = normalizeOptionalText(value);
368
+ return normalized ? normalized.replace(/\s+/g, " ").slice(0, api.HAPPY_ORG_SUMMARY_MAX_LENGTH) : null;
369
+ }
370
+ function cloneHappyOrgMetadata(happyOrg) {
371
+ return {
372
+ taskContext: happyOrg?.taskContext ? { ...happyOrg.taskContext } : void 0,
373
+ runtime: happyOrg?.runtime ? { ...happyOrg.runtime } : void 0,
374
+ activeOwner: happyOrg?.activeOwner ? { ...happyOrg.activeOwner } : null,
375
+ repeat: happyOrg?.repeat ? {
376
+ threshold: happyOrg.repeat.threshold,
377
+ fingerprints: Object.fromEntries(
378
+ Object.entries(happyOrg.repeat.fingerprints ?? {}).map(([fingerprint, entry]) => [
379
+ fingerprint,
380
+ { ...entry }
381
+ ])
382
+ )
383
+ } : void 0,
384
+ lastTurnReport: happyOrg?.lastTurnReport ? { ...happyOrg.lastTurnReport } : void 0
385
+ };
386
+ }
387
+ function normalizeHappyOrgMetadata(metadata) {
388
+ const happyOrg = cloneHappyOrgMetadata(metadata?.happyOrg);
389
+ return {
390
+ ...happyOrg,
391
+ runtime: happyOrg.runtime ?? {
392
+ status: "active",
393
+ reason: null
394
+ },
395
+ repeat: happyOrg.repeat ?? {
396
+ threshold: api.HAPPY_ORG_REPEAT_THRESHOLD,
397
+ fingerprints: {}
398
+ }
399
+ };
400
+ }
401
+ function withHappyOrgMetadata(metadata, happyOrg) {
402
+ return {
403
+ ...metadata,
404
+ happyOrg
405
+ };
406
+ }
407
+ function resetHappyOrgRuntimeForTask(taskContext) {
408
+ return {
409
+ taskContext,
410
+ runtime: {
411
+ status: "active",
412
+ reason: null
413
+ },
414
+ activeOwner: null,
415
+ repeat: {
416
+ threshold: api.HAPPY_ORG_REPEAT_THRESHOLD,
417
+ fingerprints: {}
418
+ }
419
+ };
420
+ }
421
+ function buildTerminatedStatusMessage(taskId) {
422
+ return `Task ${taskId} is terminated. Reopen it with new context, a new decision, or a new resource before continuing.`;
423
+ }
424
+ function buildMemberBusyStatusMessage(memberAgentId, activeTaskId, nextTaskId) {
425
+ return `Member ${memberAgentId} is already busy with active task ${activeTaskId}. Reject task ${nextTaskId} without continuing token usage.`;
426
+ }
427
+ function buildOwnerConflictStatusMessage(taskId, ownerAgentId) {
428
+ return `Task ${taskId} is already active under owner ${ownerAgentId}. This turn must exit without continuing token usage.`;
429
+ }
430
+ function inferDraftTurnStatus(draft) {
431
+ if (draft?.turnStatus === "turn_update" || draft?.turnStatus === "task_complete") {
432
+ return draft.turnStatus;
433
+ }
434
+ return null;
435
+ }
436
+ function inferInterventionType(draft) {
437
+ if (draft?.interventionType === "none" || draft?.interventionType === "review_needed" || draft?.interventionType === "blocker" || draft?.interventionType === "decision_needed") {
438
+ return draft.interventionType;
439
+ }
440
+ if (normalizeOptionalText(draft?.decisionNeeded)) {
441
+ return "decision_needed";
442
+ }
443
+ if (normalizeOptionalText(draft?.blockerCode)) {
444
+ return "blocker";
445
+ }
446
+ return "none";
447
+ }
448
+ function buildFallbackSummary(text, turnStatus) {
449
+ const trimmed = text.trim();
450
+ if (trimmed) {
451
+ return trimmed.replace(/\s+/g, " ").slice(0, api.HAPPY_ORG_SUMMARY_MAX_LENGTH);
452
+ }
453
+ return turnStatus === "turn_aborted" ? "Turn aborted before completion." : "Turn completed without a textual summary.";
454
+ }
455
+ function normalizeTurnReportDraft(draft) {
456
+ return {
457
+ turnStatus: inferDraftTurnStatus(draft),
458
+ summary: normalizeSummaryText(draft?.summary),
459
+ interventionType: inferInterventionType(draft),
460
+ blockerCode: normalizeOptionalText(draft?.blockerCode),
461
+ decisionNeeded: normalizeOptionalText(draft?.decisionNeeded),
462
+ targetArtifact: normalizeOptionalText(draft?.targetArtifact)
463
+ };
464
+ }
465
+ function stripCodeFence(text) {
466
+ return text.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
467
+ }
468
+ function extractTaggedTurnReport(text) {
469
+ const matcher = new RegExp(
470
+ `<${api.HAPPY_ORG_TURN_REPORT_TAG}>\\s*([\\s\\S]*?)\\s*</${api.HAPPY_ORG_TURN_REPORT_TAG}>`,
471
+ "gi"
472
+ );
473
+ let lastMatch = null;
474
+ for (let match = matcher.exec(text); match; match = matcher.exec(text)) {
475
+ lastMatch = match;
476
+ }
477
+ if (!lastMatch) {
478
+ return {
479
+ cleanedText: text.trim(),
480
+ draft: null
481
+ };
482
+ }
483
+ const rawBlock = stripCodeFence(lastMatch[1] ?? "");
484
+ let draft = null;
485
+ try {
486
+ const parsed = JSON.parse(rawBlock);
487
+ draft = {
488
+ turnStatus: normalizeOptionalText(parsed.turnStatus),
489
+ summary: normalizeSummaryText(parsed.summary),
490
+ interventionType: normalizeOptionalText(parsed.interventionType),
491
+ blockerCode: normalizeOptionalText(parsed.blockerCode),
492
+ decisionNeeded: normalizeOptionalText(parsed.decisionNeeded),
493
+ targetArtifact: normalizeOptionalText(parsed.targetArtifact)
494
+ };
495
+ } catch {
496
+ draft = null;
497
+ }
498
+ const cleanedText = `${text.slice(0, lastMatch.index)}${text.slice(lastMatch.index + lastMatch[0].length)}`.replace(/\n{3,}/g, "\n\n").trim();
499
+ return {
500
+ cleanedText,
501
+ draft
502
+ };
503
+ }
504
+ function buildRepeatFingerprint(context, blockerCode, targetArtifact) {
505
+ if (!blockerCode) {
506
+ return null;
507
+ }
508
+ return [
509
+ context.taskId,
510
+ context.memberAgentId,
511
+ blockerCode,
512
+ targetArtifact ?? ""
513
+ ].join("::");
514
+ }
515
+ function resolveReportedTurnStatus(transportTurnStatus, draft) {
516
+ if (transportTurnStatus === "turn_aborted") {
517
+ return "turn_aborted";
518
+ }
519
+ return draft.turnStatus === "task_complete" ? "task_complete" : "turn_update";
520
+ }
521
+ function buildRuntimeStateAfterTurn(report) {
522
+ if (report.turnStatus === "task_complete") {
523
+ return {
524
+ status: "waiting_close",
525
+ reason: "awaiting_ceo_close"
526
+ };
527
+ }
528
+ switch (report.interventionType) {
529
+ case "decision_needed":
530
+ return {
531
+ status: "waiting_decision",
532
+ reason: "awaiting_user_decision"
533
+ };
534
+ case "review_needed":
535
+ return {
536
+ status: "waiting_review",
537
+ reason: "awaiting_ceo_review"
538
+ };
539
+ case "blocker":
540
+ return {
541
+ status: "waiting_review",
542
+ reason: "awaiting_ceo_context"
543
+ };
544
+ default:
545
+ return {
546
+ status: "active",
547
+ reason: null
548
+ };
549
+ }
550
+ }
551
+ function buildHappyOrgTurnPrompt(prompt, turn) {
552
+ const reopenLines = turn.reopenContext ? [
553
+ "",
554
+ "This task was explicitly reopened for this turn with the following new inputs:",
555
+ turn.reopenContext.newContext ? `- newContext: ${turn.reopenContext.newContext}` : null,
556
+ turn.reopenContext.newDecision ? `- newDecision: ${turn.reopenContext.newDecision}` : null,
557
+ turn.reopenContext.newResource ? `- newResource: ${turn.reopenContext.newResource}` : null
558
+ ].filter(Boolean) : [];
559
+ const header = [
560
+ "[HAPPY_ORG_TASK_CONTEXT]",
561
+ `taskId=${turn.context.taskId}`,
562
+ `organizationId=${turn.context.organizationId}`,
563
+ `memberAgentId=${turn.context.memberAgentId}`,
564
+ `supervisorAgentId=${turn.context.supervisorAgentId}`,
565
+ "Stay on this exact task for the whole turn.",
566
+ "End your response with exactly one raw JSON block inside these tags and do not wrap it in a markdown code fence:",
567
+ `<${api.HAPPY_ORG_TURN_REPORT_TAG}>{"turnStatus":"turn_update","summary":"short task-board summary","interventionType":"none","blockerCode":null,"decisionNeeded":null,"targetArtifact":null}</${api.HAPPY_ORG_TURN_REPORT_TAG}>`,
568
+ "Allowed turnStatus values in the JSON block: turn_update, task_complete.",
569
+ "Allowed interventionType values: none, review_needed, blocker, decision_needed.",
570
+ "Use turnStatus=task_complete only when you believe the assigned task is finished and ready for CEO acceptance.",
571
+ "If turnStatus=task_complete, the task will wait for CEO close; do not treat it as automatically closed.",
572
+ "If turnStatus=task_complete, interventionType must be review_needed.",
573
+ `summary must fit on a one-line CEO card or task-board card: short, actionable, no long process logs, max ${api.HAPPY_ORG_SUMMARY_MAX_LENGTH} characters.`,
574
+ "Use blocker only for problems the organization may still solve internally.",
575
+ "Use decision_needed only when a CEO or user decision is required.",
576
+ "Use review_needed when supervisor review is needed but the work is not blocked.",
577
+ ...reopenLines,
578
+ "[/HAPPY_ORG_TASK_CONTEXT]",
579
+ "",
580
+ prompt
581
+ ];
582
+ return header.join("\n");
583
+ }
584
+ function resolveHappyOrgQueuedTurn(opts) {
585
+ const metadata = opts.metadata ?? null;
586
+ if (!metadata) {
587
+ return {
588
+ nextMetadata: null,
589
+ queuedTurn: null,
590
+ blocked: false
591
+ };
592
+ }
593
+ const currentHappyOrg = normalizeHappyOrgMetadata(metadata);
594
+ let nextHappyOrg = cloneHappyOrgMetadata(currentHappyOrg);
595
+ const messageHappyOrg = opts.message.meta?.happyOrg;
596
+ const now = opts.now?.() ?? Date.now();
597
+ const createRunId = opts.createRunId ?? ((taskContext2, currentNow) => `${taskContext2.taskId}:${taskContext2.memberAgentId}:${currentNow}`);
598
+ if (messageHappyOrg?.taskContext) {
599
+ const currentTaskId = currentHappyOrg.taskContext?.taskId ?? null;
600
+ if (currentTaskId !== messageHappyOrg.taskContext.taskId) {
601
+ if (currentHappyOrg.taskContext && currentHappyOrg.runtime?.status === "active") {
602
+ return {
603
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
604
+ queuedTurn: null,
605
+ blocked: true,
606
+ statusMessage: buildMemberBusyStatusMessage(
607
+ currentHappyOrg.taskContext.memberAgentId,
608
+ currentHappyOrg.taskContext.taskId,
609
+ messageHappyOrg.taskContext.taskId
610
+ )
611
+ };
612
+ }
613
+ nextHappyOrg = resetHappyOrgRuntimeForTask(messageHappyOrg.taskContext);
614
+ } else {
615
+ nextHappyOrg.taskContext = { ...messageHappyOrg.taskContext };
616
+ }
617
+ }
618
+ const taskContext = nextHappyOrg.taskContext ?? null;
619
+ if (!taskContext) {
620
+ return {
621
+ nextMetadata: metadata,
622
+ queuedTurn: null,
623
+ blocked: false
624
+ };
625
+ }
626
+ const control = messageHappyOrg?.control;
627
+ if (control?.action === "terminate") {
628
+ nextHappyOrg.runtime = {
629
+ status: "terminated",
630
+ reason: normalizeOptionalText(control.reason) ?? "terminated_by_supervisor",
631
+ terminatedAt: now
632
+ };
633
+ nextHappyOrg.activeOwner = null;
634
+ return {
635
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
636
+ queuedTurn: null,
637
+ blocked: true,
638
+ statusMessage: buildTerminatedStatusMessage(taskContext.taskId)
639
+ };
640
+ }
641
+ const hasReopenInputs = Boolean(
642
+ normalizeOptionalText(control?.newContext) || normalizeOptionalText(control?.newDecision) || normalizeOptionalText(control?.newResource)
643
+ );
644
+ if (nextHappyOrg.runtime?.status === "terminated") {
645
+ if (control?.action !== "reopen") {
646
+ return {
647
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
648
+ queuedTurn: null,
649
+ blocked: true,
650
+ statusMessage: buildTerminatedStatusMessage(taskContext.taskId)
651
+ };
652
+ }
653
+ if (!hasReopenInputs) {
654
+ return {
655
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
656
+ queuedTurn: null,
657
+ blocked: true,
658
+ statusMessage: `Task ${taskContext.taskId} can only reopen with new context, a new decision, or a new resource.`
659
+ };
660
+ }
661
+ }
662
+ const reopenContext = control?.action === "reopen" && hasReopenInputs ? {
663
+ newContext: normalizeOptionalText(control.newContext),
664
+ newDecision: normalizeOptionalText(control.newDecision),
665
+ newResource: normalizeOptionalText(control.newResource)
666
+ } : void 0;
667
+ if (reopenContext) {
668
+ nextHappyOrg.runtime = {
669
+ status: "active",
670
+ reason: null,
671
+ reopenedAt: now
672
+ };
673
+ } else if (!nextHappyOrg.runtime || nextHappyOrg.runtime.status !== "active") {
674
+ nextHappyOrg.runtime = {
675
+ status: "active",
676
+ reason: null
677
+ };
678
+ }
679
+ if (!nextHappyOrg.activeOwner) {
680
+ nextHappyOrg.activeOwner = {
681
+ ownerAgentId: taskContext.memberAgentId,
682
+ ownerRunId: createRunId(taskContext, now),
683
+ claimedAt: now
684
+ };
685
+ } else if (nextHappyOrg.activeOwner.ownerAgentId !== taskContext.memberAgentId) {
686
+ return {
687
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
688
+ queuedTurn: null,
689
+ blocked: true,
690
+ statusMessage: buildOwnerConflictStatusMessage(
691
+ taskContext.taskId,
692
+ nextHappyOrg.activeOwner.ownerAgentId
693
+ )
694
+ };
695
+ }
696
+ return {
697
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
698
+ queuedTurn: {
699
+ context: taskContext,
700
+ ...reopenContext ? { reopenContext } : {}
701
+ },
702
+ blocked: false
703
+ };
704
+ }
705
+ function finalizeHappyOrgTurn(opts) {
706
+ const metadata = opts.metadata ?? null;
707
+ const queuedTurn = opts.queuedTurn ?? null;
708
+ const { cleanedText, draft } = extractTaggedTurnReport(opts.responseText);
709
+ if (!metadata || !queuedTurn) {
710
+ return {
711
+ cleanedText,
712
+ report: null,
713
+ nextMetadata: metadata
714
+ };
715
+ }
716
+ const now = opts.now?.() ?? Date.now();
717
+ const normalizedDraft = normalizeTurnReportDraft(draft);
718
+ const reportTurnStatus = resolveReportedTurnStatus(opts.turnStatus, normalizedDraft);
719
+ const report = {
720
+ ...queuedTurn.context,
721
+ turnStatus: reportTurnStatus,
722
+ interventionType: reportTurnStatus === "task_complete" ? "review_needed" : normalizedDraft.interventionType ?? "none",
723
+ summary: normalizedDraft.summary ?? buildFallbackSummary(cleanedText, reportTurnStatus),
724
+ blockerCode: normalizedDraft.blockerCode ?? null,
725
+ decisionNeeded: normalizedDraft.decisionNeeded ?? null,
726
+ targetArtifact: normalizedDraft.targetArtifact ?? null,
727
+ repeatFingerprint: buildRepeatFingerprint(
728
+ queuedTurn.context,
729
+ normalizedDraft.blockerCode ?? null,
730
+ normalizedDraft.targetArtifact ?? null
731
+ )
732
+ };
733
+ const nextHappyOrg = normalizeHappyOrgMetadata(metadata);
734
+ nextHappyOrg.taskContext = { ...queuedTurn.context };
735
+ nextHappyOrg.lastTurnReport = report;
736
+ nextHappyOrg.activeOwner = null;
737
+ nextHappyOrg.repeat = nextHappyOrg.repeat ?? {
738
+ threshold: api.HAPPY_ORG_REPEAT_THRESHOLD,
739
+ fingerprints: {}
740
+ };
741
+ let terminateMessage;
742
+ if (report.repeatFingerprint) {
743
+ const currentEntry = nextHappyOrg.repeat.fingerprints[report.repeatFingerprint] ?? {
744
+ count: 0};
745
+ const nextCount = currentEntry.count + 1;
746
+ nextHappyOrg.repeat.fingerprints[report.repeatFingerprint] = {
747
+ count: nextCount,
748
+ lastSeenAt: now
749
+ };
750
+ if (nextCount >= nextHappyOrg.repeat.threshold) {
751
+ nextHappyOrg.runtime = {
752
+ status: "terminated",
753
+ reason: `repeat_fingerprint:${report.repeatFingerprint}`,
754
+ terminatedAt: now
755
+ };
756
+ terminateMessage = `Task ${queuedTurn.context.taskId} hit repeat threshold for ${report.repeatFingerprint} and is now terminated until reopen.`;
757
+ } else if (!nextHappyOrg.runtime || nextHappyOrg.runtime.status !== "terminated") {
758
+ nextHappyOrg.runtime = buildRuntimeStateAfterTurn(report);
759
+ }
760
+ } else if (!nextHappyOrg.runtime || nextHappyOrg.runtime.status !== "terminated") {
761
+ nextHappyOrg.runtime = buildRuntimeStateAfterTurn(report);
762
+ }
763
+ return {
764
+ cleanedText,
765
+ report,
766
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
767
+ terminateMessage
768
+ };
769
+ }
770
+
359
771
  const DEFAULT_MAX_MESSAGES = 200;
360
772
  const DEFAULT_MAX_CHARACTERS = 1e5;
361
773
  const DEFAULT_MAX_MESSAGE_CHARACTERS = 8e3;
@@ -1188,14 +1600,17 @@ exports.INTERACTION_TIMED_OUT_ERROR = INTERACTION_TIMED_OUT_ERROR;
1188
1600
  exports.MessageBuffer = MessageBuffer;
1189
1601
  exports.MessageQueue2 = MessageQueue2;
1190
1602
  exports.MissingMachineIdError = MissingMachineIdError;
1603
+ exports.buildHappyOrgTurnPrompt = buildHappyOrgTurnPrompt;
1191
1604
  exports.closeProviderSession = closeProviderSession;
1192
1605
  exports.createSessionMetadata = createSessionMetadata;
1193
1606
  exports.ensureManagedProviderMachine = ensureManagedProviderMachine;
1607
+ exports.finalizeHappyOrgTurn = finalizeHappyOrgTurn;
1194
1608
  exports.forwardAgentMessageToProviderSession = forwardAgentMessageToProviderSession;
1195
1609
  exports.getPendingInteractionTimeoutMs = getPendingInteractionTimeoutMs;
1196
1610
  exports.hashObject = hashObject;
1197
1611
  exports.inferToolResultError = inferToolResultError;
1198
1612
  exports.launchRuntimeHandleWithFactoryResult = launchRuntimeHandleWithFactoryResult;
1199
1613
  exports.registerKillSessionHandler = registerKillSessionHandler;
1614
+ exports.resolveHappyOrgQueuedTurn = resolveHappyOrgQueuedTurn;
1200
1615
  exports.syncControlledByUserState = syncControlledByUserState;
1201
1616
  exports.waitForResponseCompleteWithAbort = waitForResponseCompleteWithAbort;
@@ -1,8 +1,8 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { l as logger, g as backoff, h as delay, j as AsyncLock, c as configuration, s as startOfflineReconnection, f as connectionState, A as ApiClient, i as isAuthenticationRequiredError } from './api-DBy5lPZw.mjs';
2
+ import { l as logger, g as backoff, h as delay, j as AsyncLock, c as configuration, s as startOfflineReconnection, b as connectionState, A as ApiClient, i as isAuthenticationRequiredError } from './api-Cxifhw5r.mjs';
3
3
  import 'cross-spawn';
4
4
  import '@agentclientprotocol/sdk';
5
- import { j as getProjectPath, F as Future, k as claudeLocal, E as ExitCodeError, l as trimIdent, m as createClaudeBackend, f as formatDisplayMessage, t as truncateDisplayMessage, n as claudeCheckSession, e as projectPath, o as mapToClaudeMode, P as PushableAsyncIterable, q as query, A as AbortError, b as stopCaffeinate, p as publishSessionRegistration, u as getEnvironmentInfo, w as startCaffeinate } from './index-66vjECEd.mjs';
5
+ import { j as getProjectPath, F as Future, k as claudeLocal, E as ExitCodeError, l as trimIdent, m as createClaudeBackend, f as formatDisplayMessage, t as truncateDisplayMessage, n as claudeCheckSession, e as projectPath, o as mapToClaudeMode, P as PushableAsyncIterable, q as query, A as AbortError, b as stopCaffeinate, p as publishSessionRegistration, u as getEnvironmentInfo, w as startCaffeinate } from './index-Des7I5WX.mjs';
6
6
  import 'ps-list';
7
7
  import 'fs';
8
8
  import 'path';
@@ -13,7 +13,7 @@ import { dirname, basename, join, resolve } from 'node:path';
13
13
  import { homedir } from 'node:os';
14
14
  import { execSync } from 'node:child_process';
15
15
  import 'node:readline';
16
- import './persistence-BOWh1NER.mjs';
16
+ import './persistence-6d4U4Sh8.mjs';
17
17
  import { readFile } from 'node:fs/promises';
18
18
  import { stat, watch, access } from 'fs/promises';
19
19
  import 'crypto';
@@ -24,9 +24,9 @@ import 'tweetnacl';
24
24
  import 'open';
25
25
  import React, { useState, useRef, useEffect, useCallback } from 'react';
26
26
  import { useStdout, useInput, Box, Text, render } from 'ink';
27
- import { c as createKeepAliveController, P as ProviderSelectionHandler, b as buildHappyOrgTurnPrompt, f as finalizeHappyOrgTurn, r as runModeLoop, a as resolveHappyOrgQueuedTurn } from './ProviderSelectionHandler-CMaQThYO.mjs';
27
+ import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-Q8pl7e-d.mjs';
28
28
  import { R as RawJSONLinesSchema } from './types-CiliQpqS.mjs';
29
- import { B as BasePermissionHandler, d as MessageBuffer, C as ConversationHistory$1, w as waitForResponseCompleteWithAbort, l as launchRuntimeHandleWithFactoryResult, j as forwardAgentMessageToProviderSession, s as syncControlledByUserState, e as ensureManagedProviderMachine, M as MissingMachineIdError, c as createSessionMetadata, b as MessageQueue2, h as hashObject, r as registerKillSessionHandler, f as closeProviderSession } from './registerKillSessionHandler-D4_wpN18.mjs';
29
+ import { B as BasePermissionHandler, f as MessageBuffer, C as ConversationHistory$1, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, l as launchRuntimeHandleWithFactoryResult, n as forwardAgentMessageToProviderSession, s as syncControlledByUserState, r as resolveHappyOrgQueuedTurn, e as ensureManagedProviderMachine, M as MissingMachineIdError, c as createSessionMetadata, b as MessageQueue2, h as hashObject, d as registerKillSessionHandler, k as closeProviderSession } from './registerKillSessionHandler-BFBkz_XT.mjs';
30
30
  import 'socket.io-client';
31
31
  import 'expo-server-sdk';
32
32
  import { isDeepStrictEqual } from 'node:util';
@@ -993,6 +993,7 @@ async function claudeAcpRemoteLauncher(session) {
993
993
  let inkInstance = null;
994
994
  let shouldExit = false;
995
995
  let abortController = new AbortController();
996
+ let turnInFlight = false;
996
997
  let runtimeHandle = null;
997
998
  let unsubscribeRuntimeMessages = null;
998
999
  let currentModeHash = null;
@@ -1003,6 +1004,7 @@ async function claudeAcpRemoteLauncher(session) {
1003
1004
  let currentAssistantMessageId = null;
1004
1005
  let currentThinkingMessageId = null;
1005
1006
  let shouldInjectHistoryOnNextSession = false;
1007
+ let unexpectedRuntimeStopRecovery = null;
1006
1008
  let readyAlreadySent = false;
1007
1009
  const permissionHandler = new ClaudeAcpPermissionHandler(session.client);
1008
1010
  const selectionHandler = new ProviderSelectionHandler(session.client, "Claude");
@@ -1111,6 +1113,28 @@ async function claudeAcpRemoteLauncher(session) {
1111
1113
  }
1112
1114
  emitStatusMessage(reason);
1113
1115
  };
1116
+ const recoverUnexpectedRuntimeStop = async (detail) => {
1117
+ if (shouldExit || session.queue.isClosed() || unexpectedRuntimeStopRecovery) {
1118
+ return;
1119
+ }
1120
+ const errorMessage = normalizeClaudeBackendError(detail);
1121
+ unexpectedRuntimeStopRecovery = (async () => {
1122
+ queueHistoryInjectionForRestart(
1123
+ `Claude runtime stopped unexpectedly (${errorMessage}). Starting a new Claude ACP session on the next message...`
1124
+ );
1125
+ await disposeRuntimeHandle();
1126
+ session.clearSessionId();
1127
+ currentModeHash = null;
1128
+ permissionHandler.reset();
1129
+ selectionHandler.reset();
1130
+ resetTurnState();
1131
+ })();
1132
+ try {
1133
+ await unexpectedRuntimeStopRecovery;
1134
+ } finally {
1135
+ unexpectedRuntimeStopRecovery = null;
1136
+ }
1137
+ };
1114
1138
  const setupRuntimeMessageHandler = (activeRuntimeHandle) => {
1115
1139
  const forwardAgentMessage = (agentMessage) => {
1116
1140
  forwardAgentMessageToProviderSession(agentMessage, {
@@ -1159,6 +1183,9 @@ async function claudeAcpRemoteLauncher(session) {
1159
1183
  }
1160
1184
  if (msg.status === "idle" || msg.status === "stopped") {
1161
1185
  session.onThinkingChange(false);
1186
+ if (msg.status === "stopped" && !turnInFlight) {
1187
+ void recoverUnexpectedRuntimeStop(msg.detail);
1188
+ }
1162
1189
  return;
1163
1190
  }
1164
1191
  if (msg.status === "error") {
@@ -1376,6 +1403,7 @@ ${systemPrompt}` : systemPrompt,
1376
1403
  let shouldClearHistoryAfterTurn = false;
1377
1404
  let turnStatus = "task_complete";
1378
1405
  try {
1406
+ turnInFlight = true;
1379
1407
  const activeRuntimeHandle = runtimeHandle ?? await createRuntimeHandle(message.mode);
1380
1408
  let promptToSend = message.message;
1381
1409
  if (shouldInjectHistoryOnNextSession && conversationHistory.hasHistory()) {
@@ -1418,6 +1446,7 @@ ${systemPrompt}` : systemPrompt,
1418
1446
  currentModeHash = null;
1419
1447
  }
1420
1448
  } finally {
1449
+ turnInFlight = false;
1421
1450
  const finalizedTurn = finalizeHappyOrgTurn({
1422
1451
  metadata: session.client.getMetadataSnapshot?.() ?? null,
1423
1452
  queuedTurn: message.mode.happyOrg,
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
- var api = require('./api-DId_j3C2.cjs');
4
+ var api = require('./api-DZimmN4C.cjs');
5
5
  require('cross-spawn');
6
6
  require('@agentclientprotocol/sdk');
7
- var index = require('./index-CuuYSKiv.cjs');
7
+ var index = require('./index-Cuvs0lFS.cjs');
8
8
  require('ps-list');
9
9
  require('fs');
10
10
  require('path');
@@ -15,7 +15,7 @@ var path = require('node:path');
15
15
  var os = require('node:os');
16
16
  var node_child_process = require('node:child_process');
17
17
  require('node:readline');
18
- require('./persistence-Dzr6sFwD.cjs');
18
+ require('./persistence-C8-MtdQK.cjs');
19
19
  var promises = require('node:fs/promises');
20
20
  var fs = require('fs/promises');
21
21
  require('crypto');
@@ -26,9 +26,9 @@ require('tweetnacl');
26
26
  require('open');
27
27
  var React = require('react');
28
28
  var ink = require('ink');
29
- var ProviderSelectionHandler = require('./ProviderSelectionHandler-BuXk-8ji.cjs');
29
+ var ProviderSelectionHandler = require('./ProviderSelectionHandler-wwbfeK_s.cjs');
30
30
  var types = require('./types-DVk3crez.cjs');
31
- var registerKillSessionHandler = require('./registerKillSessionHandler-Dg_iRBPm.cjs');
31
+ var registerKillSessionHandler = require('./registerKillSessionHandler-BapPCRmp.cjs');
32
32
  require('socket.io-client');
33
33
  require('expo-server-sdk');
34
34
  var node_util = require('node:util');
@@ -995,6 +995,7 @@ async function claudeAcpRemoteLauncher(session) {
995
995
  let inkInstance = null;
996
996
  let shouldExit = false;
997
997
  let abortController = new AbortController();
998
+ let turnInFlight = false;
998
999
  let runtimeHandle = null;
999
1000
  let unsubscribeRuntimeMessages = null;
1000
1001
  let currentModeHash = null;
@@ -1005,6 +1006,7 @@ async function claudeAcpRemoteLauncher(session) {
1005
1006
  let currentAssistantMessageId = null;
1006
1007
  let currentThinkingMessageId = null;
1007
1008
  let shouldInjectHistoryOnNextSession = false;
1009
+ let unexpectedRuntimeStopRecovery = null;
1008
1010
  let readyAlreadySent = false;
1009
1011
  const permissionHandler = new ClaudeAcpPermissionHandler(session.client);
1010
1012
  const selectionHandler = new ProviderSelectionHandler.ProviderSelectionHandler(session.client, "Claude");
@@ -1113,6 +1115,28 @@ async function claudeAcpRemoteLauncher(session) {
1113
1115
  }
1114
1116
  emitStatusMessage(reason);
1115
1117
  };
1118
+ const recoverUnexpectedRuntimeStop = async (detail) => {
1119
+ if (shouldExit || session.queue.isClosed() || unexpectedRuntimeStopRecovery) {
1120
+ return;
1121
+ }
1122
+ const errorMessage = normalizeClaudeBackendError(detail);
1123
+ unexpectedRuntimeStopRecovery = (async () => {
1124
+ queueHistoryInjectionForRestart(
1125
+ `Claude runtime stopped unexpectedly (${errorMessage}). Starting a new Claude ACP session on the next message...`
1126
+ );
1127
+ await disposeRuntimeHandle();
1128
+ session.clearSessionId();
1129
+ currentModeHash = null;
1130
+ permissionHandler.reset();
1131
+ selectionHandler.reset();
1132
+ resetTurnState();
1133
+ })();
1134
+ try {
1135
+ await unexpectedRuntimeStopRecovery;
1136
+ } finally {
1137
+ unexpectedRuntimeStopRecovery = null;
1138
+ }
1139
+ };
1116
1140
  const setupRuntimeMessageHandler = (activeRuntimeHandle) => {
1117
1141
  const forwardAgentMessage = (agentMessage) => {
1118
1142
  registerKillSessionHandler.forwardAgentMessageToProviderSession(agentMessage, {
@@ -1161,6 +1185,9 @@ async function claudeAcpRemoteLauncher(session) {
1161
1185
  }
1162
1186
  if (msg.status === "idle" || msg.status === "stopped") {
1163
1187
  session.onThinkingChange(false);
1188
+ if (msg.status === "stopped" && !turnInFlight) {
1189
+ void recoverUnexpectedRuntimeStop(msg.detail);
1190
+ }
1164
1191
  return;
1165
1192
  }
1166
1193
  if (msg.status === "error") {
@@ -1378,6 +1405,7 @@ ${systemPrompt}` : systemPrompt,
1378
1405
  let shouldClearHistoryAfterTurn = false;
1379
1406
  let turnStatus = "task_complete";
1380
1407
  try {
1408
+ turnInFlight = true;
1381
1409
  const activeRuntimeHandle = runtimeHandle ?? await createRuntimeHandle(message.mode);
1382
1410
  let promptToSend = message.message;
1383
1411
  if (shouldInjectHistoryOnNextSession && conversationHistory.hasHistory()) {
@@ -1388,7 +1416,7 @@ ${systemPrompt}` : systemPrompt,
1388
1416
  api.logger.debug(`[ClaudeACP] Injected conversation history context (${historyContext.length} chars)`);
1389
1417
  }
1390
1418
  if (message.mode.happyOrg) {
1391
- promptToSend = ProviderSelectionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1419
+ promptToSend = registerKillSessionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1392
1420
  }
1393
1421
  if (specialCommand.type === "compact") {
1394
1422
  emitStatusMessage("Compaction started");
@@ -1420,7 +1448,8 @@ ${systemPrompt}` : systemPrompt,
1420
1448
  currentModeHash = null;
1421
1449
  }
1422
1450
  } finally {
1423
- const finalizedTurn = ProviderSelectionHandler.finalizeHappyOrgTurn({
1451
+ turnInFlight = false;
1452
+ const finalizedTurn = registerKillSessionHandler.finalizeHappyOrgTurn({
1424
1453
  metadata: session.client.getMetadataSnapshot?.() ?? null,
1425
1454
  queuedTurn: message.mode.happyOrg,
1426
1455
  responseText: accumulatedResponse,
@@ -3161,7 +3190,7 @@ function resolveClaudeQueuedMessage(message, currentState) {
3161
3190
  function bindClaudeUserMessageQueue(opts) {
3162
3191
  let currentState = { ...opts.initialState };
3163
3192
  opts.session.onUserMessage((message) => {
3164
- const happyOrgResult = opts.happyOrg ? ProviderSelectionHandler.resolveHappyOrgQueuedTurn({
3193
+ const happyOrgResult = opts.happyOrg ? registerKillSessionHandler.resolveHappyOrgQueuedTurn({
3165
3194
  metadata: opts.happyOrg.getMetadata(),
3166
3195
  message
3167
3196
  }) : {