cuelo 0.10.6 → 0.10.7

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 (138) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +7 -7
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.js +1 -1
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +2 -2
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  23. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/.next/server/app/api/agent/[id]/account/route.js +1 -1
  26. package/.next/server/app/api/agent/[id]/account/route.js.nft.json +1 -1
  27. package/.next/server/app/api/agent/[id]/events/route.js +1 -1
  28. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
  29. package/.next/server/app/api/agent/[id]/route.js +1 -1
  30. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
  31. package/.next/server/app/api/agent/new/route.js +1 -1
  32. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  33. package/.next/server/app/api/agent/running/route.js +1 -1
  34. package/.next/server/app/api/agent/running/route.js.nft.json +1 -1
  35. package/.next/server/app/api/gpt6/handles/route.js +1 -1
  36. package/.next/server/app/api/gpt6/handles/route.js.nft.json +1 -1
  37. package/.next/server/app/api/gpt6/reply/route.js +1 -1
  38. package/.next/server/app/api/gpt6/reply/route.js.nft.json +1 -1
  39. package/.next/server/app/api/gpt6/token/route.js +1 -1
  40. package/.next/server/app/api/gpt6/token/route.js.nft.json +1 -1
  41. package/.next/server/app/api/gpt6/web6-session/route.js +1 -1
  42. package/.next/server/app/api/gpt6/web6-session/route.js.nft.json +1 -1
  43. package/.next/server/app/api/live/call/[callId]/route.js +1 -1
  44. package/.next/server/app/api/live/call/[callId]/route.js.nft.json +1 -1
  45. package/.next/server/app/api/live/events/route.js +1 -1
  46. package/.next/server/app/api/live/events/route.js.nft.json +1 -1
  47. package/.next/server/app/api/live/offer/route.js +1 -1
  48. package/.next/server/app/api/live/offer/route.js.nft.json +1 -1
  49. package/.next/server/app/api/live/voices/route.js +1 -1
  50. package/.next/server/app/api/live/voices/route.js.nft.json +1 -1
  51. package/.next/server/app/api/lounge/events/route.js +1 -1
  52. package/.next/server/app/api/lounge/events/route.js.nft.json +1 -1
  53. package/.next/server/app/api/lounge/route.js +1 -1
  54. package/.next/server/app/api/lounge/route.js.nft.json +1 -1
  55. package/.next/server/app/api/project-trust/route.js +1 -1
  56. package/.next/server/app/api/project-trust/route.js.nft.json +1 -1
  57. package/.next/server/app/api/sessions/[id]/auto-name/route.js +1 -1
  58. package/.next/server/app/api/sessions/[id]/auto-name/route.js.nft.json +1 -1
  59. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  60. package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -1
  61. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  62. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  63. package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
  64. package/.next/server/app/api/sessions/[id]/state/route.js.nft.json +1 -1
  65. package/.next/server/app/api/sessions/route.js +1 -1
  66. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  67. package/.next/server/app/api/sessions/search/route.js +1 -1
  68. package/.next/server/app/api/tool-image/route.js +1 -1
  69. package/.next/server/app/api/tool-image/route.js.nft.json +1 -1
  70. package/.next/server/app/api/update-maintenance/route.js +2 -2
  71. package/.next/server/app/api/update-maintenance/route.js.nft.json +1 -1
  72. package/.next/server/app/api/updates/route.js +1 -1
  73. package/.next/server/app/index.html +1 -1
  74. package/.next/server/app/index.rsc +4 -4
  75. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  76. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  77. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  78. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  79. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  80. package/.next/server/app/office/page_client-reference-manifest.js +1 -1
  81. package/.next/server/app/office-preview/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app/office-preview.html +1 -1
  83. package/.next/server/app/office-preview.rsc +2 -2
  84. package/.next/server/app/office-preview.segments/_full.segment.rsc +2 -2
  85. package/.next/server/app/office-preview.segments/_head.segment.rsc +1 -1
  86. package/.next/server/app/office-preview.segments/_index.segment.rsc +2 -2
  87. package/.next/server/app/office-preview.segments/_tree.segment.rsc +1 -1
  88. package/.next/server/app/office-preview.segments/office-preview/__PAGE__.segment.rsc +1 -1
  89. package/.next/server/app/office-preview.segments/office-preview.segment.rsc +1 -1
  90. package/.next/server/app/office.html +1 -1
  91. package/.next/server/app/office.rsc +4 -4
  92. package/.next/server/app/office.segments/_full.segment.rsc +4 -4
  93. package/.next/server/app/office.segments/_head.segment.rsc +1 -1
  94. package/.next/server/app/office.segments/_index.segment.rsc +2 -2
  95. package/.next/server/app/office.segments/_tree.segment.rsc +1 -1
  96. package/.next/server/app/office.segments/office/__PAGE__.segment.rsc +3 -3
  97. package/.next/server/app/office.segments/office.segment.rsc +1 -1
  98. package/.next/server/app/page_client-reference-manifest.js +1 -1
  99. package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
  100. package/.next/server/app/recover.html +1 -1
  101. package/.next/server/app/recover.rsc +2 -2
  102. package/.next/server/app/recover.segments/_full.segment.rsc +2 -2
  103. package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
  104. package/.next/server/app/recover.segments/_index.segment.rsc +2 -2
  105. package/.next/server/app/recover.segments/_tree.segment.rsc +1 -1
  106. package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
  107. package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
  108. package/.next/server/app-paths-manifest.json +7 -7
  109. package/.next/server/chunks/1008.js +13 -7
  110. package/.next/server/chunks/5489.js +2 -2
  111. package/.next/server/chunks/5582.js +2 -2
  112. package/.next/server/chunks/6429.js +11 -5
  113. package/.next/server/instrumentation.js +1 -1
  114. package/.next/server/instrumentation.js.nft.json +1 -1
  115. package/.next/server/middleware-build-manifest.js +1 -1
  116. package/.next/server/pages/404.html +1 -1
  117. package/.next/server/pages/500.html +1 -1
  118. package/.next/server/server-reference-manifest.json +1 -1
  119. package/.next/static/chunks/{9575-ba2dae41d5af7b78.js → 9575-be094f2a919d52af.js} +2 -2
  120. package/.next/static/chunks/app/{layout-1bab9c460b452d7c.js → layout-236f154f35d00bfb.js} +1 -1
  121. package/.next/trace +108 -108
  122. package/.next/trace-build +1 -1
  123. package/README.md +11 -0
  124. package/Tools/CUELO_Setup/files/native-runtime-patch.js +1 -1
  125. package/Tools/OMP_Global_Config/agent/RULES.md +5 -0
  126. package/Tools/OMP_Global_Config/agent/agents/maker.md +10 -1
  127. package/Tools/OMP_Global_Config/agent/extensions/lib/maker-routing.ts +44 -39
  128. package/Tools/OMP_Global_Config/agent/prompt-copies/RULES.en.md +6 -1
  129. package/Tools/OMP_Global_Config/agent/rules/docs-handoff.md +3 -0
  130. package/Tools/OMP_Global_Config/agent/rules/harness-policy.json +7 -2
  131. package/Tools/OMP_Global_Config/agent/rules/omp-harness.md +4 -3
  132. package/Tools/OMP_Global_Config/agent/rules/subagent.md +9 -6
  133. package/Tools/OMP_Global_Config/agent/sop/_common.md +9 -0
  134. package/Tools/OMP_Global_Config/agent/tools/git-finalizer/sync-checkout.ts +172 -0
  135. package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +116 -0
  136. package/package.json +1 -1
  137. /package/.next/static/{qBzr-fZX8Gd7lhzKpXzOw → QSt9HBZG013WHRuqj1_BA}/_buildManifest.js +0 -0
  138. /package/.next/static/{qBzr-fZX8Gd7lhzKpXzOw → QSt9HBZG013WHRuqj1_BA}/_ssgManifest.js +0 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * 검증·게시가 끝난 커밋을 같은 프로젝트의 다른 체크아웃(예: WSL 작업본 → Windows 사본)에 fast-forward로 반영하는 CLI.
3
+ *
4
+ * bun sync-checkout.ts --source <루트> --target <루트> --revision <40자 sha>
5
+ *
6
+ * 모델 도구가 아니다. 상시 동기화·스케줄러·훅 없이, 호출될 때 한 번만 일한다. 빌드·설치·배포는 하지 않는다.
7
+ * 대상 사본의 변경(tracked·staged·무시되지 않는 untracked)이나 갈라진/앞선 이력이 있으면 아무것도 바꾸지 않고 멈춘다.
8
+ * reset·stash·clean·force checkout·rebase·merge·잠금 삭제는 쓰지 않는다. 갱신은 `merge --ff-only <정확한 sha>` 하나다.
9
+ */
10
+ import { execFile } from "node:child_process";
11
+ import { realpath } from "node:fs/promises";
12
+ import { resolve, sep } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ import { type GitExecutor, selectGitExecutor } from "./wsl-git";
15
+
16
+ export interface SyncCheckoutOptions {
17
+ source: string;
18
+ target: string;
19
+ revision: string;
20
+ }
21
+
22
+ export type SyncCheckoutResult =
23
+ | { ok: true; status: "updated" | "already-current"; revision: string; branch: string; previous: string }
24
+ | { ok: false; status: "blocked"; reason: string };
25
+
26
+ interface GitOutput {
27
+ code: number;
28
+ stdout: string;
29
+ stderr: string;
30
+ }
31
+
32
+ class Blocked extends Error {}
33
+
34
+ function blocked(reason: string): never {
35
+ throw new Blocked(reason);
36
+ }
37
+
38
+ /**
39
+ * git에 넘길 비대화형 환경. Windows git.exe는 interop에서 WSLENV에 이름이 든 변수만 받으므로(2026-10-11 실측: 이름이 없으면
40
+ * 빈 값) 두 변수를 WSLENV에 더한다. 기존 WSLENV 항목은 보존한다. 전역 환경은 바꾸지 않고 자식 프로세스에만 적용한다.
41
+ */
42
+ function gitEnv(): NodeJS.ProcessEnv {
43
+ const names = (process.env.WSLENV ?? "").split(":").filter((entry) => entry.length > 0);
44
+ for (const name of ["GIT_TERMINAL_PROMPT", "GCM_INTERACTIVE"]) {
45
+ if (!names.some((entry) => entry.split("/")[0] === name)) names.push(name);
46
+ }
47
+ return { ...process.env, GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never", WSLENV: names.join(":") };
48
+ }
49
+
50
+ function runGit(executor: GitExecutor, cwd: string, args: string[]): Promise<GitOutput> {
51
+ const { promise, resolve, reject } = Promise.withResolvers<GitOutput>();
52
+ execFile(
53
+ executor.command,
54
+ args,
55
+ { cwd, env: gitEnv(), maxBuffer: 16 * 1024 * 1024 },
56
+ (error, stdout, stderr) => {
57
+ if (error && typeof error.code !== "number") {
58
+ reject(error);
59
+ return;
60
+ }
61
+ resolve({ code: typeof error?.code === "number" ? error.code : 0, stdout: String(stdout), stderr: String(stderr) });
62
+ },
63
+ );
64
+ return promise;
65
+ }
66
+
67
+ /** 성공해야 하는 git 호출. 실패하면 stderr를 이유로 멈춘다. */
68
+ async function git(executor: GitExecutor, cwd: string, args: string[], what: string): Promise<string> {
69
+ const out = await runGit(executor, cwd, args);
70
+ if (out.code !== 0) blocked(`${what} 실패(git ${args[0]}, 종료 ${out.code}): ${out.stderr.trim() || out.stdout.trim()}`);
71
+ return out.stdout.trim();
72
+ }
73
+
74
+ interface Checkout {
75
+ executor: GitExecutor;
76
+ root: string;
77
+ branch: string;
78
+ origin: string;
79
+ head: string;
80
+ }
81
+
82
+ async function inspect(label: string, path: string): Promise<Checkout> {
83
+ const root = await realpath(resolve(path)).catch(() => blocked(`${label} 경로가 없다: ${path}`));
84
+ const executor = await selectGitExecutor(root);
85
+ const top = executor.toPosix(await git(executor, root, ["rev-parse", "--show-toplevel"], `${label} 루트 확인`));
86
+ const topReal = await realpath(top).catch(() => blocked(`${label} git 루트를 해석하지 못했다: ${top}`));
87
+ if (topReal !== root) blocked(`${label} 경로가 체크아웃 루트가 아니다: ${root} (루트 ${topReal})`);
88
+ const branchOut = await runGit(executor, root, ["symbolic-ref", "--short", "-q", "HEAD"]);
89
+ if (branchOut.code !== 0 || !branchOut.stdout.trim()) blocked(`${label}이 detached HEAD 상태다`);
90
+ const origin = await git(executor, root, ["remote", "get-url", "origin"], `${label} origin 확인`);
91
+ const head = await git(executor, root, ["rev-parse", "HEAD"], `${label} HEAD 확인`);
92
+ return { executor, root, branch: branchOut.stdout.trim(), origin, head };
93
+ }
94
+
95
+ async function run({ source, target, revision }: SyncCheckoutOptions): Promise<SyncCheckoutResult> {
96
+ if (!/^[0-9a-f]{40}$/.test(revision)) blocked("revision은 소문자 40자 전체 sha여야 한다");
97
+ const src = await inspect("source", source);
98
+ const dst = await inspect("target", target);
99
+ if (src.root === dst.root || src.root.startsWith(dst.root + sep) || dst.root.startsWith(src.root + sep)) {
100
+ blocked(`source와 target이 같거나 겹친다: ${src.root} / ${dst.root}`);
101
+ }
102
+ if (src.origin !== dst.origin) blocked("source와 target의 origin이 다르다");
103
+ if (src.branch !== dst.branch) blocked(`브랜치가 다르다: source ${src.branch} / target ${dst.branch}`);
104
+ if (src.head !== revision) blocked(`요청한 revision이 source HEAD(${src.head})와 다르다`);
105
+
106
+ const { executor, root, branch } = dst;
107
+ const dirty = await git(executor, root, ["status", "--porcelain", "--untracked-files=normal"], "target 상태 확인");
108
+ if (dirty) blocked(`target에 반영되지 않은 변경이 있어 건드리지 않는다:\n${dirty}`);
109
+
110
+ // target의 기존 origin 설정 그대로, 비대화형으로 그 브랜치 하나만 가져와 게시 여부를 확인한다.
111
+ await git(executor, root, ["fetch", "--no-tags", "origin", `refs/heads/${branch}`], "origin fetch");
112
+ const tip = await git(executor, root, ["rev-parse", "FETCH_HEAD"], "FETCH_HEAD 확인");
113
+ const known = await runGit(executor, root, ["cat-file", "-e", `${revision}^{commit}`]);
114
+ if (known.code !== 0) blocked(`origin/${branch}에서 ${revision} 커밋을 찾지 못했다(게시되지 않음)`);
115
+ const published = await runGit(executor, root, ["merge-base", "--is-ancestor", revision, tip]);
116
+ if (published.code !== 0) blocked(`${revision}은 origin/${branch}에 게시되지 않았다`);
117
+
118
+ const previous = dst.head;
119
+ if (previous === revision) return { ok: true, status: "already-current", revision, branch, previous };
120
+
121
+ const ff = await runGit(executor, root, ["merge-base", "--is-ancestor", previous, revision]);
122
+ if (ff.code !== 0) blocked(`target HEAD(${previous})가 ${revision}의 조상이 아니다(앞섰거나 갈라짐). 건드리지 않는다`);
123
+
124
+ // fetch 동안 target이 바뀌지 않았는지 갱신 직전에 다시 본다. 바뀌었으면 되돌리지 않고 멈춘다.
125
+ const nowHead = await git(executor, root, ["rev-parse", "HEAD"], "갱신 직전 HEAD 확인");
126
+ const nowDirty = await git(executor, root, ["status", "--porcelain", "--untracked-files=normal"], "갱신 직전 상태 확인");
127
+ if (nowHead !== previous || nowDirty) blocked("fetch 중 target이 바뀌어 갱신하지 않았다");
128
+ // 무시된 로컬 파일이 새로 추적되는 경로와 겹쳐도 덮어쓰지 않는다(git merge 기본값은 덮어쓴다).
129
+ await git(executor, root, ["merge", "--ff-only", "--no-overwrite-ignore", revision], "fast-forward");
130
+ const after = await git(executor, root, ["rev-parse", "HEAD"], "갱신 후 HEAD 확인");
131
+ if (after !== revision) blocked(`갱신 후 target HEAD(${after})가 요청 revision과 다르다`);
132
+ const left = await git(executor, root, ["status", "--porcelain", "--untracked-files=normal"], "갱신 후 상태 확인");
133
+ if (left) blocked(`갱신 후 target이 깨끗하지 않다:\n${left}`);
134
+ return { ok: true, status: "updated", revision, branch, previous };
135
+ }
136
+
137
+ /** 막힘(Blocked)은 결과로 돌려주고, 예기치 못한 오류는 그대로 던진다. */
138
+ export async function syncCheckout(options: SyncCheckoutOptions): Promise<SyncCheckoutResult> {
139
+ try {
140
+ return await run(options);
141
+ } catch (error) {
142
+ if (error instanceof Blocked) return { ok: false, status: "blocked", reason: error.message };
143
+ throw error;
144
+ }
145
+ }
146
+
147
+ function parseArgs(argv: string[]): SyncCheckoutOptions {
148
+ const values: Record<string, string> = {};
149
+ for (let i = 0; i < argv.length; i += 2) {
150
+ const key = argv[i];
151
+ const value = argv[i + 1];
152
+ if (!["--source", "--target", "--revision"].includes(key) || value === undefined) {
153
+ throw new Error("usage: sync-checkout.ts --source <path> --target <path> --revision <sha>");
154
+ }
155
+ values[key.slice(2)] = value;
156
+ }
157
+ if (!values.source || !values.target || !values.revision) {
158
+ throw new Error("usage: sync-checkout.ts --source <path> --target <path> --revision <sha>");
159
+ }
160
+ return { source: values.source, target: values.target, revision: values.revision };
161
+ }
162
+
163
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
164
+ try {
165
+ const result = await syncCheckout(parseArgs(process.argv.slice(2)));
166
+ console.log(JSON.stringify(result));
167
+ process.exit(result.ok ? 0 : 1);
168
+ } catch (error) {
169
+ console.error(error instanceof Error ? error.message : String(error));
170
+ process.exit(2);
171
+ }
172
+ }
@@ -10060,6 +10060,122 @@ export function summarizeAutoLearnSaved(messages: readonly AgentMessage[], from:
10060
10060
  const saved = summarizeAutoLearnSaved(captureAgent.state.messages, captureMessages.length);
10061
10061
  if (saved.length > 0) options.onCaptured?.(saved);`,
10062
10062
  },
10063
+ {
10064
+ // capture 한 번의 실제 비용을 잰다(2026-10-10 Hermes 비교 M1, 방법 A). 지금까지 capture 응답의 usage는 저장 요약에서만
10065
+ // 읽고 버려져 "얼마나 드는가"를 답할 수 없었다. 이 capture 가 새로 만든 assistant 응답(원본 스냅샷 제외)만 합산한다.
10066
+ // 한 요청이라도 필드를 보고하지 않으면 그 합계는 null(미상)이지 0이 아니다. 본문·도구 인자·저장한 교훈 내용은 남기지 않는다.
10067
+ file: "src/sdk.ts",
10068
+ marker: `function summarizeAutoLearnUsage(`,
10069
+ anchor: `/** Build a private capture runner over a detached message snapshot and provider session. */`,
10070
+ patched: `/**
10071
+ * What a capture run's own assistant responses reported. A total is null (unknown, never 0) unless
10072
+ * every response reported that field, so a partial sum is never presented as complete.
10073
+ */
10074
+ interface AutoLearnCaptureUsage {
10075
+ /** Assistant responses the capture agent produced; each one is one provider request. */
10076
+ requests: number;
10077
+ /** Responses that ended aborted or error, whose usage is partial. */
10078
+ incompleteRequests: number;
10079
+ lastStopReason: string | null;
10080
+ input: number | null;
10081
+ output: number | null;
10082
+ cacheRead: number | null;
10083
+ cacheWrite: number | null;
10084
+ costUsd: number | null;
10085
+ }
10086
+
10087
+ /** Aggregate usage over the messages a capture run added after its source snapshot (\`from\`). */
10088
+ function summarizeAutoLearnUsage(messages: readonly AgentMessage[], from: number): AutoLearnCaptureUsage {
10089
+ const totals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, costUsd: 0 };
10090
+ const unknown = new Set<keyof typeof totals>();
10091
+ const add = (key: keyof typeof totals, value: unknown): void => {
10092
+ if (typeof value === "number" && Number.isFinite(value)) totals[key] += value;
10093
+ else unknown.add(key);
10094
+ };
10095
+ let requests = 0;
10096
+ let incompleteRequests = 0;
10097
+ let lastStopReason: string | null = null;
10098
+ for (let index = from; index < messages.length; index++) {
10099
+ const message = messages[index];
10100
+ if (message?.role !== "assistant") continue;
10101
+ requests++;
10102
+ lastStopReason = message.stopReason ?? null;
10103
+ if (message.stopReason === "aborted" || message.stopReason === "error") incompleteRequests++;
10104
+ const usage = message.usage as
10105
+ | { input?: unknown; output?: unknown; cacheRead?: unknown; cacheWrite?: unknown; cost?: { total?: unknown } }
10106
+ | undefined;
10107
+ add("input", usage?.input);
10108
+ add("output", usage?.output);
10109
+ add("cacheRead", usage?.cacheRead);
10110
+ add("cacheWrite", usage?.cacheWrite);
10111
+ add("costUsd", usage?.cost?.total);
10112
+ }
10113
+ const total = (key: keyof typeof totals): number | null => (requests > 0 && !unknown.has(key) ? totals[key] : null);
10114
+ return {
10115
+ requests,
10116
+ incompleteRequests,
10117
+ lastStopReason,
10118
+ input: total("input"),
10119
+ output: total("output"),
10120
+ cacheRead: total("cacheRead"),
10121
+ cacheWrite: total("cacheWrite"),
10122
+ costUsd: total("costUsd"),
10123
+ };
10124
+ }
10125
+
10126
+ /** Build a private capture runner over a detached message snapshot and provider session. */`,
10127
+ },
10128
+ {
10129
+ // 위 합계를 capture 한 번에 한 줄로 남긴다. finally 맨 앞(abort 리스너 해제 직후)에 두어 저장 알림·provider 상태 정리와
10130
+ // 독립이고, 관찰 실패가 원래 오류를 대체하지 못하도록 감싼다. 던져진 오류는 그대로 던진다.
10131
+ file: "src/sdk.ts",
10132
+ marker: `logger.info("Auto-learn capture usage", {`,
10133
+ anchor: ` signal?.addEventListener("abort", abortCapture, { once: true });
10134
+ try {
10135
+ if (signal?.aborted) {
10136
+ abortCapture();
10137
+ return;
10138
+ }
10139
+ await captureAgent.prompt(captureMessage);
10140
+ } catch (error) {
10141
+ if (!signal?.aborted) throw error;
10142
+ } finally {
10143
+ signal?.removeEventListener("abort", abortCapture);`,
10144
+ patched: ` signal?.addEventListener("abort", abortCapture, { once: true });
10145
+ const startedAt = performance.now();
10146
+ let thrown = false;
10147
+ try {
10148
+ if (signal?.aborted) {
10149
+ abortCapture();
10150
+ return;
10151
+ }
10152
+ await captureAgent.prompt(captureMessage);
10153
+ } catch (error) {
10154
+ if (!signal?.aborted) {
10155
+ thrown = true;
10156
+ throw error;
10157
+ }
10158
+ } finally {
10159
+ signal?.removeEventListener("abort", abortCapture);
10160
+ try {
10161
+ const { lastStopReason, ...usage } = summarizeAutoLearnUsage(captureAgent.state.messages, captureMessages.length);
10162
+ logger.info("Auto-learn capture usage", {
10163
+ provider: captureModel.provider,
10164
+ model: captureModel.id,
10165
+ outcome:
10166
+ thrown || lastStopReason === "error"
10167
+ ? "failed"
10168
+ : signal?.aborted || lastStopReason === "aborted"
10169
+ ? "aborted"
10170
+ : "completed",
10171
+ elapsedMs: Math.round(performance.now() - startedAt),
10172
+ ...usage,
10173
+ });
10174
+ } catch {
10175
+ // Static text only: the failure may carry the very content this row must not contain.
10176
+ logger.warn("Failed to record auto-learn capture usage");
10177
+ }`,
10178
+ },
10063
10179
  {
10064
10180
  // 저장 결과를 보이는 custom 메시지로 남긴다. idle이면 턴을 시작하지 않고 붙이고, 진행 중이면 aside로 끼운다.
10065
10181
  // r2: 머리글을 "[교훈 자동 저장] N건"으로 줄이고 3건까지만 보인다. legacyPatched는 r1 적용본.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cuelo",
3
- "version": "0.10.6",
3
+ "version": "0.10.7",
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": {