cuelo 0.7.2 → 0.8.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 (179) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +11 -10
  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 +1 -1
  7. package/.next/required-server-files.json +1 -1
  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 +11 -10
  133. package/.next/server/chunks/205.js +3 -2
  134. package/.next/server/chunks/58.js +353 -0
  135. package/.next/server/chunks/6429.js +1 -1
  136. package/.next/server/chunks/7362.js +1 -0
  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/chunks/1937.8900983e70e8e9dc.js +1 -0
  143. package/.next/static/chunks/{3308.34ea31e24088c85f.js → 3308.8b94b38809d1b8b6.js} +1 -1
  144. package/.next/static/chunks/4857.cb0735ea310a39f0.js +1 -0
  145. package/.next/static/chunks/52733464.85a1551044fef357.js +1 -0
  146. package/.next/static/chunks/6110-681afd060dde5270.js +1 -0
  147. package/.next/static/chunks/9304.1f940d490ea5c972.js +1 -0
  148. package/.next/static/chunks/app/{layout-fc24ec6959a6cba5.js → layout-6aa3580989aedade.js} +1 -1
  149. package/.next/static/chunks/app/office-preview/page-2151040877dfb7cd.js +1 -0
  150. package/.next/static/chunks/app/page-f6f024bab16a7232.js +22 -0
  151. package/.next/static/chunks/b536a0f1.f7e390612229faa9.js +342 -0
  152. package/.next/static/chunks/bd904a5c.b74776e0b23d0607.js +1 -0
  153. package/.next/static/chunks/f5ef5e1c.14b6095722ff4f0b.js +12 -0
  154. package/.next/static/chunks/{framework-32a7466d5cae4a81.js → framework-e405bc515d75023a.js} +1 -1
  155. package/.next/static/chunks/webpack-93d544f82f48c3fd.js +1 -0
  156. package/.next/static/css/{88929dd0c6d44c84.css → 67b6e19482963224.css} +1 -1
  157. package/.next/static/css/829f44afcc3302e9.css +1 -0
  158. package/.next/static/css/{27f16a2ddaff39eb.css → abd3d00cca9457f7.css} +1 -1
  159. package/.next/static/vaxcaBF-y6afdFHIrgeuN/_buildManifest.js +1 -0
  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 +5 -3
  166. package/Tools/CUELO_Setup/files/native-runtime-patch.js +1 -1
  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 +95 -20
  171. package/install.mjs +6 -2
  172. package/package.json +4 -1
  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 → vaxcaBF-y6afdFHIrgeuN}/_ssgManifest.js +0 -0
package/.next/trace-build CHANGED
@@ -1 +1 @@
1
- [{"name":"run-webpack","duration":109593202,"timestamp":693851,"id":14,"parentId":1,"tags":{},"startTime":1790912309866,"traceId":"bd3cc60982244299"},{"name":"run-typescript","duration":18656625,"timestamp":110669851,"id":10803,"parentId":1,"tags":{},"startTime":1790912419841,"traceId":"bd3cc60982244299"},{"name":"static-check","duration":4168164,"timestamp":129419055,"id":10806,"parentId":1,"tags":{},"startTime":1790912438590,"traceId":"bd3cc60982244299"},{"name":"static-generation","duration":12708493,"timestamp":133691018,"id":10962,"parentId":1,"tags":{},"startTime":1790912442862,"traceId":"bd3cc60982244299"},{"name":"collect-build-traces","duration":21946836,"timestamp":133655230,"id":10959,"parentId":1,"tags":{},"startTime":1790912442826,"traceId":"bd3cc60982244299"},{"name":"telemetry-flush","duration":83,"timestamp":155607140,"id":10971,"parentId":1,"tags":{},"startTime":1790912464778,"traceId":"bd3cc60982244299"},{"name":"next-build","duration":155023395,"timestamp":583851,"id":1,"tags":{"buildMode":"default","version":"16.2.12","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1790912309756,"traceId":"bd3cc60982244299"}]
1
+ [{"name":"run-webpack","duration":90341981,"timestamp":661584,"id":14,"parentId":1,"tags":{},"startTime":1790960874577,"traceId":"cb2ef4bd7b412ca5"},{"name":"run-typescript","duration":15201345,"timestamp":91359936,"id":10890,"parentId":1,"tags":{},"startTime":1790960965274,"traceId":"cb2ef4bd7b412ca5"},{"name":"static-check","duration":3555988,"timestamp":106648200,"id":10893,"parentId":1,"tags":{},"startTime":1790960980562,"traceId":"cb2ef4bd7b412ca5"},{"name":"static-generation","duration":11521023,"timestamp":110305130,"id":11051,"parentId":1,"tags":{},"startTime":1790960984219,"traceId":"cb2ef4bd7b412ca5"},{"name":"collect-build-traces","duration":18847169,"timestamp":110276578,"id":11048,"parentId":1,"tags":{},"startTime":1790960984190,"traceId":"cb2ef4bd7b412ca5"},{"name":"telemetry-flush","duration":67,"timestamp":129128008,"id":11060,"parentId":1,"tags":{},"startTime":1790961003041,"traceId":"cb2ef4bd7b412ca5"},{"name":"next-build","duration":128558082,"timestamp":570017,"id":1,"tags":{"buildMode":"default","version":"16.2.12","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1790960874486,"traceId":"cb2ef4bd7b412ca5"}]
@@ -0,0 +1,87 @@
1
+ // File: D:\a\CUELO\CUELO\app\office-preview\page.tsx
2
+ import * as entry from '../../../../app/office-preview/page.js'
3
+ import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
4
+
5
+ import type { InstantConfigForTypeCheckInternal } from 'next/dist/build/segment-config/app/app-segment-config.js'
6
+
7
+ type TEntry = typeof import('../../../../app/office-preview/page.js')
8
+
9
+ type SegmentParams<T extends Object = any> = T extends Record<string, any>
10
+ ? { [K in keyof T]: T[K] extends string ? string | string[] | undefined : never }
11
+ : T
12
+
13
+ // Check that the entry is a valid entry
14
+ checkFields<Diff<{
15
+ default: Function
16
+ config?: {}
17
+ generateStaticParams?: Function
18
+ unstable_instant?: InstantConfigForTypeCheckInternal
19
+ unstable_dynamicStaleTime?: number
20
+ revalidate?: RevalidateRange<TEntry> | false
21
+ dynamic?: 'auto' | 'force-dynamic' | 'error' | 'force-static'
22
+ dynamicParams?: boolean
23
+ fetchCache?: 'auto' | 'force-no-store' | 'only-no-store' | 'default-no-store' | 'default-cache' | 'only-cache' | 'force-cache'
24
+ preferredRegion?: 'auto' | 'global' | 'home' | string | string[]
25
+ runtime?: 'nodejs' | 'experimental-edge' | 'edge'
26
+ maxDuration?: number
27
+
28
+ metadata?: any
29
+ generateMetadata?: Function
30
+ viewport?: any
31
+ generateViewport?: Function
32
+
33
+ }, TEntry, ''>>()
34
+
35
+
36
+ // Check the prop type of the entry function
37
+ checkFields<Diff<PageProps, FirstArg<TEntry['default']>, 'default'>>()
38
+
39
+ // Check the arguments and return type of the generateMetadata function
40
+ if ('generateMetadata' in entry) {
41
+ checkFields<Diff<PageProps, FirstArg<MaybeField<TEntry, 'generateMetadata'>>, 'generateMetadata'>>()
42
+ checkFields<Diff<ResolvingMetadata, SecondArg<MaybeField<TEntry, 'generateMetadata'>>, 'generateMetadata'>>()
43
+ }
44
+
45
+ // Check the arguments and return type of the generateViewport function
46
+ if ('generateViewport' in entry) {
47
+ checkFields<Diff<PageProps, FirstArg<MaybeField<TEntry, 'generateViewport'>>, 'generateViewport'>>()
48
+ checkFields<Diff<ResolvingViewport, SecondArg<MaybeField<TEntry, 'generateViewport'>>, 'generateViewport'>>()
49
+ }
50
+
51
+ // Check the arguments and return type of the generateStaticParams function
52
+ if ('generateStaticParams' in entry) {
53
+ checkFields<Diff<{ params: SegmentParams }, FirstArg<MaybeField<TEntry, 'generateStaticParams'>>, 'generateStaticParams'>>()
54
+ checkFields<Diff<{ __tag__: 'generateStaticParams', __return_type__: any[] | Promise<any[]> }, { __tag__: 'generateStaticParams', __return_type__: ReturnType<MaybeField<TEntry, 'generateStaticParams'>> }>>()
55
+ }
56
+
57
+ export interface PageProps {
58
+ params?: Promise<SegmentParams>
59
+ searchParams?: Promise<any>
60
+ }
61
+ export interface LayoutProps {
62
+ children?: React.ReactNode
63
+
64
+ params?: Promise<SegmentParams>
65
+ }
66
+
67
+ // =============
68
+ // Utility types
69
+ type RevalidateRange<T> = T extends { revalidate: any } ? NonNegative<T['revalidate']> : never
70
+
71
+ // If T is unknown or any, it will be an empty {} type. Otherwise, it will be the same as Omit<T, keyof Base>.
72
+ type OmitWithTag<T, K extends keyof any, _M> = Omit<T, K>
73
+ type Diff<Base, T extends Base, Message extends string = ''> = 0 extends (1 & T) ? {} : OmitWithTag<T, keyof Base, Message>
74
+
75
+ type FirstArg<T extends Function> = T extends (...args: [infer T, any]) => any ? unknown extends T ? any : T : never
76
+ type SecondArg<T extends Function> = T extends (...args: [any, infer T]) => any ? unknown extends T ? any : T : never
77
+ type MaybeField<T, K extends string> = T extends { [k in K]: infer G } ? G extends Function ? G : never : never
78
+
79
+
80
+
81
+ function checkFields<_ extends { [k in keyof any]: never }>() {}
82
+
83
+ // https://github.com/sindresorhus/type-fest
84
+ type Numeric = number | bigint
85
+ type Zero = 0 | 0n
86
+ type Negative<T extends Numeric> = T extends Zero ? never : `${T}` extends `-${string}` ? T : never
87
+ type NonNegative<T extends Numeric> = T extends Zero ? T : Negative<T> extends never ? T : '__invalid_negative_number__'
@@ -1,7 +1,7 @@
1
1
  // This file is generated automatically by Next.js
2
2
  // Do not edit this file manually
3
3
 
4
- type AppRoutes = "/" | "/recover"
4
+ type AppRoutes = "/" | "/office-preview" | "/recover"
5
5
  type AppRouteHandlerRoutes = "/api/agent/[id]" | "/api/agent/[id]/account" | "/api/agent/[id]/bash-output" | "/api/agent/[id]/events" | "/api/agent/new" | "/api/agent/running" | "/api/attachments" | "/api/auth/all-providers" | "/api/auth/api-key/[provider]" | "/api/auth/login/[provider]" | "/api/auth/logout/[provider]" | "/api/auth/providers" | "/api/cwd/browse" | "/api/cwd/validate" | "/api/default-cwd" | "/api/display-settings" | "/api/document-text" | "/api/experiments" | "/api/file-index" | "/api/files/[...path]" | "/api/git/diff" | "/api/git/status" | "/api/gpt6/handles" | "/api/gpt6/reply" | "/api/gpt6/token" | "/api/gpt6/web6-session" | "/api/home" | "/api/live/call/[callId]" | "/api/live/character-voice" | "/api/live/events" | "/api/live/offer" | "/api/live/voices" | "/api/lounge" | "/api/lounge/events" | "/api/mcp" | "/api/model-roles" | "/api/models" | "/api/models-config" | "/api/models-config/catalog" | "/api/models-config/discover" | "/api/models-config/test" | "/api/plugins" | "/api/project-trust" | "/api/projects" | "/api/runs" | "/api/runs/[runId]" | "/api/sessions" | "/api/sessions/[id]" | "/api/sessions/[id]/auto-name" | "/api/sessions/[id]/context" | "/api/sessions/[id]/entries/[entryId]/thinking" | "/api/sessions/[id]/export" | "/api/sessions/[id]/state" | "/api/sessions/search" | "/api/settings" | "/api/sidecars/[service]/[...path]" | "/api/skills" | "/api/skills/check" | "/api/skills/install" | "/api/skills/search" | "/api/skills/update" | "/api/theme" | "/api/tool-image" | "/api/update-maintenance" | "/api/updates" | "/api/web-access" | "/api/web-access/recovery" | "/api/web6/consults" | "/api/worktrees"
6
6
  type PageRoutes = never
7
7
  type LayoutRoutes = "/"
@@ -81,6 +81,7 @@ interface ParamMap {
81
81
  "/api/web-access/recovery": {}
82
82
  "/api/web6/consults": {}
83
83
  "/api/worktrees": {}
84
+ "/office-preview": {}
84
85
  "/recover": {}
85
86
  }
86
87
 
@@ -47,6 +47,15 @@ type RouteHandlerConfig<Route extends AppRouteHandlerRoutes = AppRouteHandlerRou
47
47
  }
48
48
 
49
49
 
50
+ // Validate ../../app/office-preview/page.tsx
51
+ {
52
+ type __IsExpected<Specific extends AppPageConfig<"/office-preview">> = Specific
53
+ const handler = {} as typeof import("../../app/office-preview/page.js")
54
+ type __Check = __IsExpected<typeof handler>
55
+ // @ts-ignore
56
+ type __Unused = __Check
57
+ }
58
+
50
59
  // Validate ../../app/page.tsx
51
60
  {
52
61
  type __IsExpected<Specific extends AppPageConfig<"/">> = Specific
package/README.md CHANGED
@@ -45,7 +45,7 @@ CUELO의 목적은 작업 중 확인한 실패와 막힘을 기억·작업 규
45
45
  - 입력창에 이미지·문서 외에 음성(받아쓰기), 코드·설정 파일(본문 첨부), 그 밖의 파일(저장 후 경로 첨부)을 붙여넣기·드롭·선택으로 넣습니다. 음성 받아쓰기에는 Google Antigravity 계정이 필요합니다.
46
46
  - 에이전트가 생성하거나 확인한 이미지가 그 턴의 대화 흐름에 썸네일로 보이고, 누르면 크게 열립니다.
47
47
  - Ctrl+K 팔레트로 대화 내용을 검색해 해당 메시지로 이동합니다. 압축으로 사라진 과거 메시지는 제외하고, 현재 볼 수 있는 메시지를 세션당 최대 3건 보여 줍니다. 긴 대화 안에서는 Ctrl+F로 찾고, 오른쪽 질문 레일로 내가 한 질문 사이를 오갑니다.
48
- - 실행이 3분 넘게 조용하면 멈춤 경고를, 서버나 PC가 꺼져 실행이 끊긴 대화를 열면 중단 알림을 보여 줍니다. 컨텍스트 압축 중에는 경과 시간을 표시합니다.
48
+ - 서버나 PC가 꺼져 실행이 끊긴 대화를 열면 중단 알림을 보여 줍니다. 컨텍스트 압축 중에는 경과 시간을 표시합니다.
49
49
  - 모델 선택기 맨 위에 자주 고른 모델이 나오고, 팔레트에서 넓은 대화 폭을 켤 수 있습니다.
50
50
  - 입력창 아래 줄은 Main 프리셋 → 그 제공자의 모델 → 추론 강도 순서입니다. "자동, 최대 high"처럼 상한을 고를 수 있고, Auto가 실제로 적용한 값은 「현재 추론 강도」로 따로 표시합니다. 새 대화는 선택한 상한 적용을 마친 뒤 첫 메시지를 보내며, 적용에 실패하면 재전송 때 다시 시도합니다.
51
51
  - 도구 옆 시간에는 모델 응답 생성 시간을 포함하지 않습니다. 실행 전에 취소된 도구나 완료 시각을 확인할 수 없는 옛 기록에는 시간을 추정해 붙이지 않습니다.
@@ -62,7 +62,7 @@ CUELO의 목적은 작업 중 확인한 실패와 막힘을 기억·작업 규
62
62
  - 서브에이전트를 발주한 답변 안에 접힌 카드가 붙어, 맡긴 일마다 실행 상태와 Main의 검수 판정을 한 줄로 보여 줍니다. 펼치면 현재 단계·모델·판정 사유와 상세 패널 링크가 나옵니다. 실행이 끝났어도 Main이 판정을 남기지 않았으면 「검수 미기록」으로 표시하며, 끝난 것을 통과로 치지 않습니다.
63
63
  - 끝난 턴의 마지막 답변 아래에 변경 파일·검사·실패·미확인 개수를 한 줄로 요약하고, 펼치면 파일과 검사 명령·결과를 봅니다.
64
64
  - 실행 중에 보낸 입력은 「지금 지시」와 「완료 후 요청」으로 나뉘어, 접수·전달 대기·대화에 들어감 단계를 따로 보여 줍니다. 전달을 확인하지 못하면 그렇다고 표시합니다.
65
- - 오피스 보기: 대화 보기와 전환하는 선택형 화면입니다. 왼쪽 자리에서 Main과 실제 참여한 에이전트의 상태를 보고, 고른 대상의 대화·작업 기록·파일을 오른쪽에서 확인합니다. 고르기만 해서는 모델·계정이 바뀌거나 메시지가 다른 대상으로 가지 않으며, 대화 보기로 돌아가도 작성 중인 초안이 그대로 남습니다.
65
+ - 오피스 보기: 대화 보기와 전환하는 3D 사무실 화면입니다. Main과 참여한 Maker가 각자 캐릭터로 자리에 앉아 실제 실행 상태대로 일하거나 책상 곁에서 기다리고, 실행이 끝나면 쉬는 자리로 돌아갑니다. 실행 완료는 Main의 수용으로 표시하지 않습니다. 이 세션에 참여하지 않은 캐릭터는 휴게 구역에서 쉬며 「참여 안 함」으로 표시됩니다. 참여자 캐릭터나 머리 위 말풍선, 아래 참여자 줄을 누르면 오른쪽에 그 대상의 대화나 작업 기록·파일이 열립니다. Maker 기록은 조회 전용이고 입력은 늘 Main에게 갑니다. 고르기만 해서는 모델·계정이 바뀌거나 메시지가 다른 대상으로 가지 않으며, 대화 보기로 돌아가도 작성 중인 초안이 그대로 남습니다. WebGL을 쓸 수 없거나 장면을 받지 못하면 자리 카드로 보여 주고 다시 시도할 수 있습니다. 캐릭터와 방은 내려받은 자산 없이 코드로 그립니다([`public/office3d/ASSETS.md`](./public/office3d/ASSETS.md)).
66
66
  - 자식 에이전트의 발화가 해당 턴 아래 대화 흐름에 끼어들어 누가 무슨 말을 했는지 이어서 읽힙니다.
67
67
  - 공개 하네스는 시작을 기다리거나 재작업 중인 에이전트에게 같은 파일을 중복 배정하지 않도록 확인합니다. 완료 결과와 Main이 검수한 결과의 출처를 구분하고, 재작업 이력과 최종 수용을 따로 남깁니다. 적용 경계는 [하네스 안내](./docs/harness.md#발주와-검수-계약)를 따릅니다.
68
68
  - 필요한 MCP 서버만 요청별로 연결하는 선택 모드를 지원합니다. 설치·인증·권한 변경은 먼저 승인을 받고 에이전트가 지원합니다. 설정과 적용 범위는 [요청별 MCP 선택 연결](./docs/harness.md#요청별-mcp-선택-연결)을 확인하세요.
@@ -194,7 +194,9 @@ bun run test:coverage # 앱·설치기 테스트 + 커버리지 표
194
194
 
195
195
  개발 서버를 쓰는 동안 같은 출력 경로에 `bun run build`를 돌리지 마세요. `.next/`를 덮어써서 개발 서버가 깨집니다. 검증용 production 빌드는 별도 소스 복사본이나 격리된 `CUELO_DIST_DIR`에서 실행하세요.
196
196
 
197
- 의존성을 다시 설치하거나 갱신한 뒤에는 `bun run prepare:source`를 다시 실행하세요. 이 준비 단계는 작업 사본의 SDK만 다루며 사용자 프로필이나 실행 중인 설치본을 변경하지 않습니다.
197
+ 의존성을 다시 설치하거나 갱신한 뒤에는 `bun run prepare:source`를 다시 실행하세요. 이미 설치된 작업 사본에서도 `bun install`은 패치된 SDK 패키지를 원본으로 다시 깔기 때문에, 준비 단계를 빼면 호환 패치가 빠진 채로 실행됩니다. 이 준비 단계는 작업 사본의 SDK만 다루며 사용자 프로필이나 실행 중인 설치본을 변경하지 않습니다.
198
+
199
+ 3D 오피스 장면만 고칠 때는 `bun run dev:verify`로 띄운 뒤 `http://127.0.0.1:30163/office-preview`를 여세요. 실제 장면 코드에 고정된 상태(대기·작업·주의·여러 참여자 등)와 화면 폭을 골라 넣는 개발 전용 화면이며, 세션이나 계정을 만들지 않습니다. production 빌드에서는 이 경로가 열리지 않습니다. 실제 상태 연결과 대화 전환·초안 보존은 전체 앱에서 확인하세요.
198
200
 
199
201
  참고 문서: [OMP 하네스](./docs/harness.md) · [인증](./docs/authentication.md) · [프로젝트 신뢰](./docs/project-trust.md) · [worktree](./docs/worktrees.md) · [다국어](./docs/i18n.md) · [Docker](./docs/docker.md)
200
202
 
@@ -9,7 +9,7 @@ const MEMORY_RE = /(const phase1Model = await resolveMemoryModel\(\{[^}]*?fallba
9
9
  const MEMORY_DONE = /const phase1Model = await resolveMemoryModel\(\{[^}]*?fallbackRole: "smol"/;
10
10
  const EXPECTED = {
11
11
  name: 'cuelo',
12
- version: '0.7.2',
12
+ version: '0.8.0',
13
13
  distribution: 'cuelo',
14
14
  coreVersion: '18.4.10',
15
15
  };
@@ -314,8 +314,8 @@ async function switchCharacterForSession(
314
314
  try {
315
315
  const switched = await pi.setModel(model);
316
316
  if (!switched) throw new Error(`${target.model} 인증을 사용할 수 없습니다.`);
317
- // 교체와 summon 모두 exact pin이다. 일반 explicit pin은 다음 요청의 계정 랭킹(RIN 우선·하루
318
- // 구간 초과 시 MIO)이 다른 계정으로 되돌릴 수 있어 교체 완료 보고와 실제 계정이 어긋났다.
317
+ // 교체와 summon 모두 exact pin이다. 일반 explicit pin은 다음 요청의 계정 랭킹(오늘 몫 안에서 리셋 임박·
318
+ // 잔량 많은 계정 우선)이 다른 계정으로 되돌릴 수 있어 교체 완료 보고와 실제 계정이 어긋났다.
319
319
  // exact pin은 sessions.release로 풀 수 없으므로 뒤에 실패할 단계가 없도록 마지막에 건다.
320
320
  if (
321
321
  targetCredentialId !== undefined &&
@@ -85,6 +85,8 @@ export interface RoutingDeps {
85
85
  candidates?: (ctx: ExtensionContext, policy: RoutingPolicy) => Promise<Candidate[]>;
86
86
  /** 후보 provider별 계정 잔량. 생략하면 CUELO usage 사이드카(`OMP_USAGE_PORT`, 기본 30142)를 읽는다. */
87
87
  quota?: (providers: string[], signal?: AbortSignal) => Promise<QuotaSnapshot>;
88
+ /** 준비 단계 진단용 단조 시계(ms). 생략하면 performance.now. */
89
+ clock?: () => number;
88
90
  /** 발주 이력. 생략하면 기록·history 요약을 하지 않는다. 실패는 발주를 막지 않는다. */
89
91
  ledger?: RoutingLedger;
90
92
  }
@@ -730,11 +732,19 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
730
732
  throw new Error("같은 task 계약에 더 최신 facts 준비가 있어 이전 라우팅 판단은 폐기되었습니다.");
731
733
  }
732
734
  };
735
+ const clock = deps.clock ?? (() => performance.now());
736
+ const startedAt = clock();
737
+ const elapsed = (from: number, to: number) => Math.max(0, Math.round(to - from));
738
+ // 고정 필드 진단. 숫자만 담으며 task 수와 무관하다. jevStarted는 이 호출이 실제로 시작한 judge 요청 수이고,
739
+ // 분류별 건수와 합산해 해석하지 않는다(한 요청이 decision·placement를 함께 판단할 수 있다).
740
+ const counts = { jevStarted: 0, decisionNew: 0, decisionReused: 0, placementNew: 0, placementReused: 0 };
733
741
  let quotaAbort: AbortController | undefined;
734
742
  try {
735
743
  const ownersByTask = contracts.map((contract) => relevantOwners(contract, allOwners));
736
744
  const refreshAttempts: RefreshAttempts = new Map();
745
+ const candidatesStartedAt = clock();
737
746
  const { available: candidates, unavailable: unavailableCandidates } = await candidateSet(ctx, current, refreshAttempts);
747
+ const candidatesDoneAt = clock();
738
748
  requireLatest();
739
749
  // 잔량은 시각마다 바뀌므로 revision·identity·Jev state 밖의 참고 정보로만 붙인다.
740
750
  // Jev 판단과 함께 시작하고, 이번 계정 잔량 조회가 끝난 뒤 배정 결과를 반환한다.
@@ -760,6 +770,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
760
770
  reason: error instanceof Error ? error.message : String(error),
761
771
  });
762
772
  }
773
+ const judgeStartedAt = clock();
763
774
  const publications = await Promise.all(tasks.map(async (task, index) => {
764
775
  const contract = contracts[index]!;
765
776
  const owners = ownersByTask[index]!;
@@ -773,8 +784,14 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
773
784
  let decisionPending = decisionCache.get(decisionKey);
774
785
  let placementPending = placementCache.get(placementKey);
775
786
 
787
+ // 소유자가 없으면 placement 판단 자체가 없으므로 어느 쪽으로도 세지 않는다. 새 decision 판단은 placement를 함께 덮어쓴다.
788
+ if (decisionPending) counts.decisionReused += 1;
789
+ if (decisionPending && placementPending && owners.length > 0) counts.placementReused += 1;
776
790
  if (!decisionPending) {
777
791
  const fullQuestions = { ...baseQuestions, ...ownerQuestions };
792
+ counts.jevStarted += 1;
793
+ counts.decisionNew += 1;
794
+ if (owners.length > 0) counts.placementNew += 1;
778
795
  const fullPending = judge(ctx, routingState(task.assessment, owners), fullQuestions, signal);
779
796
  decisionPending = cacheJudgment(
780
797
  decisionCache,
@@ -795,6 +812,8 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
795
812
  );
796
813
  }
797
814
  } else if (!placementPending && owners.length > 0) {
815
+ counts.jevStarted += 1;
816
+ counts.placementNew += 1;
798
817
  placementPending = cacheJudgment(
799
818
  placementCache,
800
819
  placementKey,
@@ -841,7 +860,9 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
841
860
  },
842
861
  };
843
862
  }));
863
+ const quotaWaitStartedAt = clock();
844
864
  const quota = await quotaPending;
865
+ const quotaDoneAt = clock();
845
866
  requireLatest();
846
867
  const allocation = normalAllocation(current, candidates, quota);
847
868
  // 이력은 advisory다. revision·identity·Jev state 밖에 두며 읽기 실패는 빈 이력이다.
@@ -870,7 +891,15 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
870
891
  const name = tasks[index]!.name.trim();
871
892
  preparedContracts.set(name, [...(preparedContracts.get(name) ?? []), contracts[index]!]);
872
893
  });
894
+ const diagnostics = {
895
+ totalMs: elapsed(startedAt, quotaDoneAt),
896
+ candidatesMs: elapsed(candidatesStartedAt, candidatesDoneAt),
897
+ judgeWaitMs: elapsed(judgeStartedAt, quotaWaitStartedAt),
898
+ quotaExtraWaitMs: elapsed(quotaWaitStartedAt, quotaDoneAt),
899
+ ...counts,
900
+ };
873
901
  return {
902
+ diagnostics,
874
903
  candidates,
875
904
  unavailableCandidates,
876
905
  quota,
@@ -1127,7 +1156,9 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
1127
1156
  const request = params as { context: string; tasks: RouteTask[] };
1128
1157
  const batch = await prepareBatch(request.context, request.tasks, ctx, signal, String(callId ?? ""));
1129
1158
  // 준비 handle(plan)은 발주 identity가 아니므로(routing_verdict는 spawn identity) 모델 문맥에는 싣지 않고 details에만 둔다.
1130
- const view = { ...batch, routes: batch.routes.map(({ plan: _plan, ...route }) => route) };
1159
+ // 준비 진단(diagnostics)도 details 전용이다. 모델 문맥에는 싣지 않는다.
1160
+ const { diagnostics: _diagnostics, ...shared } = batch;
1161
+ const view = { ...shared, routes: batch.routes.map(({ plan: _plan, ...route }) => route) };
1131
1162
  return { content: [{ type: "text", text: JSON.stringify(view) }], details: batch };
1132
1163
  },
1133
1164
  });
@@ -1,6 +1,6 @@
1
1
  import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent";
2
2
  import { createHash } from "node:crypto";
3
- import { mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
3
+ import { access, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
4
4
  import { tmpdir } from "node:os";
5
5
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
@@ -28,6 +28,41 @@ const manifestInstructions = `From cwd Tools/CUELO_Setup, run:
28
28
  node files/source-build-helper.js create-manifest ../.. files/runtime-integrity.json --output files/source-integrity.json
29
29
  node files/source-build-helper.js verify-source ../.. files/source-integrity.json files/runtime-integrity.json
30
30
  Then include Tools/CUELO_Setup/files/source-integrity.json in the same commit.`;
31
+ const memorySyncScript = "Tools/OMP_Global_Config/memory-sync/sync.ts";
32
+ const memoryTransport = "Tools/OMP_Global_Config/memory-sync/memories.jsonl";
33
+
34
+ type Exec = (command: string, args: string[], options: { cwd: string }) => Promise<{ code: number; stdout: string; stderr?: string }>;
35
+
36
+ /**
37
+ * 기억 PC 간 동기화의 export를 커밋 경로에 붙인다. 원래 hook은 손으로 돌리는 export.ps1 끝뿐이라
38
+ * 평소 커밋·배포로는 한 번도 내보내지지 않았다(2026-10-02). 같은 저장소 커밋이면 먼저 export하고,
39
+ * 바뀐 transport 파일을 커밋 목록에 더한다. 실패는 커밋을 막지 않고 결과 문구로 알린다.
40
+ */
41
+ async function exportMemories(cwd: string, files: string[], exec: Exec): Promise<{ file?: string; note?: string }> {
42
+ const top = await exec("git", ["-C", cwd, "rev-parse", "--show-toplevel"], { cwd });
43
+ if (top.code !== 0) return {};
44
+ const root = resolve(top.stdout.trim());
45
+ try {
46
+ await access(join(root, ...memorySyncScript.split("/")));
47
+ } catch {
48
+ return {};
49
+ }
50
+ const inRoot = (path: string) => {
51
+ const rel = relative(root, resolve(cwd, path));
52
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
53
+ };
54
+ if (!files.every(inRoot)) return {};
55
+ const transport = relative(cwd, join(root, ...memoryTransport.split("/"))).split(sep).join("/");
56
+ if (transport.startsWith("../")) return { note: "기억 export 생략: 현재 cwd 밖의 파일이라 이 커밋에 넣을 수 없다." };
57
+ if (files.some((file) => file.replace(/\\/g, "/").toLowerCase() === transport.toLowerCase())) return {};
58
+ const exported = await exec("bun", [join(root, ...memorySyncScript.split("/")), "export", root], { cwd: root });
59
+ if (exported.code !== 0) {
60
+ const reason = (exported.stderr || exported.stdout).trim().split(/\r?\n/).at(-1) || `exit ${exported.code}`;
61
+ return { note: `기억 export 실패(커밋은 진행): ${reason}` };
62
+ }
63
+ const status = await exec("git", ["-C", root, "status", "--porcelain", "--", memoryTransport], { cwd: root });
64
+ return status.code === 0 && status.stdout.trim() ? { file: transport } : {};
65
+ }
31
66
 
32
67
  function isSourcePath(path: string, packagedTools: string[]): boolean {
33
68
  if (path.split("/").some((segment) => generatedSourceSegments[segment] || segment.endsWith(".tsbuildinfo"))) return false;
@@ -137,13 +172,16 @@ const factory: CustomToolFactory = (pi) => ({
137
172
  }),
138
173
 
139
174
  async execute(_toolCallId, params, onUpdate, _ctx, signal) {
140
- const files = params.files.map((value) => value.trim()).filter(Boolean);
175
+ const requested = params.files.map((value) => value.trim()).filter(Boolean);
141
176
  const message = params.message.trim();
142
- if (files.length === 0) throw new Error("git_finalize requires at least one exact file path.");
177
+ if (requested.length === 0) throw new Error("git_finalize requires at least one exact file path.");
143
178
  if (!message) throw new Error("git_finalize requires a non-empty commit message.");
144
179
  if (process.platform !== "win32") throw new Error("git_finalize currently requires Windows PowerShell.");
145
180
 
146
- await checkSourceManifest(pi.cwd, files, (command, args, options) => pi.exec(command, args, { ...options, signal }));
181
+ const exec: Exec = (command, args, options) => pi.exec(command, args, { ...options, signal });
182
+ await checkSourceManifest(pi.cwd, requested, exec);
183
+ const memory = await exportMemories(pi.cwd, requested, exec);
184
+ const files = memory.file ? [...requested, memory.file] : requested;
147
185
 
148
186
  onUpdate?.({
149
187
  content: [{ type: "text", text: "Repository finalizer lock을 획득하고 변경 경계를 확인하는 중입니다." }],
@@ -168,7 +206,9 @@ const factory: CustomToolFactory = (pi) => ({
168
206
  content: [
169
207
  {
170
208
  type: "text",
171
- text: `Committed and pushed ${parsed.commitSha} to ${parsed.remote} ${parsed.upstreamRef}.`,
209
+ text: `Committed and pushed ${parsed.commitSha} to ${parsed.remote} ${parsed.upstreamRef}.`
210
+ + (memory.file ? ` 기억 transport(${memory.file})를 함께 커밋했다.` : "")
211
+ + (memory.note ? ` ${memory.note}` : ""),
172
212
  },
173
213
  ],
174
214
  details: parsed,
@@ -3296,24 +3296,27 @@ import { resolveUsedFraction } from "../usage";`,
3296
3296
  patched: "import {\n\torderUsageRankedCandidates,\n\tPRIMARY_WINDOW_HOT_FRACTION,\n\tplanPriority,\n",
3297
3297
  },
3298
3298
  {
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 선언 한 줄이다.
3299
+ // 2026-10-02 사용자 정책: "리셋이 얼마 안 남았는데 한도가 많이 남은 계정을 적극 쓴다". Anthropic 새/cold
3300
+ // 선택에서 오늘 몫(사용량 패널 paceOf 와 같은 기준: (지난 날 수 + 1) / 창 일수) 안쪽 계정끼리는 저장
3301
+ // 순서 대신 7d required drain(남은 비율 ÷ 리셋까지 남은 시간, upstream windowRequiredDrain 그대로)이 큰
3302
+ // 계정을 먼저 쓴다. 몫을 넘은 계정은 몫 안쪽 계정 뒤(페이스 보호), 둘 다 넘었으면 덜 넘은 쪽, 동률은 저장
3303
+ // 순서(위치 0 먼저). 2026-09-29 "몫 안쪽은 RIN(저장 순서 0) 먼저" 적용본을 대체한다(legacyPatched).
3304
+ // 사용량 그림이 완전하고 건강한 후보만, upstream ranking 에서 이미 차지한 자리들 안에서만 재배열한다.
3305
+ // unknown·partial·blocked·reserve·plan 부적격·5h hot 후보는 upstream 자리 그대로다. exact summon 은 이
3306
+ // 앞에서 return 하고 warm/explicit pin·plan pin 재승격은 이 뒤에 온다(warm pin 은 shouldRank=false).
3307
+ // 재배열 대상은 한도 미도달·측정 완료(used<1) 후보뿐이라 18.4.5 spent allowance 후보는 upstream 자리 그대로다.
3308
+ // 앵커는 18.4.4~18.4.6 모두 한 번 있는 preflightFailures 선언 한 줄이다. 검증: core-account-order-test.ts.
3308
3309
  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.",
3310
+ marker: "// Prefer the Anthropic account whose unused weekly quota expires soonest, inside its daily slice.",
3310
3311
  anchor: "\t\tconst preflightFailures = new Set<OAuthCandidate>();",
3311
- legacyPatched: ` // Prefer the healthy Anthropic account whose weekly window resets first.
3312
+ legacyPatched: ` // Prefer RIN (first Anthropic account) while it stays inside its daily slice of the weekly quota.
3312
3313
  // Only candidates with a complete, healthy usage picture move, and only among the slots they
3313
3314
  // 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.
3315
+ // 5h-hot candidates keep their place. Daily slice = (elapsed whole days + 1) / window days.
3316
+ // Inside the slice: storage order. Over it: smaller overshoot first, then storage order.
3315
3317
  if (provider === "anthropic" && shouldRank && strategy) {
3316
3318
  const nowMs = Date.now();
3319
+ const dayMs = 86_400_000;
3317
3320
  const weekly = candidates.map(candidate => {
3318
3321
  const usage = candidate.usage;
3319
3322
  if (!candidate.usageChecked || !usage || candidate.inReserve === true) return undefined;
@@ -3343,17 +3346,21 @@ import { resolveUsedFraction } from "../usage";`,
3343
3346
  return undefined;
3344
3347
  }
3345
3348
  const resetAt = secondary.window?.resetsAt;
3349
+ const durationMs = secondary.window?.durationMs;
3346
3350
  const used = resolveUsedFraction(secondary);
3347
3351
  if (typeof resetAt !== "number" || !Number.isFinite(resetAt) || resetAt <= nowMs) return undefined;
3352
+ if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < dayMs) return undefined;
3348
3353
  if (typeof used !== "number" || !Number.isFinite(used)) return undefined;
3349
- return { resetAt, remaining: 1 - used };
3354
+ const elapsedMs = Math.min(durationMs, Math.max(0, durationMs - (resetAt - nowMs)));
3355
+ const allowance = Math.min(1, ((Math.floor(elapsedMs / dayMs) + 1) * dayMs) / durationMs);
3356
+ return { overshoot: Math.max(0, used - allowance), index: candidate.selection.index };
3350
3357
  });
3351
3358
  const slots = candidates.flatMap((_candidate, pos) => (weekly[pos] ? [pos] : []));
3352
3359
  const preferred = [...slots]
3353
3360
  .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;
3361
+ const a = weekly[left]!;
3362
+ const b = weekly[right]!;
3363
+ return Number(a.overshoot > 0) - Number(b.overshoot > 0) || a.overshoot - b.overshoot || a.index - b.index;
3357
3364
  })
3358
3365
  .map(pos => candidates[pos]!);
3359
3366
  slots.forEach((pos, order) => {
@@ -3361,11 +3368,12 @@ import { resolveUsedFraction } from "../usage";`,
3361
3368
  });
3362
3369
  }
3363
3370
  const preflightFailures = new Set<OAuthCandidate>();`,
3364
- patched: ` // Prefer RIN (first Anthropic account) while it stays inside its daily slice of the weekly quota.
3371
+ patched: ` // Prefer the Anthropic account whose unused weekly quota expires soonest, inside its daily slice.
3365
3372
  // Only candidates with a complete, healthy usage picture move, and only among the slots they
3366
3373
  // already hold in the upstream ranking: unknown, partial, blocked, reserve, plan-ineligible or
3367
3374
  // 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.
3375
+ // Inside the slice: larger weekly required drain (upstream windowRequiredDrain) first.
3376
+ // Over it: after every in-slice account, smaller overshoot first. Ties: storage order.
3369
3377
  if (provider === "anthropic" && shouldRank && strategy) {
3370
3378
  const nowMs = Date.now();
3371
3379
  const dayMs = 86_400_000;
@@ -3405,14 +3413,23 @@ import { resolveUsedFraction } from "../usage";`,
3405
3413
  if (typeof used !== "number" || !Number.isFinite(used)) return undefined;
3406
3414
  const elapsedMs = Math.min(durationMs, Math.max(0, durationMs - (resetAt - nowMs)));
3407
3415
  const allowance = Math.min(1, ((Math.floor(elapsedMs / dayMs) + 1) * dayMs) / durationMs);
3408
- return { overshoot: Math.max(0, used - allowance), index: candidate.selection.index };
3416
+ return {
3417
+ overshoot: Math.max(0, used - allowance),
3418
+ drain: windowRequiredDrain(secondary, nowMs, strategy.windowDefaults.secondaryMs),
3419
+ index: candidate.selection.index,
3420
+ };
3409
3421
  });
3410
3422
  const slots = candidates.flatMap((_candidate, pos) => (weekly[pos] ? [pos] : []));
3411
3423
  const preferred = [...slots]
3412
3424
  .sort((left, right) => {
3413
3425
  const a = weekly[left]!;
3414
3426
  const b = weekly[right]!;
3415
- return Number(a.overshoot > 0) - Number(b.overshoot > 0) || a.overshoot - b.overshoot || a.index - b.index;
3427
+ return (
3428
+ Number(a.overshoot > 0) - Number(b.overshoot > 0) ||
3429
+ a.overshoot - b.overshoot ||
3430
+ (a.overshoot > 0 ? 0 : b.drain - a.drain) ||
3431
+ a.index - b.index
3432
+ );
3416
3433
  })
3417
3434
  .map(pos => candidates[pos]!);
3418
3435
  slots.forEach((pos, order) => {
@@ -3421,6 +3438,64 @@ import { resolveUsedFraction } from "../usage";`,
3421
3438
  }
3422
3439
  const preflightFailures = new Set<OAuthCandidate>();`,
3423
3440
  },
3441
+ // 2026-10-02 사용자 정책: summon marker 없이 띄운 일반 maker child 는 부모 세션의 Anthropic 계정 고정(warm 자동
3442
+ // pin·교체 exact pin 모두)을 물려받지 않고 위 순서 규칙으로 새로 고른다. 실제 경로: task 도구(task/index.ts) →
3443
+ // runStructuredSubagent(structured-subagent.ts: credentialSourceSessionId = 부모 agent.sessionId) → runSubprocess
3444
+ // → createAgentSession(sdk.ts) → authStorage.sessions.inherit. ‘린/미오 호출’ summon child 는 상속 뒤 character-voice
3445
+ // before_agent_start 가 지정 위치 exact pin 을 다시 걸므로 그대로 둔다. 다른 provider·maker 아닌 child 상속은 그대로.
3446
+ // 아래 네 파일 다섯 항목: inherit 의 provider 제외 인자, 그 타입, sdk 옵션·전달, executor 의 maker 판정.
3447
+ // 검증: core-account-order-test.ts [상속].
3448
+ {
3449
+ file: "../pi-ai/src/auth/affinity.ts",
3450
+ marker: "\tinherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number {",
3451
+ anchor: ` inherit(sourceSessionId: string, targetSessionId: string): number {
3452
+ if (!sourceSessionId || !targetSessionId || sourceSessionId === targetSessionId) return 0;
3453
+ let inherited = 0;
3454
+ for (const provider of this.#pool.providers()) {
3455
+ const credential = this.get(provider, sourceSessionId);
3456
+ if (!credential) continue;`,
3457
+ patched: ` inherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number {
3458
+ if (!sourceSessionId || !targetSessionId || sourceSessionId === targetSessionId) return 0;
3459
+ let inherited = 0;
3460
+ for (const provider of this.#pool.providers()) {
3461
+ if (skipProviders?.includes(provider)) continue;
3462
+ const credential = this.get(provider, sourceSessionId);
3463
+ if (!credential) continue;`,
3464
+ },
3465
+ {
3466
+ file: "../pi-ai/src/auth/types.ts",
3467
+ marker: "\tinherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number;",
3468
+ anchor: "\tinherit(sourceSessionId: string, targetSessionId: string): number;",
3469
+ patched: ` /** \`skipProviders\`: providers whose affinity the target must choose fresh instead of copying. */
3470
+ inherit(sourceSessionId: string, targetSessionId: string, skipProviders?: readonly string[]): number;`,
3471
+ },
3472
+ {
3473
+ file: "src/sdk.ts",
3474
+ marker: "\tcredentialInheritSkipProviders?: readonly string[];",
3475
+ anchor: "\tcredentialSourceSessionId?: string;\n\n\t/** Model to use. Default: from settings, else first available */",
3476
+ patched: ` credentialSourceSessionId?: string;
3477
+ /** Providers whose {@link credentialSourceSessionId} affinity is not copied; the child selects them fresh. */
3478
+ credentialInheritSkipProviders?: readonly string[];
3479
+
3480
+ /** Model to use. Default: from settings, else first available */`,
3481
+ },
3482
+ {
3483
+ file: "src/sdk.ts",
3484
+ marker: "options.credentialSourceSessionId, providerSessionId, options.credentialInheritSkipProviders);",
3485
+ anchor: "\t\tmodelRegistry.authStorage.sessions.inherit(options.credentialSourceSessionId, providerSessionId);",
3486
+ patched: ` modelRegistry.authStorage.sessions.inherit(
3487
+ options.credentialSourceSessionId, providerSessionId, options.credentialInheritSkipProviders);`,
3488
+ },
3489
+ {
3490
+ file: "src/task/executor.ts",
3491
+ marker: "\t\t\t\tcredentialInheritSkipProviders:",
3492
+ anchor: "\t\t\t\tcredentialSourceSessionId: options.credentialSourceSessionId,\n",
3493
+ patched: ` credentialSourceSessionId: options.credentialSourceSessionId,
3494
+ // A plain maker picks its own Anthropic account; a character summon re-pins its exact one.
3495
+ credentialInheritSkipProviders:
3496
+ agent.name === "maker" && !/\\[character-summon\\s/u.test(task) ? ["anthropic"] : undefined,
3497
+ `,
3498
+ },
3424
3499
  {
3425
3500
  // exact OAuth 가 해석되지 않으면 login API 키·18.4.5 config fallback 키(#13815)·env 키로 조용히 넘어가지 않는다.
3426
3501
  // 18.4.5는 resolveOAuth 성공 분기에 oauthIdentity 전달을 넣어 옛 한 덩어리 앵커가 사라졌다. 라벨은
package/install.mjs CHANGED
@@ -22,7 +22,11 @@ import { fileURLToPath } from "node:url";
22
22
  const ROOT = path.dirname(fileURLToPath(import.meta.url));
23
23
  const require = createRequire(path.join(ROOT, "package.json"));
24
24
 
25
- /** The model slots the public harness routes Makers to; `--model` sets omp's core `default` separately. */
25
+ /**
26
+ * The model slots the public harness routes Makers to; `--model` sets omp's core `default` separately.
27
+ * Same list as `lib/harness-roles.ts`, which the Model roles panel lists as "not set" until chosen;
28
+ * this file runs before dependencies exist, so `install.test.mjs` keeps the two equal.
29
+ */
26
30
  export const HARNESS_ROLES = [
27
31
  "implSonnet",
28
32
  "implOpus",
@@ -274,7 +278,7 @@ function setup(options) {
274
278
  if (roles.written) console.log(`Profile config: wrote ${roles.configPath}.`);
275
279
  if (roles.ignored.length > 0) console.log(`Profile config: ${roles.configPath} already exists and was not changed; ignored ${roles.ignored.join(", ")}.`);
276
280
  if (roles.missing.length > 0) {
277
- console.log(`Model roles not set: ${roles.missing.join(", ")}. Choose your own models in CUELO Settings > Model roles.`);
281
+ console.log(`Model roles not set: ${roles.missing.join(", ")}. They are listed as not set in CUELO Settings > Models > Model roles; choose your own models there.`);
278
282
  }
279
283
  console.log("Next: run `node install.mjs start`, open the address it prints, and sign in to your providers under Settings > Models.");
280
284
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cuelo",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "CUELO — open-source AI coding agent workspace and harness for omp (oh-my-pi)",
5
5
  "homepage": "https://github.com/gim47656-ship-it/CUELO#readme",
6
6
  "repository": {
@@ -109,6 +109,7 @@
109
109
  },
110
110
  "devDependencies": {
111
111
  "@lobehub/icons": "^5.16.0",
112
+ "@react-three/fiber": "^9.8.1",
112
113
  "@tailwindcss/postcss": "^4.3.3",
113
114
  "@types/bun": "^1.4.0",
114
115
  "@types/js-yaml": "^4.0.9",
@@ -116,6 +117,7 @@
116
117
  "@types/react": "^19.2.18",
117
118
  "@types/react-dom": "^19.2.5",
118
119
  "@types/react-syntax-highlighter": "^15.5.13",
120
+ "@types/three": "^0.186.0",
119
121
  "eslint": "^9.39.5",
120
122
  "eslint-config-next": "16.2.12",
121
123
  "jiti": "^2.7.0",
@@ -131,6 +133,7 @@
131
133
  "remark-gfm": "^4.0.1",
132
134
  "remark-math": "^6.0.0",
133
135
  "tailwindcss": "^4.3.3",
136
+ "three": "^0.186.1",
134
137
  "typescript": "^5.9.3"
135
138
  }
136
139
  }
@@ -0,0 +1,8 @@
1
+ # Office 3D assets
2
+
3
+ 오피스 보기의 3D 사무실(`components/office/OfficeScene3D.tsx`)은 내려받은 모델·텍스처·애니메이션 파일을 쓰지 않는다.
4
+ 방(바닥·벽·책상·의자·노트북·소파)과 일곱 캐릭터는 모두 코드에서 three.js 기본 도형으로 만든다. 유료 자산은 쓰지 않는다.
5
+
6
+ - 캐릭터 겉모습과 동작(대기 숨쉬기·걷기·앉아 일하기·손짓·쉬기)은 `components/office/OfficeCharacter.ts` 한 곳에 있다.
7
+ 각 캐릭터의 머리색·머리 모양·옷 색은 같은 저장소의 계정 아바타(`public/avatars/`)를 보고 정했다.
8
+ - 이전에 쓰던 three.js 예제 로봇(`RobotExpressive.glb`, CC0 1.0)은 더 쓰지 않아 지웠다.