happy-imou-cloud 2.0.22 → 2.1.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.
Files changed (35) hide show
  1. package/bin/happy-cloud.mjs +1 -1
  2. package/dist/{BaseReasoningProcessor-CJVv1aNR.cjs → BaseReasoningProcessor-C9mH8EVn.cjs} +3 -3
  3. package/dist/{BaseReasoningProcessor-mIqqngd3.mjs → BaseReasoningProcessor-DQkzwRuf.mjs} +3 -3
  4. package/dist/ProviderSelectionHandler-5Dedbm8j.cjs +265 -0
  5. package/dist/ProviderSelectionHandler-BlrrLPlo.mjs +261 -0
  6. package/dist/{api-DP-RQUao.cjs → api-Bd-MnOS4.cjs} +24 -2
  7. package/dist/{api-DrijKeDb.mjs → api-w_CUxb9Q.mjs} +25 -3
  8. package/dist/{command-BZphfJrt.cjs → command-DoDmHNxR.cjs} +3 -3
  9. package/dist/{command--vV6BSsL.mjs → command-mTWwCqTY.mjs} +3 -3
  10. package/dist/{index-CqCEZDFi.cjs → index-BQmJ4NAa.cjs} +199 -79
  11. package/dist/{index-BIki80pQ.mjs → index-GuXV-pxB.mjs} +196 -76
  12. package/dist/index.cjs +3 -3
  13. package/dist/index.mjs +3 -3
  14. package/dist/lib.cjs +1 -1
  15. package/dist/lib.d.cts +95 -92
  16. package/dist/lib.d.mts +95 -92
  17. package/dist/lib.mjs +1 -1
  18. package/dist/{persistence-yVTbf_Ng.cjs → persistence-BL06LLVz.cjs} +1 -1
  19. package/dist/{persistence-C3NBdZdz.mjs → persistence-MSy70is3.mjs} +1 -1
  20. package/dist/{registerKillSessionHandler-CHEj7UjN.mjs → registerKillSessionHandler-CjWfUfc3.mjs} +428 -13
  21. package/dist/{registerKillSessionHandler-QmBN446A.cjs → registerKillSessionHandler-D9kwxy6B.cjs} +430 -12
  22. package/dist/{runClaude-BuI6OOEv.cjs → runClaude-D2ZEXue8.cjs} +11 -9
  23. package/dist/{runClaude-D0DD_Ya5.mjs → runClaude-DpZ95Twb.mjs} +8 -6
  24. package/dist/{runCodex-BzZ0jODI.mjs → runCodex-CJwaep2R.mjs} +9 -7
  25. package/dist/{runCodex-1jTTmCvq.cjs → runCodex-Dz_1ho8d.cjs} +12 -10
  26. package/dist/{runGemini-Bx2SYAyG.mjs → runGemini-BehqjM73.mjs} +192 -71
  27. package/dist/{runGemini-1gJRE8oT.cjs → runGemini-Dfu6LltX.cjs} +192 -71
  28. package/package.json +1 -1
  29. package/scripts/build.mjs +66 -66
  30. package/scripts/devtools/README.md +9 -9
  31. package/scripts/e2e/fake-codex-acp-agent.mjs +139 -139
  32. package/scripts/e2e/local-server-session-roundtrip.mjs +1063 -1063
  33. package/scripts/release-smoke.mjs +3 -0
  34. package/dist/ProviderSelectionHandler-BjLyIfSR.mjs +0 -673
  35. package/dist/ProviderSelectionHandler-e4zL4Y5_.cjs +0 -680
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CqCEZDFi.cjs');
4
- var persistence = require('./persistence-yVTbf_Ng.cjs');
3
+ var index = require('./index-BQmJ4NAa.cjs');
4
+ var persistence = require('./persistence-BL06LLVz.cjs');
5
5
  var os = require('node:os');
6
6
  var path = require('node:path');
7
- var api = require('./api-DP-RQUao.cjs');
7
+ var api = require('./api-Bd-MnOS4.cjs');
8
8
  var node_crypto = require('node:crypto');
9
9
  var crypto = require('crypto');
10
10
  require('axios');
@@ -261,15 +261,18 @@ async function closeProviderSession(session, opts = {}) {
261
261
  firstError = error;
262
262
  }
263
263
  };
264
- if (opts.archiveReason) {
264
+ if (opts.archiveOnClose || opts.archiveReason) {
265
265
  try {
266
- session.updateMetadata((currentMetadata) => ({
267
- ...currentMetadata,
268
- lifecycleState: "archived",
269
- lifecycleStateSince: Date.now(),
270
- archivedBy: opts.archivedBy ?? "cli",
271
- archiveReason: opts.archiveReason
272
- }));
266
+ session.updateMetadata((currentMetadata) => {
267
+ const { archiveReason: _existingArchiveReason, ...metadataWithoutArchiveReason } = currentMetadata;
268
+ return {
269
+ ...metadataWithoutArchiveReason,
270
+ lifecycleState: "archived",
271
+ lifecycleStateSince: Date.now(),
272
+ archivedBy: opts.archivedBy ?? "cli",
273
+ ...opts.archiveReason ? { archiveReason: opts.archiveReason } : {}
274
+ };
275
+ });
273
276
  } catch (error) {
274
277
  captureError(error);
275
278
  }
@@ -299,7 +302,7 @@ function createAbortError() {
299
302
  error.name = "AbortError";
300
303
  return error;
301
304
  }
302
- async function waitForResponseCompleteWithAbort(backend, signal, timeoutMs = 12e4) {
305
+ async function waitForResponseCompleteWithAbort(backend, signal, timeoutMs = 10 * 6e4) {
303
306
  if (!backend.waitForResponseComplete) {
304
307
  return;
305
308
  }
@@ -353,6 +356,418 @@ async function syncControlledByUserState(sessionClient, controlledByUser) {
353
356
  });
354
357
  }
355
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
+
356
771
  const DEFAULT_MAX_MESSAGES = 200;
357
772
  const DEFAULT_MAX_CHARACTERS = 1e5;
358
773
  const DEFAULT_MAX_MESSAGE_CHARACTERS = 8e3;
@@ -1185,14 +1600,17 @@ exports.INTERACTION_TIMED_OUT_ERROR = INTERACTION_TIMED_OUT_ERROR;
1185
1600
  exports.MessageBuffer = MessageBuffer;
1186
1601
  exports.MessageQueue2 = MessageQueue2;
1187
1602
  exports.MissingMachineIdError = MissingMachineIdError;
1603
+ exports.buildHappyOrgTurnPrompt = buildHappyOrgTurnPrompt;
1188
1604
  exports.closeProviderSession = closeProviderSession;
1189
1605
  exports.createSessionMetadata = createSessionMetadata;
1190
1606
  exports.ensureManagedProviderMachine = ensureManagedProviderMachine;
1607
+ exports.finalizeHappyOrgTurn = finalizeHappyOrgTurn;
1191
1608
  exports.forwardAgentMessageToProviderSession = forwardAgentMessageToProviderSession;
1192
1609
  exports.getPendingInteractionTimeoutMs = getPendingInteractionTimeoutMs;
1193
1610
  exports.hashObject = hashObject;
1194
1611
  exports.inferToolResultError = inferToolResultError;
1195
1612
  exports.launchRuntimeHandleWithFactoryResult = launchRuntimeHandleWithFactoryResult;
1196
1613
  exports.registerKillSessionHandler = registerKillSessionHandler;
1614
+ exports.resolveHappyOrgQueuedTurn = resolveHappyOrgQueuedTurn;
1197
1615
  exports.syncControlledByUserState = syncControlledByUserState;
1198
1616
  exports.waitForResponseCompleteWithAbort = waitForResponseCompleteWithAbort;
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
- var api = require('./api-DP-RQUao.cjs');
4
+ var api = require('./api-Bd-MnOS4.cjs');
5
5
  require('cross-spawn');
6
6
  require('@agentclientprotocol/sdk');
7
- var index = require('./index-CqCEZDFi.cjs');
7
+ var index = require('./index-BQmJ4NAa.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-yVTbf_Ng.cjs');
18
+ require('./persistence-BL06LLVz.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-e4zL4Y5_.cjs');
29
+ var ProviderSelectionHandler = require('./ProviderSelectionHandler-5Dedbm8j.cjs');
30
30
  var types = require('./types-DVk3crez.cjs');
31
- var registerKillSessionHandler = require('./registerKillSessionHandler-QmBN446A.cjs');
31
+ var registerKillSessionHandler = require('./registerKillSessionHandler-D9kwxy6B.cjs');
32
32
  require('socket.io-client');
33
33
  require('expo-server-sdk');
34
34
  var node_util = require('node:util');
@@ -1388,7 +1388,7 @@ ${systemPrompt}` : systemPrompt,
1388
1388
  api.logger.debug(`[ClaudeACP] Injected conversation history context (${historyContext.length} chars)`);
1389
1389
  }
1390
1390
  if (message.mode.happyOrg) {
1391
- promptToSend = ProviderSelectionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1391
+ promptToSend = registerKillSessionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1392
1392
  }
1393
1393
  if (specialCommand.type === "compact") {
1394
1394
  emitStatusMessage("Compaction started");
@@ -1420,7 +1420,7 @@ ${systemPrompt}` : systemPrompt,
1420
1420
  currentModeHash = null;
1421
1421
  }
1422
1422
  } finally {
1423
- const finalizedTurn = ProviderSelectionHandler.finalizeHappyOrgTurn({
1423
+ const finalizedTurn = registerKillSessionHandler.finalizeHappyOrgTurn({
1424
1424
  metadata: session.client.getMetadataSnapshot?.() ?? null,
1425
1425
  queuedTurn: message.mode.happyOrg,
1426
1426
  responseText: accumulatedResponse,
@@ -3161,7 +3161,7 @@ function resolveClaudeQueuedMessage(message, currentState) {
3161
3161
  function bindClaudeUserMessageQueue(opts) {
3162
3162
  let currentState = { ...opts.initialState };
3163
3163
  opts.session.onUserMessage((message) => {
3164
- const happyOrgResult = opts.happyOrg ? ProviderSelectionHandler.resolveHappyOrgQueuedTurn({
3164
+ const happyOrgResult = opts.happyOrg ? registerKillSessionHandler.resolveHappyOrgQueuedTurn({
3165
3165
  metadata: opts.happyOrg.getMetadata(),
3166
3166
  message
3167
3167
  }) : {
@@ -3365,7 +3365,9 @@ async function runClaude(credentials, options = {}) {
3365
3365
  currentSession?.cleanup();
3366
3366
  api.logger.debug("Waiting for socket to flush...");
3367
3367
  api.logger.debug("Closing session...");
3368
- await registerKillSessionHandler.closeProviderSession(session);
3368
+ await registerKillSessionHandler.closeProviderSession(session, {
3369
+ archiveOnClose: true
3370
+ });
3369
3371
  index.stopCaffeinate();
3370
3372
  api.logger.debug("Stopped sleep prevention");
3371
3373
  hookServer.stop();
@@ -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-DrijKeDb.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-w_CUxb9Q.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-BIki80pQ.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-GuXV-pxB.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-C3NBdZdz.mjs';
16
+ import './persistence-MSy70is3.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-BjLyIfSR.mjs';
27
+ import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-BlrrLPlo.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-CHEj7UjN.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-CjWfUfc3.mjs';
30
30
  import 'socket.io-client';
31
31
  import 'expo-server-sdk';
32
32
  import { isDeepStrictEqual } from 'node:util';
@@ -3363,7 +3363,9 @@ async function runClaude(credentials, options = {}) {
3363
3363
  currentSession?.cleanup();
3364
3364
  logger.debug("Waiting for socket to flush...");
3365
3365
  logger.debug("Closing session...");
3366
- await closeProviderSession(session);
3366
+ await closeProviderSession(session, {
3367
+ archiveOnClose: true
3368
+ });
3367
3369
  stopCaffeinate();
3368
3370
  logger.debug("Stopped sleep prevention");
3369
3371
  hookServer.stop();
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { l as logger, f as connectionState, A as ApiClient } from './api-DrijKeDb.mjs';
3
- import { B as BasePermissionHandler, h as hashObject, d as MessageBuffer, C as ConversationHistory$1, w as waitForResponseCompleteWithAbort, r as registerKillSessionHandler, l as launchRuntimeHandleWithFactoryResult, i as inferToolResultError, j as forwardAgentMessageToProviderSession, f as closeProviderSession, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, s as syncControlledByUserState } from './registerKillSessionHandler-CHEj7UjN.mjs';
4
- import { f as formatDisplayMessage, v as validateCodexAcpSpawn, d as createCodexBackend, t as truncateDisplayMessage, b as stopCaffeinate } from './index-BIki80pQ.mjs';
2
+ import { l as logger, b as connectionState, A as ApiClient } from './api-w_CUxb9Q.mjs';
3
+ import { B as BasePermissionHandler, h as hashObject, f as MessageBuffer, C as ConversationHistory$1, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, d as registerKillSessionHandler, l as launchRuntimeHandleWithFactoryResult, m as inferToolResultError, n as forwardAgentMessageToProviderSession, k as closeProviderSession, e as ensureManagedProviderMachine, M as MissingMachineIdError, b as MessageQueue2, r as resolveHappyOrgQueuedTurn, s as syncControlledByUserState } from './registerKillSessionHandler-CjWfUfc3.mjs';
4
+ import { f as formatDisplayMessage, v as validateCodexAcpSpawn, d as createCodexBackend, t as truncateDisplayMessage, b as stopCaffeinate } from './index-GuXV-pxB.mjs';
5
5
  import 'cross-spawn';
6
6
  import '@agentclientprotocol/sdk';
7
7
  import 'ps-list';
@@ -14,7 +14,7 @@ import 'node:path';
14
14
  import 'node:os';
15
15
  import 'node:child_process';
16
16
  import 'node:readline';
17
- import './persistence-C3NBdZdz.mjs';
17
+ import './persistence-MSy70is3.mjs';
18
18
  import 'node:fs/promises';
19
19
  import 'fs/promises';
20
20
  import 'crypto';
@@ -25,8 +25,8 @@ import 'tweetnacl';
25
25
  import 'open';
26
26
  import React, { useState, useRef, useEffect, useCallback } from 'react';
27
27
  import { useStdout, useInput, Box, Text, render } from 'ink';
28
- import { c as createKeepAliveController, P as ProviderSelectionHandler, b as buildHappyOrgTurnPrompt, f as finalizeHappyOrgTurn, r as runModeLoop, a as resolveHappyOrgQueuedTurn } from './ProviderSelectionHandler-BjLyIfSR.mjs';
29
- import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-mIqqngd3.mjs';
28
+ import { c as createKeepAliveController, P as ProviderSelectionHandler, r as runModeLoop } from './ProviderSelectionHandler-BlrrLPlo.mjs';
29
+ import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-DQkzwRuf.mjs';
30
30
  import 'zod';
31
31
  import 'socket.io-client';
32
32
  import 'expo-server-sdk';
@@ -1297,7 +1297,9 @@ async function runCodex(opts) {
1297
1297
  loopError = error;
1298
1298
  } finally {
1299
1299
  try {
1300
- await closeProviderSession(sessionClient);
1300
+ await closeProviderSession(sessionClient, {
1301
+ archiveOnClose: true
1302
+ });
1301
1303
  } catch (error) {
1302
1304
  closeError = error;
1303
1305
  }