cuelo 0.5.4 → 0.5.6

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 (113) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -8
  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.js +1 -1
  17. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/_not-found.html +1 -1
  19. package/.next/server/app/_not-found.rsc +4 -4
  20. package/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  21. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  25. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  26. package/.next/server/app/api/agent/[id]/account/route.js +1 -1
  27. package/.next/server/app/api/agent/[id]/account/route.js.nft.json +1 -1
  28. package/.next/server/app/api/agent/[id]/events/route.js +1 -1
  29. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
  30. package/.next/server/app/api/agent/[id]/route.js +1 -1
  31. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
  32. package/.next/server/app/api/agent/new/route.js +1 -1
  33. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  34. package/.next/server/app/api/agent/running/route.js +1 -1
  35. package/.next/server/app/api/agent/running/route.js.nft.json +1 -1
  36. package/.next/server/app/api/gpt6/handles/route.js +1 -1
  37. package/.next/server/app/api/gpt6/handles/route.js.nft.json +1 -1
  38. package/.next/server/app/api/gpt6/mcp/route.js +1 -1
  39. package/.next/server/app/api/gpt6/mcp/route.js.nft.json +1 -1
  40. package/.next/server/app/api/gpt6/reply/route.js +1 -1
  41. package/.next/server/app/api/gpt6/reply/route.js.nft.json +1 -1
  42. package/.next/server/app/api/gpt6/token/route.js +1 -1
  43. package/.next/server/app/api/gpt6/token/route.js.nft.json +1 -1
  44. package/.next/server/app/api/gpt6/web6-session/route.js +1 -1
  45. package/.next/server/app/api/gpt6/web6-session/route.js.nft.json +1 -1
  46. package/.next/server/app/api/live/call/[callId]/route.js +1 -1
  47. package/.next/server/app/api/live/call/[callId]/route.js.nft.json +1 -1
  48. package/.next/server/app/api/live/events/route.js +1 -1
  49. package/.next/server/app/api/live/events/route.js.nft.json +1 -1
  50. package/.next/server/app/api/live/offer/route.js +1 -1
  51. package/.next/server/app/api/live/offer/route.js.nft.json +1 -1
  52. package/.next/server/app/api/live/voices/route.js +1 -1
  53. package/.next/server/app/api/live/voices/route.js.nft.json +1 -1
  54. package/.next/server/app/api/project-trust/route.js +1 -1
  55. package/.next/server/app/api/project-trust/route.js.nft.json +1 -1
  56. package/.next/server/app/api/sessions/[id]/auto-name/route.js +1 -1
  57. package/.next/server/app/api/sessions/[id]/auto-name/route.js.nft.json +1 -1
  58. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  59. package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -1
  60. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  61. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  62. package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
  63. package/.next/server/app/api/sessions/[id]/state/route.js.nft.json +1 -1
  64. package/.next/server/app/api/sessions/route.js +1 -1
  65. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  66. package/.next/server/app/api/update-maintenance/route.js +2 -2
  67. package/.next/server/app/api/update-maintenance/route.js.nft.json +1 -1
  68. package/.next/server/app/api/updates/route.js +1 -1
  69. package/.next/server/app/favicon.ico/route.js +1 -1
  70. package/.next/server/app/favicon.ico.body +0 -0
  71. package/.next/server/app/index.html +1 -1
  72. package/.next/server/app/index.rsc +6 -6
  73. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  74. package/.next/server/app/index.segments/_full.segment.rsc +6 -6
  75. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  76. package/.next/server/app/index.segments/_index.segment.rsc +3 -3
  77. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  78. package/.next/server/app/page.js +2 -2
  79. package/.next/server/app/page_client-reference-manifest.js +1 -1
  80. package/.next/server/app/recover/page.js +1 -1
  81. package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app/recover.html +1 -1
  83. package/.next/server/app/recover.rsc +4 -4
  84. package/.next/server/app/recover.segments/_full.segment.rsc +4 -4
  85. package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
  86. package/.next/server/app/recover.segments/_index.segment.rsc +3 -3
  87. package/.next/server/app/recover.segments/_tree.segment.rsc +2 -2
  88. package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
  89. package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
  90. package/.next/server/app-paths-manifest.json +8 -8
  91. package/.next/server/chunks/6429.js +3 -3
  92. package/.next/server/middleware-build-manifest.js +1 -1
  93. package/.next/server/pages/404.html +1 -1
  94. package/.next/server/pages/500.html +1 -1
  95. package/.next/server/server-reference-manifest.json +1 -1
  96. package/.next/static/chunks/app/{layout-61356b8386302172.js → layout-6261ac86255ccc75.js} +1 -1
  97. package/.next/static/chunks/app/{page-d1291e02ffa77a51.js → page-d101dfa547083afb.js} +2 -2
  98. package/.next/static/css/{41958fa4965167ad.css → 0282259eb1a6b95f.css} +1 -1
  99. package/.next/trace +104 -104
  100. package/.next/trace-build +1 -1
  101. package/Tools/CUELO_Setup/files/native-runtime-patch.js +1 -1
  102. package/Tools/OMP_Global_Config/agent/extensions/jev-runtime.ts +10 -3
  103. package/Tools/OMP_Global_Config/agent/extensions/turn-end-guard.ts +4 -0
  104. package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +124 -6
  105. package/install.mjs +5 -3
  106. package/package.json +1 -1
  107. package/public/icons/apple-touch-icon.png +0 -0
  108. package/public/icons/cuelo-icon.svg +8 -0
  109. package/public/icons/icon-192.png +0 -0
  110. package/public/icons/icon-512.png +0 -0
  111. package/public/sw.js +3 -2
  112. /package/.next/static/{Xey7BdddcpqFxM5-ikcal → NZvNUVntEzl6V9pD45vuq}/_buildManifest.js +0 -0
  113. /package/.next/static/{Xey7BdddcpqFxM5-ikcal → NZvNUVntEzl6V9pD45vuq}/_ssgManifest.js +0 -0
package/.next/trace-build CHANGED
@@ -1 +1 @@
1
- [{"name":"run-webpack","duration":106080758,"timestamp":830040,"id":14,"parentId":1,"tags":{},"startTime":1790520334061,"traceId":"e7386bf183a20ea0"},{"name":"run-typescript","duration":16683711,"timestamp":107254477,"id":10640,"parentId":1,"tags":{},"startTime":1790520440486,"traceId":"e7386bf183a20ea0"},{"name":"static-check","duration":3754285,"timestamp":124053163,"id":10643,"parentId":1,"tags":{},"startTime":1790520457284,"traceId":"e7386bf183a20ea0"},{"name":"static-generation","duration":12403799,"timestamp":127920348,"id":10789,"parentId":1,"tags":{},"startTime":1790520461152,"traceId":"e7386bf183a20ea0"},{"name":"collect-build-traces","duration":21809759,"timestamp":127877906,"id":10786,"parentId":1,"tags":{},"startTime":1790520461109,"traceId":"e7386bf183a20ea0"},{"name":"telemetry-flush","duration":85,"timestamp":149692392,"id":10798,"parentId":1,"tags":{},"startTime":1790520482924,"traceId":"e7386bf183a20ea0"},{"name":"next-build","duration":149011974,"timestamp":680527,"id":1,"tags":{"buildMode":"default","version":"16.2.12","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1790520333912,"traceId":"e7386bf183a20ea0"}]
1
+ [{"name":"run-webpack","duration":89649911,"timestamp":688510,"id":14,"parentId":1,"tags":{},"startTime":1790570150388,"traceId":"a6840ff45438012c"},{"name":"run-typescript","duration":13356553,"timestamp":90667751,"id":10641,"parentId":1,"tags":{},"startTime":1790570240367,"traceId":"a6840ff45438012c"},{"name":"static-check","duration":3579393,"timestamp":104233152,"id":10644,"parentId":1,"tags":{},"startTime":1790570253932,"traceId":"a6840ff45438012c"},{"name":"static-generation","duration":9780588,"timestamp":107903437,"id":10790,"parentId":1,"tags":{},"startTime":1790570257602,"traceId":"a6840ff45438012c"},{"name":"collect-build-traces","duration":17435274,"timestamp":107871717,"id":10787,"parentId":1,"tags":{},"startTime":1790570257571,"traceId":"a6840ff45438012c"},{"name":"telemetry-flush","duration":55,"timestamp":125310779,"id":10799,"parentId":1,"tags":{},"startTime":1790570275009,"traceId":"a6840ff45438012c"},{"name":"next-build","duration":124705406,"timestamp":605447,"id":1,"tags":{"buildMode":"default","version":"16.2.12","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1790570150305,"traceId":"a6840ff45438012c"}]
@@ -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.5.4',
12
+ version: '0.5.6',
13
13
  distribution: 'cuelo',
14
14
  coreVersion: '18.3.5',
15
15
  };
@@ -239,8 +239,15 @@ function textContent(content: unknown): string {
239
239
  : "";
240
240
  }
241
241
 
242
- function classifyError(content: unknown): string {
242
+ // Windows 기본 curl.exe 는 `-o /dev/null` 을 파일 경로로 받아 쓰지 못하고 응답을 받은 뒤 exit 23 으로 끝난다.
243
+ const WINDOWS_CURL_DEVNULL = /\bcurl(?:\.exe)?\b[^\n;|&]*\s-o\s*\/dev\/null\b/u;
244
+
245
+ function classifyError(content: unknown, input?: unknown): string {
243
246
  const text = textContent(content);
247
+ const command = input && typeof input === "object" && "command" in input ? input.command : undefined;
248
+ if (/exited with code 23\b/u.test(text) && typeof command === "string" && WINDOWS_CURL_DEVNULL.test(command)) {
249
+ return "windows-shell";
250
+ }
244
251
  for (const [pattern, category] of ERROR_CATEGORY_PATTERNS) {
245
252
  if (pattern.test(text)) return category;
246
253
  }
@@ -1468,7 +1475,7 @@ export function createJevRuntime(deps: JevRuntimeDeps = {}) {
1468
1475
  const inputChanged = serializeInput(event.input) !== failure.inputSerialized;
1469
1476
  const observation = failure.observation;
1470
1477
  const nextAction = failure.category === "windows-shell"
1471
- ? "같은 명령을 그대로 재시도하지 않는다. PowerShell 로직은 write로 .ps1 파일을 만들고 -File <슬래시 절대경로>로 실행한다. .\\x·역슬래시 경로 대신 슬래시 절대경로를 쓴다. cmd /c rd·del 대신 rm 또는 .ps1의 Remove-Item -LiteralPath를 쓴다. `$'\\r'` 구문 오류는 PATH 첫 bash(WSL)가 CRLF .sh를 읽은 것이니 Git Bash(\"C:/Program Files/Git/bin/bash.exe\" <스크립트>)로 실행한다."
1478
+ ? "같은 명령을 그대로 재시도하지 않는다. PowerShell 로직은 write로 .ps1 파일을 만들고 -File <슬래시 절대경로>로 실행한다. .\\x·역슬래시 경로 대신 슬래시 절대경로를 쓴다. cmd /c rd·del 대신 rm 또는 .ps1의 Remove-Item -LiteralPath를 쓴다. `$'\\r'` 구문 오류는 PATH 첫 bash(WSL)가 CRLF .sh를 읽은 것이니 Git Bash(\"C:/Program Files/Git/bin/bash.exe\" <스크립트>)로 실행한다. `curl -o /dev/null`의 exit 23은 Windows curl.exe가 /dev/null에 쓰지 못한 것이라 응답은 이미 받았다. `-o NUL`이나 셸 리디렉션 `>/dev/null`로 바꾼다."
1472
1479
  : observation.cancelled && !observation.deterministicExitObserved
1473
1480
  ? "취소 근거 없음: 실행 결과 회수 또는 다음 한 변수 확인. 산출물·로그·프로세스 생존 중 하나를 새로 확인한 뒤 결정한다. stdout 침묵·낮은 CPU·elapsed만으로 stall을 확정하지 않는다."
1474
1481
  : RETRY_CATEGORY_NEXT_ACTION[failure.category]
@@ -1698,7 +1705,7 @@ export function createJevRuntime(deps: JevRuntimeDeps = {}) {
1698
1705
  if (!EXPLORATION_TOOLS[event.toolName]) {
1699
1706
  pendingFailures.set(event.toolName, {
1700
1707
  inputSerialized: serializeInput(event.input),
1701
- category: classifyError(event.content),
1708
+ category: classifyError(event.content, event.input),
1702
1709
  interveningTools: [],
1703
1710
  observation: readFailureObservation(event.details, event.content),
1704
1711
  });
@@ -313,6 +313,10 @@ export function createTurnEndGuard(
313
313
  });
314
314
  pi.on("agent_end", async (event, ctx) => {
315
315
  if (event.willContinue || nudgedThisInput || pendingJudge) return;
316
+ // 사용자 정지·업데이트/재시작 interrupt 가 끊은 턴이다. 여기서 이어 가게 하면 drain 뒤 옛 서버에서 도구가 다시 돈다.
317
+ const lastAssistant = [...event.messages].reverse().find((message) => (message as Message)?.role === "assistant") as
318
+ (Message & { stopReason?: string }) | undefined;
319
+ if (lastAssistant?.stopReason === "aborted") return;
316
320
  const hasTodo = todos.some((item) => item.status === "pending" || item.status === "in_progress");
317
321
  const last = lastAssistantText(event.messages);
318
322
  const soloText = activeInput && !hasTodo && last && !last.hasToolCall && !classifiedSoloThisInput
@@ -4915,6 +4915,62 @@ function operationFromNative(op: string): Operation | undefined {
4915
4915
  anchor: "\t\treturn `- ${content}${source}${date}`;\n",
4916
4916
  patched: "\t\t// HANSE: recall line carries memory id\n\t\tconst memoryId = result.id ? ` (id: ${result.id})` : \"\";\n\t\treturn `- ${content}${source}${date}${memoryId}`;\n",
4917
4917
  },
4918
+ {
4919
+ file: "src/tools/learn.ts",
4920
+ marker: 'import { redactMemorySecrets } from "../memory-backend/redact";',
4921
+ anchor: 'import { localBackend } from "../memory-backend/local-backend";',
4922
+ patched: 'import { localBackend } from "../memory-backend/local-backend";\nimport { redactMemorySecrets } from "../memory-backend/redact";\nimport type { MnemopiSessionState } from "../mnemopi/state";',
4923
+ },
4924
+ {
4925
+ file: "src/tools/learn.ts",
4926
+ marker: '"topic?": type("string").describe("stable topic key',
4927
+ anchor: '\t"context?": type("string").describe("optional source context for the lesson"),',
4928
+ patched: '\t"context?": type("string").describe("optional source context for the lesson"),\n\t"topic?": type("string").describe("stable topic key; later lessons with this key replace the prior project lesson"),',
4929
+ },
4930
+ {
4931
+ file: "src/tools/learn.ts",
4932
+ marker: '"topic?": type("string").describe("stable topic key; later lessons with this key replace the prior project lesson"),\n\t"scope?"',
4933
+ anchor: '\t"scope?": type("\'project\' | \'global\'").describe(',
4934
+ patched: '\t"topic?": type("string").describe("stable topic key; later lessons with this key replace the prior project lesson"),\n\t"scope?": type("\'project\' | \'global\'").describe(',
4935
+ },
4936
+ {
4937
+ file: "src/tools/learn.ts",
4938
+ marker: "// HANSE: topic-key learn upsert",
4939
+ anchor: "export class LearnTool implements AgentTool<LearnSchema> {",
4940
+ patched: `// HANSE: topic-key learn upsert
4941
+ function upsertLearnTopic(
4942
+ state: MnemopiSessionState,
4943
+ params: LearnParams,
4944
+ target: ReturnType<MnemopiSessionState["getScopedRetainTarget"]>,
4945
+ ): { id: string; revision: number } {
4946
+ const topic = params.topic!.normalize("NFKC").trim().toLowerCase();
4947
+ if (!topic) throw new Error("Learn topic must not be blank.");
4948
+ if (redactMemorySecrets(topic) !== topic) throw new Error("Learn topic contains a credential.");
4949
+ const db = target.memory.conn;
4950
+ const existing = db.query(
4951
+ "SELECT id, metadata_json FROM working_memory WHERE json_extract(metadata_json, '$.topic_key') = ? ORDER BY timestamp DESC, id DESC LIMIT 1",
4952
+ ).get(topic) as { id: string; metadata_json: string } | null;
4953
+ const revision = existing ? (Number(JSON.parse(existing.metadata_json).revision) || 1) + 1 : 1;
4954
+ if (existing) return db.transaction(() => {
4955
+ const content = redactMemorySecrets(params.memory);
4956
+ db.query("UPDATE working_memory SET content = ?, embed_text = NULL, timestamp = ?, metadata_json = ? WHERE id = ?").run(
4957
+ content, new Date().toISOString(),
4958
+ JSON.stringify({ ...JSON.parse(existing.metadata_json), context: params.context == null ? null : redactMemorySecrets(params.context), topic_key: topic, revision }),
4959
+ existing.id,
4960
+ );
4961
+ db.query("DELETE FROM memory_embeddings WHERE memory_id = ?").run(existing.id);
4962
+ return { id: existing.id, revision };
4963
+ })();
4964
+ const id = state.rememberScoped(params.memory, {
4965
+ source: "coding-agent-learn", importance: 0.8,
4966
+ metadata: { session_id: state.sessionId, cwd: state.session.sessionManager.getCwd(), context: params.context ?? null, tool: "learn", topic_key: topic, revision },
4967
+ scope: "bank", extract: true, extractEntities: true, veracity: "tool", memoryType: "fact",
4968
+ }, target);
4969
+ return { id, revision };
4970
+ }
4971
+
4972
+ export class LearnTool implements AgentTool<LearnSchema> {`,
4973
+ },
4918
4974
  {
4919
4975
  // learn 은 rememberScoped 가 돌려준 기억 id 를 버리고 "Lesson stored." 만 알렸다. 교훈을 뒤에서
4920
4976
  // 가리킬 식별자가 없으면 적용·결과를 연결할 수 없다. mnemopi 경로에서만 id 를 싣는다.
@@ -4923,13 +4979,15 @@ function operationFromNative(op: string): Operation | undefined {
4923
4979
  file: "src/tools/learn.ts",
4924
4980
  marker: "// HANSE: learn reports memory id",
4925
4981
  anchor: "\t\t\ttry {\n\t\t\t\tstate.rememberScoped(\n",
4926
- patched: "\t\t\ttry {\n\t\t\t\t// HANSE: learn reports memory id\n\t\t\t\tconst memoryId = state.rememberScoped(\n",
4982
+ legacyPatched: "\t\t\ttry {\n\t\t\t\t// HANSE: learn reports memory id\n\t\t\t\tconst memoryId = state.rememberScoped(\n",
4983
+ patched: "\t\t\ttry {\n\t\t\t\t// HANSE: learn reports memory id\n\t\t\t\tconst topicResult = params.topic ? upsertLearnTopic(state, params, target ?? state.getScopedRetainTarget()) : undefined;\n\t\t\t\tconst memoryId = topicResult?.id ?? state.rememberScoped(\n",
4927
4984
  },
4928
4985
  {
4929
4986
  file: "src/tools/learn.ts",
4930
- marker: "memoryMessage = `Lesson stored (id: ${memoryId})`;",
4987
+ marker: "memoryMessage = `Lesson stored (id: ${memoryId}${topicResult ?",
4931
4988
  anchor: "\t\t\t\t\ttarget,\n\t\t\t\t);\n\t\t\t} catch (error) {\n",
4932
- patched: "\t\t\t\t\ttarget,\n\t\t\t\t);\n\t\t\t\tif (memoryId) memoryMessage = `Lesson stored (id: ${memoryId})`;\n\t\t\t} catch (error) {\n",
4989
+ legacyPatched: "\t\t\t\t\ttarget,\n\t\t\t\t);\n\t\t\t\tif (memoryId) memoryMessage = `Lesson stored (id: ${memoryId})`;\n\t\t\t} catch (error) {\n",
4990
+ patched: "\t\t\t\t\ttarget,\n\t\t\t\t);\n\t\t\t\tif (memoryId) memoryMessage = `Lesson stored (id: ${memoryId}${topicResult ? `, revision: ${topicResult.revision}` : \"\"})`;\n\t\t\t} catch (error) {\n",
4933
4991
  },
4934
4992
  {
4935
4993
  // 2026-09-27: 자동 주입 <memories> 는 세션 파일에 남지 않아, Main 단독 세션에서 어떤 교훈이 전달됐는지
@@ -5173,12 +5231,64 @@ function raiseToAutoThinkingFloor(model: Model, level: Effort | undefined, setti
5173
5231
  this.#thinkingLevelCeiling,
5174
5232
  );`,
5175
5233
  },
5234
+ {
5235
+ // 2026-09-28 도구 오류 집계: `computer.window(65822)`처럼 숫자 id를 넘기면 필터 객체로 해석돼
5236
+ // 조건이 하나도 걸리지 않아 모든 창이 일치했고("multiple windows match 65822"), `title: /정규식/`은
5237
+ // 안내 없이 TypeError로 죽었다. 필터 값은 문자열만 받고, 아니면 무엇이 틀렸는지 말하는 ToolError를 낸다.
5238
+ file: "src/tools/computer/worker.ts",
5239
+ marker: "function assertWindowFilter(filter: unknown)",
5240
+ anchor: `function matchesFilter(window: DesktopWindow, filter?: WindowFilter): boolean {
5241
+ if (!filter) return true;`,
5242
+ patched: `/** A filter is a plain \`{ id?, app?, title? }\` of strings; anything else used to match every window. */
5243
+ function assertWindowFilter(filter: unknown): asserts filter is WindowFilter | undefined {
5244
+ if (filter === undefined) return;
5245
+ if (filter === null || typeof filter !== "object" || Array.isArray(filter)) {
5246
+ throw new ToolError(\`window filter must be an object like { app?, title?, id? }; got \${filter === null ? "null" : typeof filter}\`);
5247
+ }
5248
+ for (const key of ["id", "app", "title"] as const) {
5249
+ const value = (filter as Record<string, unknown>)[key];
5250
+ if (value !== undefined && typeof value !== "string") {
5251
+ const got = value instanceof RegExp ? \`RegExp \${value}\` : typeof value;
5252
+ throw new ToolError(\`window filter \${key} must be a string (\${key === "id" ? "exact window id" : "case-insensitive substring"}); got \${got}\`);
5253
+ }
5254
+ }
5255
+ }
5256
+
5257
+ function matchesFilter(window: DesktopWindow, filter?: WindowFilter): boolean {
5258
+ if (!filter) return true;`,
5259
+ },
5260
+ {
5261
+ // 숫자 id는 창 id(숫자 문자열)와 뜻이 하나뿐이라 문자열로 바꿔 id로 찾는다. 그 밖의 값은 위에서 거절한다.
5262
+ file: "src/tools/computer/worker.ts",
5263
+ marker: "const byId = typeof selector === \"number\"",
5264
+ anchor: ` const windows = await nativeCall(signal, () => session.listWindows());
5265
+ const matches =
5266
+ typeof selector === "string"
5267
+ ? windows.filter(window => window.id === selector)
5268
+ : windows.filter(window => matchesFilter(window, selector));`,
5269
+ patched: ` const byId = typeof selector === "number" && Number.isSafeInteger(selector) ? String(selector) : selector;
5270
+ if (typeof byId !== "string") assertWindowFilter(byId);
5271
+ const windows = await nativeCall(signal, () => session.listWindows());
5272
+ const matches =
5273
+ typeof byId === "string"
5274
+ ? windows.filter(window => window.id === byId)
5275
+ : windows.filter(window => matchesFilter(window, byId));`,
5276
+ },
5277
+ {
5278
+ file: "src/tools/computer/worker.ts",
5279
+ marker: "windows: async (filter?: WindowFilter): Promise<DesktopWindow[]> => {\n\t\t\t\tassertWindowFilter(filter);",
5280
+ anchor: ` windows: async (filter?: WindowFilter): Promise<DesktopWindow[]> => {
5281
+ const { signal } = getContext();`,
5282
+ patched: ` windows: async (filter?: WindowFilter): Promise<DesktopWindow[]> => {
5283
+ assertWindowFilter(filter);
5284
+ const { signal } = getContext();`,
5285
+ },
5176
5286
  ];
5177
5287
  // EDITS 문자열의 줄 끝을 LF로 통일한다. 이 파일의 작업 사본이 CRLF여도 core 파일(LF)과
5178
5288
  // 비교·치환이 어긋나지 않는다. core 파일 자체의 줄 끝은 건드리지 않는다.
5179
5289
  for (const entry of EDITS) {
5180
5290
  for (const candidate of [entry, ...(entry.alternates ?? [])]) {
5181
- for (const key of ["anchor", "marker", "patched"]) {
5291
+ for (const key of ["anchor", "marker", "patched", "legacyPatched"]) {
5182
5292
  if (typeof candidate[key] === "string") candidate[key] = candidate[key].replaceAll("\r\n", "\n");
5183
5293
  }
5184
5294
  }
@@ -5200,6 +5310,7 @@ function resolveEdit(entry, target) {
5200
5310
  const live = present
5201
5311
  .map(candidate => {
5202
5312
  const text = readFileSync(join(target, candidate.file), "utf8");
5313
+ if (candidate.legacyPatched && text.includes(candidate.legacyPatched)) return { ...candidate, path: join(target, candidate.file), text, status: "legacy" };
5203
5314
  if (text.includes(candidate.marker)) return { ...candidate, path: join(target, candidate.file), text, status: "applied" };
5204
5315
  if (text.includes(candidate.anchor)) return { ...candidate, path: join(target, candidate.file), text, status: "appliable" };
5205
5316
  return undefined;
@@ -5258,7 +5369,7 @@ function main() {
5258
5369
  // 적용의 역연산이므로 역순으로 되돌린다. 뒤 항목이 앞 항목의 patched 안쪽을 앵커로
5259
5370
  // 쓰는 중첩 편집(completion-bridge.ts)은 정순이면 앞 항목의 patched 가 이미 달라져 있다.
5260
5371
  for (const s of [...state].reverse()) {
5261
- if (s.status !== "applied") {
5372
+ if (s.status !== "applied" && s.status !== "legacy") {
5262
5373
  console.log(` 건너뜀 ${s.file} (적용 상태가 아니다)`);
5263
5374
  continue;
5264
5375
  }
@@ -5271,6 +5382,11 @@ function main() {
5271
5382
  console.log(` 복원 ${s.file}`);
5272
5383
  continue;
5273
5384
  }
5385
+ if (s.legacyPatched && current.includes(s.legacyPatched)) {
5386
+ writeFileSync(s.path, current.replace(s.legacyPatched, s.anchor), "utf8");
5387
+ console.log(` 복원 ${s.file} (옛 패치)`);
5388
+ continue;
5389
+ }
5274
5390
  const bak = join(BACKUP, s.file);
5275
5391
  if (existsSync(bak) && !readFileSync(bak, "utf8").includes(s.marker)) {
5276
5392
  copyFileSync(bak, s.path);
@@ -5306,7 +5422,9 @@ function main() {
5306
5422
  // 위와 같은 이유로 스냅샷이 아니라 현재 내용에 얹는다. 앵커 상실 검사는 위에서
5307
5423
  // 스냅샷 전체를 보고 이미 끝났으므로 preflight 의 원자성은 그대로다.
5308
5424
  const current = readFileSync(s.path, "utf8");
5309
- writeFileSync(s.path, current.replace(s.anchor, s.patched), "utf8");
5425
+ const from = s.status === "legacy" ? s.legacyPatched : s.anchor;
5426
+ if (!current.includes(from)) throw new Error(`적용 중 앵커가 사라졌다: ${s.file}`);
5427
+ writeFileSync(s.path, current.replace(from, s.patched), "utf8");
5310
5428
  console.log(` 적용 ${s.file}`);
5311
5429
  }
5312
5430
  console.log("적용 완료. CUELO를 재시작해야 반영된다.");
package/install.mjs CHANGED
@@ -155,9 +155,10 @@ export function copyHarness(sourceDir, agentDir, entries) {
155
155
  /**
156
156
  * What a new profile's `config.yml` starts with, so the public harness runs the way it is used:
157
157
  * local learning and project-scoped memory, the harness's Maker routing (isolated task runs,
158
- * its roles instead of the bundled agents) and request budget, and nothing that spends
159
- * provider requests on its own (`autoContinue`, `autoRetain` stay off). Values equal to the
160
- * omp defaults are left out.
158
+ * its roles instead of the bundled agents) and request budget, long `eval` cells that yield
159
+ * to steering (`eval.autoBackground`, off in omp), and nothing that spends provider requests
160
+ * on its own (`autoContinue`, `autoRetain` stay off). Values equal to the omp defaults are
161
+ * left out.
161
162
  */
162
163
  export const PROFILE_DEFAULTS = {
163
164
  defaultThinkingLevel: "auto",
@@ -172,6 +173,7 @@ export const PROFILE_DEFAULTS = {
172
173
  isolation: { enabled: true },
173
174
  disabledAgents: ["scout", "sonic", "task", "reviewer", "security-reviewer"],
174
175
  },
176
+ eval: { autoBackground: { enabled: true } },
175
177
  };
176
178
 
177
179
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cuelo",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
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": {
Binary file
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="512" height="512">
2
+ <!-- CUELO 앱 아이콘 원본. icon-192/512·apple-touch-icon·favicon.ico는 이 파일에서 뽑는다. -->
3
+ <rect width="100" height="100" rx="22" fill="#16171b"/>
4
+ <g transform="translate(15 15) scale(0.7)">
5
+ <path d="M77.9 30.5 A34 34 0 0 0 16 50 A26 26 0 0 0 68 50" fill="none" stroke="#eceef2" stroke-width="10" stroke-linecap="round"/>
6
+ <circle cx="42" cy="50" r="8.5" fill="#f5a524"/>
7
+ </g>
8
+ </svg>
Binary file
Binary file
package/public/sw.js CHANGED
@@ -3,8 +3,9 @@ const CACHE_PREFIX = "pi-web";
3
3
  // a precached shell file changes without a version change, so the activate
4
4
  // handler drops the previous cache instead of serving the stale shell. The
5
5
  // SEED surface cutover rewrote /offline.html and /manifest.webmanifest; r3
6
- // added the offline page's automatic return to the original address.
7
- const SHELL_REVISION = "3";
6
+ // added the offline page's automatic return to the original address; r4
7
+ // replaced the precached app icons with the spiral-lamp logo.
8
+ const SHELL_REVISION = "4";
8
9
  const CACHE_VERSION = `${new URL(self.location.href).searchParams.get("v") || "dev"}-r${SHELL_REVISION}`;
9
10
  const STATIC_CACHE = `${CACHE_PREFIX}-static-${CACHE_VERSION}`;
10
11
  const OFFLINE_URL = "/offline.html";