cuelo 0.7.2 → 0.8.1

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 (179) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +6 -5
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +27 -3
  5. package/.next/react-loadable-manifest.json +13 -3
  6. package/.next/required-server-files.js +2 -2
  7. package/.next/required-server-files.json +2 -2
  8. package/.next/routes-manifest.json +6 -0
  9. package/.next/server/app/_global-error/page.js +3 -3
  10. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/_global-error.html +1 -1
  12. package/.next/server/app/_global-error.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/server/app/_not-found/page.js +2 -2
  20. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/.next/server/app/_not-found.html +1 -1
  22. package/.next/server/app/_not-found.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  24. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  26. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/api/agent/[id]/account/route.js +1 -1
  30. package/.next/server/app/api/agent/[id]/bash-output/route.js +1 -1
  31. package/.next/server/app/api/agent/[id]/events/route.js +2 -2
  32. package/.next/server/app/api/agent/[id]/route.js +1 -1
  33. package/.next/server/app/api/agent/new/route.js +1 -1
  34. package/.next/server/app/api/agent/running/route.js +1 -1
  35. package/.next/server/app/api/attachments/route.js +2 -2
  36. package/.next/server/app/api/auth/all-providers/route.js +1 -1
  37. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
  38. package/.next/server/app/api/auth/login/[provider]/route.js +2 -2
  39. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
  40. package/.next/server/app/api/auth/providers/route.js +1 -1
  41. package/.next/server/app/api/cwd/browse/route.js +1 -1
  42. package/.next/server/app/api/cwd/validate/route.js +1 -1
  43. package/.next/server/app/api/default-cwd/route.js +1 -1
  44. package/.next/server/app/api/display-settings/route.js +1 -1
  45. package/.next/server/app/api/document-text/route.js +2 -2
  46. package/.next/server/app/api/experiments/route.js +1 -1
  47. package/.next/server/app/api/file-index/route.js +1 -1
  48. package/.next/server/app/api/files/[...path]/route.js +1 -1
  49. package/.next/server/app/api/git/diff/route.js +1 -1
  50. package/.next/server/app/api/git/status/route.js +2 -2
  51. package/.next/server/app/api/gpt6/handles/route.js +1 -1
  52. package/.next/server/app/api/gpt6/reply/route.js +1 -1
  53. package/.next/server/app/api/gpt6/token/route.js +1 -1
  54. package/.next/server/app/api/gpt6/web6-session/route.js +1 -1
  55. package/.next/server/app/api/home/route.js +1 -1
  56. package/.next/server/app/api/live/call/[callId]/route.js +1 -1
  57. package/.next/server/app/api/live/character-voice/route.js +1 -1
  58. package/.next/server/app/api/live/events/route.js +2 -2
  59. package/.next/server/app/api/live/offer/route.js +1 -1
  60. package/.next/server/app/api/live/voices/route.js +1 -1
  61. package/.next/server/app/api/lounge/events/route.js +2 -2
  62. package/.next/server/app/api/lounge/route.js +1 -1
  63. package/.next/server/app/api/mcp/route.js +2 -2
  64. package/.next/server/app/api/model-roles/route.js +1 -1
  65. package/.next/server/app/api/models/route.js +1 -1
  66. package/.next/server/app/api/models-config/catalog/route.js +1 -1
  67. package/.next/server/app/api/models-config/discover/route.js +1 -1
  68. package/.next/server/app/api/models-config/route.js +3 -3
  69. package/.next/server/app/api/models-config/test/route.js +1 -1
  70. package/.next/server/app/api/plugins/route.js +1 -1
  71. package/.next/server/app/api/project-trust/route.js +1 -1
  72. package/.next/server/app/api/projects/route.js +2 -2
  73. package/.next/server/app/api/runs/[runId]/route.js +1 -1
  74. package/.next/server/app/api/runs/route.js +1 -1
  75. package/.next/server/app/api/sessions/[id]/auto-name/route.js +1 -1
  76. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  77. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +1 -1
  78. package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
  79. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  80. package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
  81. package/.next/server/app/api/sessions/route.js +1 -1
  82. package/.next/server/app/api/sessions/search/route.js +1 -1
  83. package/.next/server/app/api/settings/route.js +1 -1
  84. package/.next/server/app/api/sidecars/[service]/[...path]/route.js +1 -1
  85. package/.next/server/app/api/skills/check/route.js +1 -1
  86. package/.next/server/app/api/skills/install/route.js +2 -2
  87. package/.next/server/app/api/skills/route.js +2 -2
  88. package/.next/server/app/api/skills/search/route.js +1 -1
  89. package/.next/server/app/api/skills/update/route.js +1 -1
  90. package/.next/server/app/api/theme/route.js +1 -1
  91. package/.next/server/app/api/tool-image/route.js +1 -1
  92. package/.next/server/app/api/update-maintenance/route.js +2 -2
  93. package/.next/server/app/api/updates/route.js +1 -1
  94. package/.next/server/app/api/web-access/recovery/route.js +1 -1
  95. package/.next/server/app/api/web-access/route.js +1 -1
  96. package/.next/server/app/api/web6/consults/route.js +1 -1
  97. package/.next/server/app/api/worktrees/route.js +1 -1
  98. package/.next/server/app/favicon.ico/route.js +1 -1
  99. package/.next/server/app/index.html +1 -1
  100. package/.next/server/app/index.rsc +7 -6
  101. package/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -4
  102. package/.next/server/app/index.segments/_full.segment.rsc +7 -6
  103. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  104. package/.next/server/app/index.segments/_index.segment.rsc +3 -3
  105. package/.next/server/app/index.segments/_tree.segment.rsc +4 -3
  106. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  107. package/.next/server/app/office-preview/page.js +2 -0
  108. package/.next/server/app/office-preview/page.js.nft.json +1 -0
  109. package/.next/server/app/office-preview/page_client-reference-manifest.js +1 -0
  110. package/.next/server/app/office-preview.html +1 -0
  111. package/.next/server/app/office-preview.meta +16 -0
  112. package/.next/server/app/office-preview.rsc +20 -0
  113. package/.next/server/app/office-preview.segments/_full.segment.rsc +20 -0
  114. package/.next/server/app/office-preview.segments/_head.segment.rsc +6 -0
  115. package/.next/server/app/office-preview.segments/_index.segment.rsc +7 -0
  116. package/.next/server/app/office-preview.segments/_tree.segment.rsc +4 -0
  117. package/.next/server/app/office-preview.segments/office-preview/__PAGE__.segment.rsc +7 -0
  118. package/.next/server/app/office-preview.segments/office-preview.segment.rsc +5 -0
  119. package/.next/server/app/page.js +19 -19
  120. package/.next/server/app/page.js.nft.json +1 -1
  121. package/.next/server/app/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/recover/page.js +2 -2
  123. package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app/recover.html +1 -1
  125. package/.next/server/app/recover.rsc +3 -3
  126. package/.next/server/app/recover.segments/_full.segment.rsc +3 -3
  127. package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
  128. package/.next/server/app/recover.segments/_index.segment.rsc +3 -3
  129. package/.next/server/app/recover.segments/_tree.segment.rsc +2 -2
  130. package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
  131. package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
  132. package/.next/server/app-paths-manifest.json +6 -5
  133. package/.next/server/chunks/205.js +3 -2
  134. package/.next/server/chunks/2607.js +1 -0
  135. package/.next/server/chunks/3602.js +353 -0
  136. package/.next/server/chunks/6429.js +3 -3
  137. package/.next/server/middleware-build-manifest.js +1 -1
  138. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  139. package/.next/server/pages/404.html +1 -1
  140. package/.next/server/pages/500.html +1 -1
  141. package/.next/server/server-reference-manifest.json +1 -1
  142. package/.next/static/_VEUT2T9aZcGJdOeXmxhm/_buildManifest.js +1 -0
  143. package/.next/static/chunks/1937.70e7ce89f87f1119.js +1 -0
  144. package/.next/static/chunks/2992.16b931bb2dfe8845.js +1 -0
  145. package/.next/static/chunks/{3308.34ea31e24088c85f.js → 3308.8b94b38809d1b8b6.js} +1 -1
  146. package/.next/static/chunks/52733464.85a1551044fef357.js +1 -0
  147. package/.next/static/chunks/9304.1f940d490ea5c972.js +1 -0
  148. package/.next/static/chunks/9889-481b318dcf48ee30.js +1 -0
  149. package/.next/static/chunks/app/{layout-fc24ec6959a6cba5.js → layout-27cec017946e8765.js} +1 -1
  150. package/.next/static/chunks/app/office-preview/page-5874dc1ab28d3b1d.js +1 -0
  151. package/.next/static/chunks/app/page-95261aed574d5860.js +22 -0
  152. package/.next/static/chunks/b536a0f1.f7e390612229faa9.js +342 -0
  153. package/.next/static/chunks/bd904a5c.b74776e0b23d0607.js +1 -0
  154. package/.next/static/chunks/f5ef5e1c.14b6095722ff4f0b.js +12 -0
  155. package/.next/static/chunks/{framework-32a7466d5cae4a81.js → framework-e405bc515d75023a.js} +1 -1
  156. package/.next/static/chunks/webpack-d2da69f7c8164141.js +1 -0
  157. package/.next/static/css/001d6e9d9d06b017.css +1 -0
  158. package/.next/static/css/{88929dd0c6d44c84.css → 67b6e19482963224.css} +1 -1
  159. package/.next/static/css/{27f16a2ddaff39eb.css → abd3d00cca9457f7.css} +1 -1
  160. package/.next/trace +106 -106
  161. package/.next/trace-build +1 -1
  162. package/.next/types/app/office-preview/page.ts +87 -0
  163. package/.next/types/routes.d.ts +2 -1
  164. package/.next/types/validator.ts +9 -0
  165. package/README.md +6 -4
  166. package/Tools/CUELO_Setup/files/native-runtime-patch.js +5 -5
  167. package/Tools/OMP_Global_Config/agent/extensions/character-voice.ts +2 -2
  168. package/Tools/OMP_Global_Config/agent/extensions/lib/maker-routing.ts +32 -1
  169. package/Tools/OMP_Global_Config/agent/tools/git-finalizer/index.ts +45 -5
  170. package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +246 -392
  171. package/install.mjs +6 -2
  172. package/package.json +10 -7
  173. package/public/office3d/ASSETS.md +8 -0
  174. package/.next/static/5vW3pyOv87cK3zk2pchwv/_buildManifest.js +0 -1
  175. package/.next/static/chunks/2619.9aac8983f30c7c8a.js +0 -1
  176. package/.next/static/chunks/52733464.3870f99cc446f9ff.js +0 -1
  177. package/.next/static/chunks/app/page-11dfb512f246679c.js +0 -22
  178. package/.next/static/chunks/webpack-b1a76402d0d0fa1a.js +0 -1
  179. /package/.next/static/{5vW3pyOv87cK3zk2pchwv → _VEUT2T9aZcGJdOeXmxhm}/_ssgManifest.js +0 -0
@@ -64,6 +64,20 @@ const OPUS55_ROW_1846 = {
64
64
  patched: '"claude-opus-5-5":{"id":"claude-opus-5-5","name":"Claude Opus 5.5","api":"anthropic-messages","provider":"anthropic","baseUrl":"https://api.anthropic.com","reasoning":true,"input":["text","image"],"cost":{"input":4,"output":20,"cacheRead":0.2,"cacheWrite":5},"contextWindow":1000000,"maxTokens":128000,"int":57.6,"tps":95.2,"thinking":{"mode":"anthropic-adaptive","efforts":["low","medium","high","xhigh","max"],"supportsDisplay":true,"prefixBinding":true},"identity":{"class":"anthropic","family":"opus","revision":"5.5.0"},"requiresGlyphTokenization":true,"tokenizer":"claude-v5","supportsComputerUse":false,"compat":{"officialEndpoint":true,"signingEndpoint":true,"supportsContextManagement":true,"supportsServerCompaction":true,"firstPartyProvider":true,"supportsOutputEffort":true,"disableStrictTools":false,"disableAdaptiveThinking":false,"allowAnthropicHeaderOverrides":false,"supportsEagerToolInputStreaming":true,"supportsLongCacheRetention":true,"supportsMidConversationSystem":true,"supportsTurnScopedSystem":true,"supportsMidConversationToolChanges":true,"supportsPerMessageEffort":true,"supportsThinkingBindingControls":true',
65
65
  };
66
66
 
67
+ /**
68
+ * #310의 18.4.10 후보. binding controls만 켜고 18.4.6 결과와 `": true"` 공백으로 구분한다(EDITS 항목 주석). marker는
69
+ * patched 전체다: 18.4.12 후보와는 행 앞쪽 측정값 tps로만 갈리므로 tps 뒤 조각을 marker로 쓰면 둘 다 applied가 된다.
70
+ */
71
+ const OPUS55_TPS_18410 = '"tps":95.2,';
72
+ const OPUS55_TPS_18412 = '"tps":92.9,';
73
+ const OPUS55_ROW_18410_PATCHED = OPUS55_ROW_1846.patched.replace('"supportsThinkingBindingControls":true', '"supportsThinkingBindingControls": true');
74
+ const OPUS55_ROW_18410 = {
75
+ file: "../pi-catalog/src/models.json",
76
+ marker: OPUS55_ROW_18410_PATCHED,
77
+ anchor: OPUS55_ROW_1846.anchor.replace('"supportsDisplay":true}', '"supportsDisplay":true,"prefixBinding":true}'),
78
+ patched: OPUS55_ROW_18410_PATCHED,
79
+ };
80
+
67
81
  /** 각 항목: 원본 앵커를 찾아 patched 로 바꾼다. marker 가 있으면 이미 적용된 것으로 본다. */
68
82
  const EDITS = [
69
83
  {
@@ -454,6 +468,136 @@ const EDITS = [
454
468
  anchor: " Every task MUST skip build/lint/tests/formatters mid-flight; run once afterward.",
455
469
  patched: " Validation ownership: each task owner MUST run the smallest meaningful validation for its settled changes; do not blanket-ban independent checks. Defer only checks that depend on another writer's unfinished changes or concurrently mutate the same build output, cache, database, or profile; name one owner and run each shared check once after convergence, reusing valid results instead of repeating them in Main.",
456
470
  },
471
+ {
472
+ // 18.4.12(upstream "subagents skip their own builds, tests, and smoke runs")는 subagent 렌더에서 # 5. Verify 전체를
473
+ // "NEVER verify your changes … unless your assignment explicitly instructs it" Hand-off 로 바꿨다. CUELO 계약은
474
+ // Maker 가 자기 변경을 집중 검사로 증명·보고하고 무거운 통합 검사는 Main 에 exact command 로 넘기는 것이다
475
+ // (agent/sop/_writer.md, rule://subagent 「검증 소유권」). 그래서 subagent 에도 Verify 본문(UI·버그·테스트 규칙)을
476
+ // 그대로 두고 subagent 줄만 앞에 붙인다. 프로젝트 전체 검사 금지는 이 템플릿에 worktree 정보가 없어 여기 두지 않고
477
+ // subagent-system-prompt.md 의 `{{#unless worktree}}` # Validation 이 맡는다(18.4.10 의미). 18.4.10 에는 subagent
478
+ // 분기가 없어 할 일이 없다: alternate 는 그 판 Verify 머리의 no-op 이고, 18.4.12 결과와 순정 어디에도 없는 문맥이다.
479
+ file: "src/prompts/system/system-prompt.md",
480
+ marker: "Scoped proof of your own change is yours:",
481
+ anchor: `{{#if subagent}}
482
+ # 5. Hand-off
483
+ Main agent verifies once after all subagents land; parallel runs storm the CPU and trip on siblings' half-finished edits.
484
+ - NEVER verify your changes (builds, tests, linters, formatters, smoke runs) unless your assignment explicitly instructs it.
485
+ - Changes complete → yield; name the checks main agent should run.
486
+ {{else}}
487
+ # 5. Verify
488
+ Non-trivial work: NEVER yield without a smoke run: run the thing, exercise the changed path, observe the result. Tests alone are not proof.
489
+ - Investigation: run it; output proves it; no tests.
490
+ - UI: verify actual surface.
491
+ {{#if browserEnabled}}
492
+ - Web: \`browser.open\` tab, direct helpers for actions, \`tab.run\` for custom JS; visual proof; \`tab.close\`. No tests unless existing suite breaks.
493
+ {{/if}}
494
+ {{#if computerEnabled}}
495
+ - Native desktop: JS/Python eval \`computer\` helpers; fresh screenshot/accessibility proof.
496
+ {{/if}}
497
+ - TUI/CLI: launch actual program; observe interaction/output/state.
498
+ {{#ifAny (not browserEnabled) (not computerEnabled)}}
499
+ - No runtime for changed surface: throwaway script/smoke test; report visual limit.
500
+ {{/ifAny}}
501
+ - Bug: reproduce before; confirm after. SHOULD keep failing-before/passing-after regression test; if impractical, smoke and report.
502
+ - Feature/API: update broken contract tests; prove new behavior via throwaway script. New test ONLY for uncertain edge or user request.
503
+ - Permanent tests MUST catch plausible consumer-visible bugs: behavior, boundaries, invariants, transitions, precedence, errors. Follow conventions; deterministic, isolated, full-suite-safe.
504
+ - NEVER test wiring/copies/forwarding/mock echoes/source text/incidental defaults, tautologies, bare not-throw, non-empty/length-grew, duplicate same-path rows. Use throwaway scripts.
505
+ - Existing wording/implementation/incidental-behavior tests: MUST delete, NEVER re-pin regardless of author.
506
+ {{/if}}
507
+
508
+ # 6. Cleanup
509
+ {{#if subagent}}Permanent{{else}}After smoke proof: permanent{{/if}} fix/feature`,
510
+ patched: `# 5. Verify
511
+ {{#if subagent}}
512
+ Scoped proof of your own change is yours: run the single test file, targeted repro, or smoke run below that exercises the changed path, and report each command, exit status, and observed result. A check you cannot run here, or a heavy integration check main agent owns → yield its exact command for main agent to run.
513
+ {{/if}}
514
+ Non-trivial work: NEVER yield without a smoke run: run the thing, exercise the changed path, observe the result. Tests alone are not proof.
515
+ - Investigation: run it; output proves it; no tests.
516
+ - UI: verify actual surface.
517
+ {{#if browserEnabled}}
518
+ - Web: \`browser.open\` tab, direct helpers for actions, \`tab.run\` for custom JS; visual proof; \`tab.close\`. No tests unless existing suite breaks.
519
+ {{/if}}
520
+ {{#if computerEnabled}}
521
+ - Native desktop: JS/Python eval \`computer\` helpers; fresh screenshot/accessibility proof.
522
+ {{/if}}
523
+ - TUI/CLI: launch actual program; observe interaction/output/state.
524
+ {{#ifAny (not browserEnabled) (not computerEnabled)}}
525
+ - No runtime for changed surface: throwaway script/smoke test; report visual limit.
526
+ {{/ifAny}}
527
+ - Bug: reproduce before; confirm after. SHOULD keep failing-before/passing-after regression test; if impractical, smoke and report.
528
+ - Feature/API: update broken contract tests; prove new behavior via throwaway script. New test ONLY for uncertain edge or user request.
529
+ - Permanent tests MUST catch plausible consumer-visible bugs: behavior, boundaries, invariants, transitions, precedence, errors. Follow conventions; deterministic, isolated, full-suite-safe.
530
+ - NEVER test wiring/copies/forwarding/mock echoes/source text/incidental defaults, tautologies, bare not-throw, non-empty/length-grew, duplicate same-path rows. Use throwaway scripts.
531
+ - Existing wording/implementation/incidental-behavior tests: MUST delete, NEVER re-pin regardless of author.
532
+
533
+ # 6. Cleanup
534
+ After smoke proof: permanent fix/feature`,
535
+ alternates: [{
536
+ file: "src/prompts/system/system-prompt.md",
537
+ marker: "code made obsolete by cutover is in scope.{{/has}}\n\n# 5. Verify\nNon-trivial work:",
538
+ anchor: "code made obsolete by cutover is in scope.{{/has}}\n\n# 5. Verify\nNon-trivial work:",
539
+ patched: "code made obsolete by cutover is in scope.{{/has}}\n\n# 5. Verify\nNon-trivial work:",
540
+ }],
541
+ },
542
+ {
543
+ // 같은 18.4.12 변경이 project-prompt.md <critical> 의 검증 의무 줄을 subagent 에서 "verification is main agent's job.
544
+ // NEVER run it yourself …"로 바꿨다. 의무 줄을 모두에게 되돌리고 subagent 범위(집중 증명·exit status 보고·못 돌린
545
+ // 검사의 exact command)만 덧붙인다. 18.4.10 alternate 는 그 판 의무 줄(바로 뒤 </critical>)의 no-op 이다.
546
+ file: "src/prompts/system/project-prompt.md",
547
+ marker: "- As a subagent, that proof is a scoped check of your own change;",
548
+ anchor: `{{#if subagent}}
549
+ - Changes complete → yield; verification is main agent's job. NEVER run it yourself unless your assignment explicitly instructs it.
550
+ {{else}}
551
+ - Before yielding, MUST verify significant behavioral changes: run the specific test, command, or scenario covering the change.
552
+ {{/if}}`,
553
+ patched: `- Before yielding, MUST verify significant behavioral changes: run the specific test, command, or scenario covering the change.
554
+ {{#if subagent}}
555
+ - As a subagent, that proof is a scoped check of your own change; report its command and exit status, and yield the exact command for any check you cannot run so main agent runs it.
556
+ {{/if}}`,
557
+ alternates: [{
558
+ file: "src/prompts/system/project-prompt.md",
559
+ marker: "- Before yielding, MUST verify significant behavioral changes: run the specific test, command, or scenario covering the change.\n</critical>",
560
+ anchor: "- Before yielding, MUST verify significant behavioral changes: run the specific test, command, or scenario covering the change.\n</critical>",
561
+ patched: "- Before yielding, MUST verify significant behavioral changes: run the specific test, command, or scenario covering the change.\n</critical>",
562
+ }],
563
+ },
564
+ {
565
+ // 18.4.11 은 subagent-system-prompt.md 의 # Validation 절을 지웠다. 18.4.10 과 같은 자리·같은 `{{#unless worktree}}`
566
+ // 조건으로 되돌린다: 작업 트리를 형제와 공유할 때만 프로젝트 전체 빌드·포매터·린터·전체 스위트를 금지한다(형제의 미완
567
+ // 편집·CPU 경합). 집중 증명은 "fine"(허용)이 아니라 요구로 적는다 — 18.4.12 의 다른 두 템플릿과 같은 계약이고,
568
+ // 18.4.10 순정 문장과 구분돼 그 판에서 applied 로 보이지 않는다. 18.4.10 alternate 는 그 판 절 끝의 no-op 이다.
569
+ file: "src/prompts/system/subagent-system-prompt.md",
570
+ marker: "Scoped proof of your own change (single test file, targeted repro, smoke run) is still required: run it and report the result.",
571
+ anchor: "You are operating on a piece of work assigned to you by the main agent.\n\n{{#if worktree}}",
572
+ patched: `You are operating on a piece of work assigned to you by the main agent.
573
+
574
+ {{#unless worktree}}
575
+ # Validation
576
+ Project-wide validation is the main agent's job, run once after all subagents land. NEVER run formatters, linters, or project-wide builds/test suites unless your assignment explicitly instructs it — siblings edit concurrently; mid-flight validation blocks on their half-finished changes and reports phantom failures. Scoped proof of your own change (single test file, targeted repro, smoke run) is still required: run it and report the result.
577
+ {{/unless}}
578
+
579
+ {{#if worktree}}`,
580
+ alternates: [{
581
+ file: "src/prompts/system/subagent-system-prompt.md",
582
+ marker: "Scoped proof of your own change (single test file, targeted repro, smoke run) is fine.\n{{/unless}}",
583
+ anchor: "Scoped proof of your own change (single test file, targeted repro, smoke run) is fine.\n{{/unless}}",
584
+ patched: "Scoped proof of your own change (single test file, targeted repro, smoke run) is fine.\n{{/unless}}",
585
+ }],
586
+ },
587
+ {
588
+ // 18.4.11 은 같은 파일 Completion 의 "investigate, edit, run, verify." 에서 run·verify 를 뺐다. 실행·검증을 되살리되
589
+ // 범위를 집중 검사로 적는다(18.4.10 문장과도 구분된다). 18.4.10 alternate 는 그 판 문장의 no-op 이다.
590
+ file: "src/prompts/system/subagent-system-prompt.md",
591
+ marker: "you MUST continue with another tool call — investigate, edit, run scoped checks, verify.",
592
+ anchor: "you MUST continue with another tool call — investigate, edit. Save narrative",
593
+ patched: "you MUST continue with another tool call — investigate, edit, run scoped checks, verify. Save narrative",
594
+ alternates: [{
595
+ file: "src/prompts/system/subagent-system-prompt.md",
596
+ marker: "you MUST continue with another tool call — investigate, edit, run, verify. Save narrative",
597
+ anchor: "you MUST continue with another tool call — investigate, edit, run, verify. Save narrative",
598
+ patched: "you MUST continue with another tool call — investigate, edit, run, verify. Save narrative",
599
+ }],
600
+ },
457
601
  {
458
602
  // 2026-09-15 실환경: 사용자가 보낸 steer 가 ask 시작 12.7초 전에 큐에
459
603
  // 들어왔지만, ask 가 24분 timeout 을 전부 기다린 뒤에야 interrupt_skipped
@@ -2063,373 +2207,6 @@ function evalRejectionResult(error: unknown): AgentToolResult<EvalToolDetails |
2063
2207
  return result;
2064
2208
  });`,
2065
2209
  },
2066
- // ---- task maker external runtime bridge (Codex app-server / Claude Code CLI) ----
2067
- // 분기는 코어가 provider/model/auth fallback 을 최종 승인한 뒤에만 일어난다.
2068
- // 두 env 중 하나라도 없거나 maker 이외 agent 면 기존 createAgentSession 경로를 그대로 탄다.
2069
- {
2070
- file: "src/task/executor.ts",
2071
- marker: 'import { pathToFileURL } from "node:url";',
2072
- anchor: `import path from "node:path";`,
2073
- patched: `import path from "node:path";
2074
- import { pathToFileURL } from "node:url";`,
2075
- },
2076
- {
2077
- file: "src/task/executor.ts",
2078
- marker: `type ExternalMakerEngine = "codex" | "claude";`,
2079
- anchor: `function normalizeModelPatterns(value: string | string[] | undefined): string[] {
2080
- if (!value) return [];
2081
- if (Array.isArray(value)) {
2082
- return value.map(entry => entry.trim()).filter(Boolean);
2083
- }
2084
- return value
2085
- .split(",")
2086
- .map(entry => entry.trim())
2087
- .filter(Boolean);
2088
- }`,
2089
- patched: `function normalizeModelPatterns(value: string | string[] | undefined): string[] {
2090
- if (!value) return [];
2091
- if (Array.isArray(value)) {
2092
- return value.map(entry => entry.trim()).filter(Boolean);
2093
- }
2094
- return value
2095
- .split(",")
2096
- .map(entry => entry.trim())
2097
- .filter(Boolean);
2098
- }
2099
-
2100
- type ExternalMakerEngine = "codex" | "claude";
2101
- type ExternalMakerEvent =
2102
- | { type: "session_started"; sessionId: string; engine: ExternalMakerEngine }
2103
- | { type: "text_delta"; text: string }
2104
- | { type: "reasoning_delta"; text: string }
2105
- | { type: "tool_started"; id: string; name: string; input: unknown }
2106
- | { type: "tool_completed"; id: string; output: string; isError: boolean }
2107
- | { type: "file_changed"; path: string }
2108
- | { type: "usage"; input: number; cachedInput: number; cacheWrite: number; output: number }
2109
- | { type: "turn_completed"; stopReason: "stop" | "aborted" | "error"; text: string }
2110
- | { type: "error"; message: string };
2111
-
2112
- interface ExternalMakerSession {
2113
- readonly id: string;
2114
- readonly engine: ExternalMakerEngine;
2115
- prompt(message: string): Promise<void>;
2116
- abort(): Promise<void>;
2117
- onEvent(handler: (event: ExternalMakerEvent) => void): () => void;
2118
- dispose(): Promise<void>;
2119
- }
2120
-
2121
- interface ExternalMakerRuntime {
2122
- createSession(options: {
2123
- cwd: string;
2124
- model?: string;
2125
- thinking?: string;
2126
- }): Promise<ExternalMakerSession>;
2127
- }
2128
-
2129
- function resolveExternalMakerEngine(
2130
- agentName: string,
2131
- model: Model<Api> | undefined,
2132
- ): { engine: ExternalMakerEngine; runtimeDir: string } | undefined {
2133
- if (agentName !== "maker" || !model) return undefined;
2134
- const configured = process.env.CUELO_MAKER_ENGINES?.trim();
2135
- const runtimeDir = process.env.CUELO_RUNTIME_DIR?.trim();
2136
- if (!configured || !runtimeDir) return undefined;
2137
- const engines = new Set(configured.split(",").map(value => value.trim()).filter(Boolean));
2138
- const engine =
2139
- model.provider === "openai-codex" && engines.has("codex")
2140
- ? "codex"
2141
- : model.provider === "anthropic" && engines.has("claude")
2142
- ? "claude"
2143
- : undefined;
2144
- if (!engine) return undefined;
2145
- if (!path.isAbsolute(runtimeDir)) {
2146
- throw new Error("CUELO_RUNTIME_DIR must be an absolute path when an external maker engine is selected");
2147
- }
2148
- return { engine, runtimeDir };
2149
- }
2150
-
2151
- async function loadExternalMakerRuntime(
2152
- engine: ExternalMakerEngine,
2153
- runtimeDir: string,
2154
- ): Promise<ExternalMakerRuntime> {
2155
- const moduleUrl = pathToFileURL(path.join(runtimeDir, "index.ts")).href;
2156
- const runtimeModule = (await import(moduleUrl)) as {
2157
- getRuntime?: (selected: ExternalMakerEngine) => Promise<ExternalMakerRuntime>;
2158
- };
2159
- if (typeof runtimeModule.getRuntime !== "function") {
2160
- throw new Error(\`CUELO runtime module does not export getRuntime(): \${moduleUrl}\`);
2161
- }
2162
- return runtimeModule.getRuntime(engine);
2163
- }`,
2164
- },
2165
- {
2166
- file: "src/task/executor.ts",
2167
- marker: "acceptExternalEvent(event: ExternalMakerEvent, engine: ExternalMakerEngine): void;",
2168
- anchor: ` /** Subscribe the monitor to a session's events. Returns the unsubscribe function. */
2169
- attach(session: AgentSession): () => void;`,
2170
- patched: ` /** Subscribe the monitor to a session's events. Returns the unsubscribe function. */
2171
- attach(session: AgentSession): () => void;
2172
- /** Translate one optional-runtime event into the existing task progress/result stream. */
2173
- acceptExternalEvent(event: ExternalMakerEvent, engine: ExternalMakerEngine): void;`,
2174
- },
2175
- {
2176
- file: "src/task/executor.ts",
2177
- marker: "let hasExternalUsage = false;",
2178
- anchor: ` const outputChunks: string[] = [];
2179
- const finalOutputChunks: string[] = [];`,
2180
- patched: ` const outputChunks: string[] = [];
2181
- const finalOutputChunks: string[] = [];
2182
- const externalToolNames = new Map<string, string>();
2183
- let externalStreamText = "";
2184
- let hasExternalUsage = false;
2185
- const externalUsage = { input: 0, cachedInput: 0, cacheWrite: 0, output: 0 };`,
2186
- },
2187
- {
2188
- file: "src/task/executor.ts",
2189
- marker: "const acceptExternalEvent = (event: ExternalMakerEvent, engine: ExternalMakerEngine): void => {",
2190
- anchor: ` const publishAdvisorState = (session: AgentSession | null): void => {`,
2191
- patched: ` const acceptExternalEvent = (event: ExternalMakerEvent, engine: ExternalMakerEngine): void => {
2192
- const forward = (mapped: AgentEvent): void => {
2193
- emitSubagentEvent(mapped);
2194
- processEvent(mapped);
2195
- };
2196
- switch (event.type) {
2197
- case "session_started":
2198
- emitSubagentEvent({ type: "agent_start" } as AgentEvent);
2199
- break;
2200
- case "text_delta": {
2201
- externalStreamText += event.text;
2202
- forward({
2203
- type: "message_update",
2204
- message: { role: "assistant", content: [] },
2205
- assistantMessageEvent: { type: "text_delta", delta: event.text },
2206
- } as unknown as AgentEvent);
2207
- break;
2208
- }
2209
- case "reasoning_delta":
2210
- forward({
2211
- type: "message_update",
2212
- message: { role: "assistant", content: [] },
2213
- assistantMessageEvent: { type: "thinking_delta", delta: event.text },
2214
- } as unknown as AgentEvent);
2215
- break;
2216
- case "tool_started":
2217
- externalToolNames.set(event.id, event.name);
2218
- forward({
2219
- type: "tool_execution_start",
2220
- toolCallId: event.id,
2221
- toolName: event.name,
2222
- args: isRecord(event.input) ? event.input : {},
2223
- } as unknown as AgentEvent);
2224
- break;
2225
- case "tool_completed": {
2226
- const toolName = externalToolNames.get(event.id) ?? "external-tool";
2227
- externalToolNames.delete(event.id);
2228
- forward({
2229
- type: "tool_execution_end",
2230
- toolCallId: event.id,
2231
- toolName,
2232
- args: {},
2233
- result: { content: [{ type: "text", text: event.output }], details: {} },
2234
- isError: event.isError,
2235
- } as unknown as AgentEvent);
2236
- break;
2237
- }
2238
- case "file_changed":
2239
- progress.lastIntent = \`changed \${event.path}\`;
2240
- scheduleProgress();
2241
- break;
2242
- case "usage":
2243
- hasExternalUsage = true;
2244
- externalUsage.input += event.input;
2245
- externalUsage.cachedInput += event.cachedInput;
2246
- externalUsage.cacheWrite += event.cacheWrite;
2247
- externalUsage.output += event.output;
2248
- break;
2249
- case "turn_completed": {
2250
- const report = event.text.trim() ? event.text : externalStreamText;
2251
- const finalText = \`[external-engine: \${engine}]\${report ? \`\\n\\n\${report}\` : ""}\`;
2252
- const usage = hasExternalUsage
2253
- ? {
2254
- input: externalUsage.input,
2255
- output: externalUsage.output,
2256
- cacheRead: externalUsage.cachedInput,
2257
- cacheWrite: externalUsage.cacheWrite,
2258
- totalTokens:
2259
- externalUsage.input +
2260
- externalUsage.cachedInput +
2261
- externalUsage.cacheWrite +
2262
- externalUsage.output,
2263
- reasoningTokens: 0,
2264
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
2265
- }
2266
- : undefined;
2267
- const message = {
2268
- role: "assistant",
2269
- content: [{ type: "text", text: finalText }],
2270
- ...(usage ? { usage } : {}),
2271
- };
2272
- forward({ type: "message_end", message } as unknown as AgentEvent);
2273
- forward({ type: "agent_end", messages: [message] } as unknown as AgentEvent);
2274
- if (event.stopReason === "stop") {
2275
- recordExtractedToolData("yield", { useLastTurn: true });
2276
- }
2277
- break;
2278
- }
2279
- case "error":
2280
- progress.lastIntent = "external-engine error";
2281
- scheduleProgress(true);
2282
- break;
2283
- }
2284
- };
2285
-
2286
- const publishAdvisorState = (session: AgentSession | null): void => {`,
2287
- },
2288
- {
2289
- file: "src/task/executor.ts",
2290
- marker: "\t\tacceptExternalEvent,",
2291
- anchor: ` attach,
2292
- captureSalvage,`,
2293
- patched: ` attach,
2294
- acceptExternalEvent,
2295
- captureSalvage,`,
2296
- },
2297
- {
2298
- file: "src/task/executor.ts",
2299
- marker: "Running maker with external engine",
2300
- anchor: ` const sessionManagerPromise = sessionFile
2301
- ? SessionManager.open(sessionFile, undefined, undefined, {
2302
- initialCwd: effectiveCwd,
2303
- parentSession: options.sessionFile ?? undefined,
2304
- suppressBreadcrumb: true,
2305
- })
2306
- : Promise.resolve(SessionManager.inMemory(effectiveCwd));`,
2307
- patched: ` const externalSelection = resolveExternalMakerEngine(agent.name, model);
2308
- if (externalSelection) {
2309
- const { engine, runtimeDir } = externalSelection;
2310
- progress.resolvedModelRoute = \`external-engine: \${engine}\`;
2311
- logger.info("Running maker with external engine", {
2312
- id,
2313
- engine,
2314
- provider: model?.provider,
2315
- model: model?.id,
2316
- });
2317
- emitSubagentFrame(options.eventBus, options.subagentEventBus, TASK_SUBAGENT_LIFECYCLE_CHANNEL, {
2318
- id,
2319
- agent: agent.name,
2320
- parentToolCallId: options.parentToolCallId,
2321
- detached: options.detached,
2322
- agentSource: agent.source,
2323
- description: options.description,
2324
- status: "started" as const,
2325
- sessionFile: subtaskSessionFile,
2326
- index,
2327
- });
2328
- const runtime = await awaitAbortable(loadExternalMakerRuntime(engine, runtimeDir));
2329
- const sessionPromise = runtime.createSession({
2330
- cwd: effectiveCwd,
2331
- model: model?.id,
2332
- thinking: effectiveThinkingLevel,
2333
- });
2334
- let externalSession: ExternalMakerSession;
2335
- try {
2336
- externalSession = await awaitAbortable(sessionPromise);
2337
- } catch (err) {
2338
- if (abortSignal.aborted) void sessionPromise.then(session => session.dispose()).catch(() => {});
2339
- throw err;
2340
- }
2341
- let stopReason: "stop" | "aborted" | "error" | undefined;
2342
- let externalError: string | undefined;
2343
- const unsubscribeExternal = externalSession.onEvent(event => {
2344
- if (event.type === "turn_completed") stopReason = event.stopReason;
2345
- if (event.type === "error") externalError = event.message;
2346
- monitor.acceptExternalEvent(event, engine);
2347
- });
2348
- const onExternalAbort = () => {
2349
- void externalSession.abort().catch(err => {
2350
- logger.debug("External maker abort failed", {
2351
- id,
2352
- engine,
2353
- error: err instanceof Error ? err.message : String(err),
2354
- });
2355
- });
2356
- };
2357
- abortSignal.addEventListener("abort", onExternalAbort, { once: true });
2358
- try {
2359
- const externalSystemPrompt = prompt.render(subagentSystemPromptTemplate, {
2360
- agent: agent.systemPrompt,
2361
- context: options.context?.trim() ?? "",
2362
- planReference: options.planReference?.content ?? "",
2363
- planReferencePath: options.planReference?.path ?? "",
2364
- worktree: worktree ?? "",
2365
- outputSchema: undefined,
2366
- outputSchemaOverridesAgent: false,
2367
- workPoolYieldItems: [],
2368
- ircPeers: [],
2369
- ircParkedCount: 0,
2370
- ircOmittedCount: 0,
2371
- ircSelfId: "",
2372
- });
2373
- const externalPrompt =
2374
- \`\${externalSystemPrompt}\\n\\n§ External engine completion\\n\` +
2375
- "Complete the assignment and return the final report as ordinary text in this turn. " +
2376
- "The bridge normalizes that text into the parent task result; the OMP yield tool is unavailable.\\n\\n" +
2377
- \`§ Assignment\\n\${task}\`;
2378
- readyAt = performance.now();
2379
- await awaitAbortable(externalSession.prompt(externalPrompt));
2380
- if (abortSignal.aborted || stopReason === "aborted") {
2381
- return {
2382
- exitCode: 1,
2383
- aborted: true,
2384
- abortReason: monitor.resolveAbortReasonText(),
2385
- durationMs: Date.now() - startTime,
2386
- };
2387
- }
2388
- if (stopReason !== "stop") {
2389
- throw new Error(externalError ?? \`External maker engine \${engine} ended without a successful turn\`);
2390
- }
2391
- return { exitCode: 0, durationMs: Date.now() - startTime };
2392
- } finally {
2393
- abortSignal.removeEventListener("abort", onExternalAbort);
2394
- unsubscribeExternal();
2395
- await externalSession.dispose();
2396
- }
2397
- }
2398
-
2399
- const sessionManagerPromise = sessionFile
2400
- ? SessionManager.open(sessionFile, undefined, undefined, {
2401
- initialCwd: effectiveCwd,
2402
- parentSession: options.sessionFile ?? undefined,
2403
- suppressBreadcrumb: true,
2404
- })
2405
- : Promise.resolve(SessionManager.inMemory(effectiveCwd));`,
2406
- },
2407
- {
2408
- file: "src/task/executor.ts",
2409
- marker: 'const externalEngineResult = progress.resolvedModelRoute?.startsWith("external-engine:") === true;',
2410
- anchor: ` // Breadcrumb the synchronous yield-payload shaping (O(rawOutput)) so a block
2411
- // here is attributed to this subagent rather than logged as "unknown".
2412
- pushLoopPhase(\`subagent:\${id}\`);
2413
- let finalized: FinalizeSubprocessOutputResult;`,
2414
- patched: ` // Breadcrumb the synchronous yield-payload shaping (O(rawOutput)) so a block
2415
- // here is attributed to this subagent rather than logged as "unknown".
2416
- pushLoopPhase(\`subagent:\${id}\`);
2417
- const externalEngineResult = progress.resolvedModelRoute?.startsWith("external-engine:") === true;
2418
- let finalized: FinalizeSubprocessOutputResult;`,
2419
- },
2420
- {
2421
- file: "src/task/executor.ts",
2422
- marker: 'outputSchemaSource: externalEngineResult ? "none" : args.outputSchemaSource,',
2423
- anchor: ` outputSchema: args.outputSchema,
2424
- outputSchemaMode: args.outputSchemaMode,
2425
- outputSchemaSource: args.outputSchemaSource,`,
2426
- patched: ` // Optional runtimes return one ordinary-text turn and do not expose the
2427
- // core yield tool. Keep their result on the normal SingleResult path,
2428
- // but do not claim caller-schema validation that never ran.
2429
- outputSchema: externalEngineResult ? undefined : args.outputSchema,
2430
- outputSchemaMode: externalEngineResult ? undefined : args.outputSchemaMode,
2431
- outputSchemaSource: externalEngineResult ? "none" : args.outputSchemaSource,`,
2432
- },
2433
2210
  // ---- task per-item model selector (Arena hypothesis makers) ----
2434
2211
  // 네이티브 task wire 계약에는 per-spawn 모델 선택기가 없고 모델은 agent 정의에서만
2435
2212
  // 왔다. StructuredSubagentRequest.model → resolveEffectiveSubagentPolicy의
@@ -3296,24 +3073,27 @@ import { resolveUsedFraction } from "../usage";`,
3296
3073
  patched: "import {\n\torderUsageRankedCandidates,\n\tPRIMARY_WINDOW_HOT_FRACTION,\n\tplanPriority,\n",
3297
3074
  },
3298
3075
  {
3299
- // 2026-09-29 사용자 정책: Anthropic 새/cold 재선택은 RIN(저장 순서 0)을 먼저 쓰고, RIN 이 주간 한도의
3300
- // 하루 구간(사용량 패널 paceOf 와 같은 기준: 지난 날 수 + 1 일치)을 넘으면 MIO 로 넘긴다. 날이 바뀌어
3301
- // 허용치가 늘면 다시 RIN 이다. 둘 다 넘었으면 덜 넘은 쪽. 옛 "주간 reset 이 빠른 계정 우선"(2026-09-26)을
3302
- // 대체한다(legacyPatched). 사용량 그림이 완전하고 건강한 후보만, upstream ranking 에서 이미 차지한
3303
- // 자리들 안에서만 재배열한다. unknown·partial·blocked·reserve·plan 부적격·5h hot 후보는 upstream 자리
3304
- // 그대로다. exact summon 은 이 앞에서 return 하고 warm/explicit pin·plan pin 재승격은 이 뒤에 온다.
3305
- // 18.4.5(#13889)는 비ranking 후보 목록 끝을 `}));` 에서 삼항 map 으로 바꾸고 ranking 비교기에 spent
3306
- // allowance 를 reserve 보다 앞에 넣었다. 재배열 대상은 한도 미도달·측정 완료(used<1) 후보뿐이라 spent
3307
- // 후보는 upstream 자리 그대로다. 앵커는 두 버전 모두 한 번 있는 preflightFailures 선언 한 줄이다.
3076
+ // 2026-10-02 사용자 정책: "리셋이 얼마 안 남았는데 한도가 많이 남은 계정을 적극 쓴다". Anthropic 새/cold
3077
+ // 선택에서 오늘 몫(사용량 패널 paceOf 와 같은 기준: (지난 날 수 + 1) / 창 일수) 안쪽 계정끼리는 저장
3078
+ // 순서 대신 7d required drain(남은 비율 ÷ 리셋까지 남은 시간, upstream windowRequiredDrain 그대로)이 큰
3079
+ // 계정을 먼저 쓴다. 몫을 넘은 계정은 몫 안쪽 계정 뒤(페이스 보호), 둘 다 넘었으면 덜 넘은 쪽, 동률은 저장
3080
+ // 순서(위치 0 먼저). 2026-09-29 "몫 안쪽은 RIN(저장 순서 0) 먼저" 적용본을 대체한다(legacyPatched).
3081
+ // 사용량 그림이 완전하고 건강한 후보만, upstream ranking 에서 이미 차지한 자리들 안에서만 재배열한다.
3082
+ // unknown·partial·blocked·reserve·plan 부적격·5h hot 후보는 upstream 자리 그대로다. exact summon 은 이
3083
+ // 앞에서 return 하고 warm/explicit pin·plan pin 재승격은 이 뒤에 온다(warm pin 은 shouldRank=false).
3084
+ // 재배열 대상은 한도 미도달·측정 완료(used<1) 후보뿐이라 18.4.5 spent allowance 후보는 upstream 자리 그대로다.
3085
+ // 앵커는 18.4.4~18.4.6 모두 한 번 있는 preflightFailures 선언 한 줄이다. 검증: core-account-order-test.ts.
3308
3086
  file: "../pi-ai/src/auth/select.ts",
3309
- marker: "// Prefer RIN (first Anthropic account) while it stays inside its daily slice of the weekly quota.",
3087
+ marker: "// Prefer the Anthropic account whose unused weekly quota expires soonest, inside its daily slice.",
3310
3088
  anchor: "\t\tconst preflightFailures = new Set<OAuthCandidate>();",
3311
- legacyPatched: ` // Prefer the healthy Anthropic account whose weekly window resets first.
3089
+ legacyPatched: ` // Prefer RIN (first Anthropic account) while it stays inside its daily slice of the weekly quota.
3312
3090
  // Only candidates with a complete, healthy usage picture move, and only among the slots they
3313
3091
  // already hold in the upstream ranking: unknown, partial, blocked, reserve, plan-ineligible or
3314
- // 5h-hot candidates keep their place. Ties: larger remaining weekly quota, then upstream order.
3092
+ // 5h-hot candidates keep their place. Daily slice = (elapsed whole days + 1) / window days.
3093
+ // Inside the slice: storage order. Over it: smaller overshoot first, then storage order.
3315
3094
  if (provider === "anthropic" && shouldRank && strategy) {
3316
3095
  const nowMs = Date.now();
3096
+ const dayMs = 86_400_000;
3317
3097
  const weekly = candidates.map(candidate => {
3318
3098
  const usage = candidate.usage;
3319
3099
  if (!candidate.usageChecked || !usage || candidate.inReserve === true) return undefined;
@@ -3343,17 +3123,21 @@ import { resolveUsedFraction } from "../usage";`,
3343
3123
  return undefined;
3344
3124
  }
3345
3125
  const resetAt = secondary.window?.resetsAt;
3126
+ const durationMs = secondary.window?.durationMs;
3346
3127
  const used = resolveUsedFraction(secondary);
3347
3128
  if (typeof resetAt !== "number" || !Number.isFinite(resetAt) || resetAt <= nowMs) return undefined;
3129
+ if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < dayMs) return undefined;
3348
3130
  if (typeof used !== "number" || !Number.isFinite(used)) return undefined;
3349
- return { resetAt, remaining: 1 - used };
3131
+ const elapsedMs = Math.min(durationMs, Math.max(0, durationMs - (resetAt - nowMs)));
3132
+ const allowance = Math.min(1, ((Math.floor(elapsedMs / dayMs) + 1) * dayMs) / durationMs);
3133
+ return { overshoot: Math.max(0, used - allowance), index: candidate.selection.index };
3350
3134
  });
3351
3135
  const slots = candidates.flatMap((_candidate, pos) => (weekly[pos] ? [pos] : []));
3352
3136
  const preferred = [...slots]
3353
3137
  .sort((left, right) => {
3354
- const leftWeekly = weekly[left]!;
3355
- const rightWeekly = weekly[right]!;
3356
- return leftWeekly.resetAt - rightWeekly.resetAt || rightWeekly.remaining - leftWeekly.remaining || left - right;
3138
+ const a = weekly[left]!;
3139
+ const b = weekly[right]!;
3140
+ return Number(a.overshoot > 0) - Number(b.overshoot > 0) || a.overshoot - b.overshoot || a.index - b.index;
3357
3141
  })
3358
3142
  .map(pos => candidates[pos]!);
3359
3143
  slots.forEach((pos, order) => {
@@ -3361,11 +3145,12 @@ import { resolveUsedFraction } from "../usage";`,
3361
3145
  });
3362
3146
  }
3363
3147
  const preflightFailures = new Set<OAuthCandidate>();`,
3364
- patched: ` // Prefer RIN (first Anthropic account) while it stays inside its daily slice of the weekly quota.
3148
+ patched: ` // Prefer the Anthropic account whose unused weekly quota expires soonest, inside its daily slice.
3365
3149
  // Only candidates with a complete, healthy usage picture move, and only among the slots they
3366
3150
  // already hold in the upstream ranking: unknown, partial, blocked, reserve, plan-ineligible or
3367
3151
  // 5h-hot candidates keep their place. Daily slice = (elapsed whole days + 1) / window days.
3368
- // Inside the slice: storage order. Over it: smaller overshoot first, then storage order.
3152
+ // Inside the slice: larger weekly required drain (upstream windowRequiredDrain) first.
3153
+ // Over it: after every in-slice account, smaller overshoot first. Ties: storage order.
3369
3154
  if (provider === "anthropic" && shouldRank && strategy) {
3370
3155
  const nowMs = Date.now();
3371
3156
  const dayMs = 86_400_000;
@@ -3405,14 +3190,23 @@ import { resolveUsedFraction } from "../usage";`,
3405
3190
  if (typeof used !== "number" || !Number.isFinite(used)) return undefined;
3406
3191
  const elapsedMs = Math.min(durationMs, Math.max(0, durationMs - (resetAt - nowMs)));
3407
3192
  const allowance = Math.min(1, ((Math.floor(elapsedMs / dayMs) + 1) * dayMs) / durationMs);
3408
- return { overshoot: Math.max(0, used - allowance), index: candidate.selection.index };
3193
+ return {
3194
+ overshoot: Math.max(0, used - allowance),
3195
+ drain: windowRequiredDrain(secondary, nowMs, strategy.windowDefaults.secondaryMs),
3196
+ index: candidate.selection.index,
3197
+ };
3409
3198
  });
3410
3199
  const slots = candidates.flatMap((_candidate, pos) => (weekly[pos] ? [pos] : []));
3411
3200
  const preferred = [...slots]
3412
3201
  .sort((left, right) => {
3413
3202
  const a = weekly[left]!;
3414
3203
  const b = weekly[right]!;
3415
- return Number(a.overshoot > 0) - Number(b.overshoot > 0) || a.overshoot - b.overshoot || a.index - b.index;
3204
+ return (
3205
+ Number(a.overshoot > 0) - Number(b.overshoot > 0) ||
3206
+ a.overshoot - b.overshoot ||
3207
+ (a.overshoot > 0 ? 0 : b.drain - a.drain) ||
3208
+ a.index - b.index
3209
+ );
3416
3210
  })
3417
3211
  .map(pos => candidates[pos]!);
3418
3212
  slots.forEach((pos, order) => {
@@ -3421,6 +3215,64 @@ import { resolveUsedFraction } from "../usage";`,
3421
3215
  }
3422
3216
  const preflightFailures = new Set<OAuthCandidate>();`,
3423
3217
  },
3218
+ // 2026-10-02 사용자 정책: summon marker 없이 띄운 일반 maker child 는 부모 세션의 Anthropic 계정 고정(warm 자동
3219
+ // pin·교체 exact pin 모두)을 물려받지 않고 위 순서 규칙으로 새로 고른다. 실제 경로: task 도구(task/index.ts) →
3220
+ // runStructuredSubagent(structured-subagent.ts: credentialSourceSessionId = 부모 agent.sessionId) → runSubprocess
3221
+ // → createAgentSession(sdk.ts) → authStorage.sessions.inherit. ‘린/미오 호출’ summon child 는 상속 뒤 character-voice
3222
+ // before_agent_start 가 지정 위치 exact pin 을 다시 걸므로 그대로 둔다. 다른 provider·maker 아닌 child 상속은 그대로.
3223
+ // 아래 네 파일 다섯 항목: inherit 의 provider 제외 인자, 그 타입, sdk 옵션·전달, executor 의 maker 판정.
3224
+ // 검증: core-account-order-test.ts [상속].
3225
+ {
3226
+ file: "../pi-ai/src/auth/affinity.ts",
3227
+ marker: "\tinherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number {",
3228
+ anchor: ` inherit(sourceSessionId: string, targetSessionId: string): number {
3229
+ if (!sourceSessionId || !targetSessionId || sourceSessionId === targetSessionId) return 0;
3230
+ let inherited = 0;
3231
+ for (const provider of this.#pool.providers()) {
3232
+ const credential = this.get(provider, sourceSessionId);
3233
+ if (!credential) continue;`,
3234
+ patched: ` inherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number {
3235
+ if (!sourceSessionId || !targetSessionId || sourceSessionId === targetSessionId) return 0;
3236
+ let inherited = 0;
3237
+ for (const provider of this.#pool.providers()) {
3238
+ if (skipProviders?.includes(provider)) continue;
3239
+ const credential = this.get(provider, sourceSessionId);
3240
+ if (!credential) continue;`,
3241
+ },
3242
+ {
3243
+ file: "../pi-ai/src/auth/types.ts",
3244
+ marker: "\tinherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number;",
3245
+ anchor: "\tinherit(sourceSessionId: string, targetSessionId: string): number;",
3246
+ patched: ` /** \`skipProviders\`: providers whose affinity the target must choose fresh instead of copying. */
3247
+ inherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number;`,
3248
+ },
3249
+ {
3250
+ file: "src/sdk.ts",
3251
+ marker: "\tcredentialInheritSkipProviders?: readonly string[];",
3252
+ anchor: "\tcredentialSourceSessionId?: string;\n\n\t/** Model to use. Default: from settings, else first available */",
3253
+ patched: ` credentialSourceSessionId?: string;
3254
+ /** Providers whose {@link credentialSourceSessionId} affinity is not copied; the child selects them fresh. */
3255
+ credentialInheritSkipProviders?: readonly string[];
3256
+
3257
+ /** Model to use. Default: from settings, else first available */`,
3258
+ },
3259
+ {
3260
+ file: "src/sdk.ts",
3261
+ marker: "options.credentialSourceSessionId, providerSessionId, options.credentialInheritSkipProviders);",
3262
+ anchor: "\t\tmodelRegistry.authStorage.sessions.inherit(options.credentialSourceSessionId, providerSessionId);",
3263
+ patched: ` modelRegistry.authStorage.sessions.inherit(
3264
+ options.credentialSourceSessionId, providerSessionId, options.credentialInheritSkipProviders);`,
3265
+ },
3266
+ {
3267
+ file: "src/task/executor.ts",
3268
+ marker: "\t\t\t\tcredentialInheritSkipProviders:",
3269
+ anchor: "\t\t\t\tcredentialSourceSessionId: options.credentialSourceSessionId,\n",
3270
+ patched: ` credentialSourceSessionId: options.credentialSourceSessionId,
3271
+ // A plain maker picks its own Anthropic account; a character summon re-pins its exact one.
3272
+ credentialInheritSkipProviders:
3273
+ agent.name === "maker" && !/\\[character-summon\\s/u.test(task) ? ["anthropic"] : undefined,
3274
+ `,
3275
+ },
3424
3276
  {
3425
3277
  // exact OAuth 가 해석되지 않으면 login API 키·18.4.5 config fallback 키(#13815)·env 키로 조용히 넘어가지 않는다.
3426
3278
  // 18.4.5는 resolveOAuth 성공 분기에 oauthIdentity 전달을 넣어 옛 한 덩어리 앵커가 사라졌다. 라벨은
@@ -8239,11 +8091,14 @@ function parentSubagentServiceTiers(
8239
8091
  // 18.4.10(#14019)은 이 행에 prefixBinding을 넣었지만 binding controls는 false로 남긴다. 18.4.10 후보는 binding controls만 켠다.
8240
8092
  // 그 결과가 18.4.6 적용본과 바이트까지 같으면 두 후보가 함께 applied(ambiguous)이고, 문맥으로도 가를 수 없다(가장 가까운
8241
8093
  // 18.4.6↔18.4.10 차이가 앵커 앞 53K자·뒤 249K자). 그래서 18.4.10 결과만 `": true"` 공백으로 구분한다. JSON.parse는 이 공백을 무시한다.
8094
+ // 18.4.12: 같은 행의 측정값 tps가 95.2→92.9로 바뀌어 18.4.10 앵커가 사라졌다. thinking(prefixBinding true)·compat(binding
8095
+ // controls false)는 18.4.10과 같으므로 본 후보는 18.4.10 후보에서 tps만 바꾼다. 두 판 결과는 tps 뒤가 같아 예전 marker(tps
8096
+ // 뒤 조각)로는 둘 다 applied(ambiguous)가 되므로, 18.4.12·18.4.10 후보 모두 tps를 포함한 patched 전체를 marker로 쓴다.
8242
8097
  file: "../pi-catalog/src/models.json",
8243
- marker: OPUS55_ROW_1846.marker.replace('"supportsThinkingBindingControls":true', '"supportsThinkingBindingControls": true'),
8244
- anchor: OPUS55_ROW_1846.anchor.replace('"supportsDisplay":true}', '"supportsDisplay":true,"prefixBinding":true}'),
8245
- patched: OPUS55_ROW_1846.patched.replace('"supportsThinkingBindingControls":true', '"supportsThinkingBindingControls": true'),
8246
- alternates: [OPUS55_ROW_1846],
8098
+ marker: OPUS55_ROW_18410.patched.replace(OPUS55_TPS_18410, OPUS55_TPS_18412),
8099
+ anchor: OPUS55_ROW_18410.anchor.replace(OPUS55_TPS_18410, OPUS55_TPS_18412),
8100
+ patched: OPUS55_ROW_18410.patched.replace(OPUS55_TPS_18410, OPUS55_TPS_18412),
8101
+ alternates: [OPUS55_ROW_18410, OPUS55_ROW_1846],
8247
8102
  },
8248
8103
  {
8249
8104
  // 모든 provider의 Opus 5.5 규칙 계보에 prefixBinding(Sonnet 5.5 규칙과 같은 모양). 18.4.10은 upstream #14019가 kdl:61에
@@ -8909,7 +8764,6 @@ for (const entry of EDITS) {
8909
8764
  }
8910
8765
 
8911
8766
 
8912
-
8913
8767
  /**
8914
8768
  * 항목 하나를 이 설치에서 성립하는 후보로 좁힌다. 후보는 항목 자신과 `alternates` 이고 각 후보는
8915
8769
  * file·anchor·marker·patched 묶음이다. upstream 이 그 조각을 다른 모듈이나 다른 패키지로 옮기면