@covro/covro 0.7.0-beta.1 → 0.7.1-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +10 -10
  2. package/README.zh-CN.md +10 -10
  3. package/dist/cli/background.js +10 -7
  4. package/dist/cli/background.js.map +2 -2
  5. package/dist/cli/daemon.js +3 -1
  6. package/dist/cli/daemon.js.map +2 -2
  7. package/dist/cli/launch-environment.js +5 -2
  8. package/dist/cli/launch-environment.js.map +2 -2
  9. package/dist/cli/launchd.js +14 -8
  10. package/dist/cli/launchd.js.map +2 -2
  11. package/dist/cli/runtime-launch.js +108 -0
  12. package/dist/cli/runtime-launch.js.map +7 -0
  13. package/dist/cli/runtime.js +12 -0
  14. package/dist/cli/runtime.js.map +7 -0
  15. package/dist/cli/service.js +7 -4
  16. package/dist/cli/service.js.map +2 -2
  17. package/dist/codex/account-usage.js +132 -0
  18. package/dist/codex/account-usage.js.map +7 -0
  19. package/dist/codex/adapter.js +45 -4
  20. package/dist/codex/adapter.js.map +2 -2
  21. package/dist/codex/mapping.js +3 -2
  22. package/dist/codex/mapping.js.map +2 -2
  23. package/dist/server/http.js +8 -0
  24. package/dist/server/http.js.map +2 -2
  25. package/dist/server/service.js +71 -1
  26. package/dist/server/service.js.map +2 -2
  27. package/dist/server/workspaces.js +6 -0
  28. package/dist/server/workspaces.js.map +2 -2
  29. package/dist/shared/account-usage.js +1 -0
  30. package/dist/shared/account-usage.js.map +7 -0
  31. package/dist/shared/skills.js +25 -0
  32. package/dist/shared/skills.js.map +7 -0
  33. package/dist/shared/thread-summary.js +4 -0
  34. package/dist/shared/thread-summary.js.map +2 -2
  35. package/dist/shared/updates.js.map +2 -2
  36. package/dist/shared/validation.js +18 -1
  37. package/dist/shared/validation.js.map +2 -2
  38. package/dist/update-worker.cjs +1111 -754
  39. package/dist/updates/manager.js +89 -8
  40. package/dist/updates/manager.js.map +2 -2
  41. package/dist/updates/registry.js +7 -6
  42. package/dist/updates/registry.js.map +2 -2
  43. package/dist/updates/runtime.js +183 -0
  44. package/dist/updates/runtime.js.map +7 -0
  45. package/dist/updates/transaction.js +8 -4
  46. package/dist/updates/transaction.js.map +2 -2
  47. package/dist/updates/worker.js +177 -112
  48. package/dist/updates/worker.js.map +3 -3
  49. package/dist/web/assets/{abnfDiagram-WEYOIA3C-DPrSyxx5.js → abnfDiagram-WEYOIA3C-Ct5ChZBc.js} +1 -1
  50. package/dist/web/assets/{arc-4B8zsDlv.js → arc-BXRV0CVi.js} +1 -1
  51. package/dist/web/assets/{architecture-WOLXFQ4H-DzDNYcvm.js → architecture-WOLXFQ4H-CPBgJhsO.js} +1 -1
  52. package/dist/web/assets/{architectureDiagram-ZHVYKT53-CJ9tt7RD.js → architectureDiagram-ZHVYKT53-CLEC3Xoj.js} +1 -1
  53. package/dist/web/assets/{blockDiagram-RJAE7QA3-C9ljbm6J.js → blockDiagram-RJAE7QA3-BmLPHgTS.js} +1 -1
  54. package/dist/web/assets/{c4Diagram-XDPPPE54-Sd9QMUQp.js → c4Diagram-XDPPPE54-CR-FGGI9.js} +1 -1
  55. package/dist/web/assets/channel-B8Z0MEpl.js +1 -0
  56. package/dist/web/assets/{chunk-2E7WHVMD-DsUWsTrf.js → chunk-2E7WHVMD-CAKelRoz.js} +1 -1
  57. package/dist/web/assets/{chunk-4EMNKR2T-Bh91FySB.js → chunk-4EMNKR2T-CzHhqgrM.js} +1 -1
  58. package/dist/web/assets/{chunk-55XCU76K-BRxH4G9N.js → chunk-55XCU76K-BXdn9HRo.js} +1 -1
  59. package/dist/web/assets/{chunk-7S6XSTFO-DbTYm4kS.js → chunk-7S6XSTFO-iQXMs5VF.js} +1 -1
  60. package/dist/web/assets/{chunk-AQDTSKZB-D1NiDG4T.js → chunk-AQDTSKZB-BTLhVc8_.js} +1 -1
  61. package/dist/web/assets/{chunk-DSNLSHJZ-C0LQPoI8.js → chunk-DSNLSHJZ-MjR5Eo7J.js} +1 -1
  62. package/dist/web/assets/{chunk-HAGFOTED-DRrIOJjB.js → chunk-HAGFOTED-Bma7AjUx.js} +1 -1
  63. package/dist/web/assets/{chunk-HNE4Q36P-Bok-UYL9.js → chunk-HNE4Q36P-B-TPWEoT.js} +1 -1
  64. package/dist/web/assets/{chunk-NQOKRVIF-D1zmT8gY.js → chunk-NQOKRVIF-BnVBL0oP.js} +1 -1
  65. package/dist/web/assets/{chunk-UHW7PFBP-BDwjuCRk.js → chunk-UHW7PFBP-BrCzpTQe.js} +1 -1
  66. package/dist/web/assets/{chunk-VQ5W62QI-DAHWoS2u.js → chunk-VQ5W62QI-SVCda4i-.js} +1 -1
  67. package/dist/web/assets/{chunk-WQQL4CDK-ggfsBWta.js → chunk-WQQL4CDK-CFa1_xXP.js} +1 -1
  68. package/dist/web/assets/{chunk-XXDRQBXY-DBRGTT6L.js → chunk-XXDRQBXY-BrTjiUzN.js} +1 -1
  69. package/dist/web/assets/{chunk-YZO67HFG-BCM-hzbV.js → chunk-YZO67HFG-BqM0aDwN.js} +1 -1
  70. package/dist/web/assets/{chunk-ZAUX2LTX-MnMFUU_S.js → chunk-ZAUX2LTX-BAhm5jhj.js} +1 -1
  71. package/dist/web/assets/{chunk-ZCHMQSOR-ClT-_dGN.js → chunk-ZCHMQSOR-Cip7n8Sg.js} +1 -1
  72. package/dist/web/assets/{classDiagram-v2-4MYWR3UA-CPV9IWEk.js → classDiagram-v2-4MYWR3UA-D7N6Uj0X.js} +1 -1
  73. package/dist/web/assets/{cose-bilkent-JH36ORCC-DqgOWzoX.js → cose-bilkent-JH36ORCC-By_XO8JA.js} +1 -1
  74. package/dist/web/assets/{cynefin-EF2NZ3EQ-Dkit62ND.js → cynefin-EF2NZ3EQ-D4tmIqN2.js} +1 -1
  75. package/dist/web/assets/{cynefinDiagram-WF24UDRP-DSiF7XN6.js → cynefinDiagram-WF24UDRP-BiBX9g64.js} +1 -1
  76. package/dist/web/assets/{dagre-NK4GIZVX-DPMP_fYv.js → dagre-NK4GIZVX-BGoSiF2R.js} +1 -1
  77. package/dist/web/assets/{diagram-CBK3MWTC-CyMSNHt0.js → diagram-CBK3MWTC-CcFPBcEd.js} +1 -1
  78. package/dist/web/assets/{diagram-I5XIIV2D-tQ2bMi8B.js → diagram-I5XIIV2D-DehB2F5t.js} +1 -1
  79. package/dist/web/assets/{diagram-ODIL2UCW-BGZKonG-.js → diagram-ODIL2UCW-V8fUY3mq.js} +1 -1
  80. package/dist/web/assets/{diagram-PFBEJUXE-ChscR483.js → diagram-PFBEJUXE-BHHEFVnW.js} +1 -1
  81. package/dist/web/assets/{diagram-RJA3I4VV-frBsA7DX.js → diagram-RJA3I4VV-D2exArjj.js} +1 -1
  82. package/dist/web/assets/{diagram-TYUNFSNR-B8qZBREp.js → diagram-TYUNFSNR-BdtGXIpi.js} +1 -1
  83. package/dist/web/assets/{dist-7U4_LxsV.js → dist-DaQz3nkD.js} +1 -1
  84. package/dist/web/assets/{ebnfDiagram-V4P3TTPT-CfnjkhXT.js → ebnfDiagram-V4P3TTPT-Cggzc5yD.js} +1 -1
  85. package/dist/web/assets/{elk-QONTBCTQ-D6KBNmbF.js → elk-QONTBCTQ-DDC0zLrS.js} +1 -1
  86. package/dist/web/assets/{erDiagram-KYQIGQAA-Sx8YaD42.js → erDiagram-KYQIGQAA-DfypQFgb.js} +1 -1
  87. package/dist/web/assets/{eventmodeling-K75KTNOO-DgI4Zm6z.js → eventmodeling-K75KTNOO-D8qBsuC_.js} +1 -1
  88. package/dist/web/assets/flowDiagram-IUGLLWBU-GpPr3WFa.js +1 -0
  89. package/dist/web/assets/{ganttDiagram-R7GPNTJY-FN9ghlFf.js → ganttDiagram-R7GPNTJY-CENwnE1B.js} +1 -1
  90. package/dist/web/assets/{gitGraph-VSP46ZUC-B6RMx5nS.js → gitGraph-VSP46ZUC-BVF17ADV.js} +1 -1
  91. package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-BUfDV32d.js → gitGraphDiagram-PDYL7XHY-C1qi9iCy.js} +1 -1
  92. package/dist/web/assets/index-2ms-LtOu.css +1 -0
  93. package/dist/web/assets/index-C-VE9GLc.js +158 -0
  94. package/dist/web/assets/{info-OHQRW6UA-i9U_Vjx9.js → info-OHQRW6UA-LgFb_2F-.js} +1 -1
  95. package/dist/web/assets/{infoDiagram-MVDRKAX5-BcIiBHfp.js → infoDiagram-MVDRKAX5-17P2DCcG.js} +1 -1
  96. package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-CBq8uWqz.js → ishikawaDiagram-HPEHV2GE-YI3XteWz.js} +1 -1
  97. package/dist/web/assets/{journeyDiagram-BOSHW7O7-BoH8zvhM.js → journeyDiagram-BOSHW7O7-DqIEkafR.js} +1 -1
  98. package/dist/web/assets/{kanban-definition-FNSA4HC5-DqWoSu__.js → kanban-definition-FNSA4HC5-CMQ9DCXo.js} +1 -1
  99. package/dist/web/assets/{line-mJzmbB6p.js → line-BzaaPKlk.js} +1 -1
  100. package/dist/web/assets/{linear-BwkmaM-M.js → linear-8o2E18fD.js} +1 -1
  101. package/dist/web/assets/{mermaid-parser.core-DwFqVvpp.js → mermaid-parser.core-kGccWBJU.js} +3 -3
  102. package/dist/web/assets/{mermaid.core-DcF8gYr_.js → mermaid.core-BSQidwq_.js} +4 -4
  103. package/dist/web/assets/{mindmap-definition-6OY57UG3-D4XGBbWO.js → mindmap-definition-6OY57UG3-D-FFEmUv.js} +1 -1
  104. package/dist/web/assets/{packet-JDAUHWVQ-Da_cMCDo.js → packet-JDAUHWVQ-DJhUFf1j.js} +1 -1
  105. package/dist/web/assets/{pegDiagram-ECIUJNBX-CVgVmFmC.js → pegDiagram-ECIUJNBX-CmIOvdbf.js} +1 -1
  106. package/dist/web/assets/{pie-XZMESJXO-7pec9CJT.js → pie-XZMESJXO-CSrWK9rU.js} +1 -1
  107. package/dist/web/assets/{pieDiagram-GNMPY74T-97N9EH_E.js → pieDiagram-GNMPY74T-tvVSdXH-.js} +1 -1
  108. package/dist/web/assets/{quadrantDiagram-D57K4MC3-FJDGQ0ZC.js → quadrantDiagram-D57K4MC3-CGK1kRkp.js} +1 -1
  109. package/dist/web/assets/{radar-ABXABTNO-DsWXE4id.js → radar-ABXABTNO-MDz1NYHf.js} +1 -1
  110. package/dist/web/assets/{railroad-I3PHUGI6-Cs3NR5Rp.js → railroad-I3PHUGI6-CiLd87KR.js} +1 -1
  111. package/dist/web/assets/{railroad-abnf-LNEFI6M7-fn-KtM-H.js → railroad-abnf-LNEFI6M7-RY_WYJN6.js} +1 -1
  112. package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-BuexEj3O.js → railroad-ebnf-DWYD2UWJ-B4ZEET0K.js} +1 -1
  113. package/dist/web/assets/{railroad-peg-JR7BVNR7-C59VHWhm.js → railroad-peg-JR7BVNR7-9DbLhbQQ.js} +1 -1
  114. package/dist/web/assets/{railroadDiagram-Y72NRBL7-Dwpn4kqo.js → railroadDiagram-Y72NRBL7-onpNqRG_.js} +1 -1
  115. package/dist/web/assets/{requirementDiagram-EQYSW5RA-BE9cDXG8.js → requirementDiagram-EQYSW5RA-Bk6XTcPp.js} +1 -1
  116. package/dist/web/assets/{sankeyDiagram-SY24JHO5-BiPoxRoH.js → sankeyDiagram-SY24JHO5-K4434mnD.js} +1 -1
  117. package/dist/web/assets/{sequenceDiagram-BLEHNHQU-OHewZwiU.js → sequenceDiagram-BLEHNHQU-DQiu1tXe.js} +1 -1
  118. package/dist/web/assets/{src-CAqT2rVv.js → src-PYZv1Xmx.js} +1 -1
  119. package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-BHul6PGu.js → stateDiagram-v2-A6IESKWZ-BVNOf4hf.js} +1 -1
  120. package/dist/web/assets/{swimlanes-B3ENRKFQ-BBjoKZII.js → swimlanes-B3ENRKFQ-Sr8zlNgH.js} +1 -1
  121. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-Cxqy1i01.js +8 -0
  122. package/dist/web/assets/{timeline-definition-JXYKGLGB-D7reGFUV.js → timeline-definition-JXYKGLGB-D3UD0on6.js} +1 -1
  123. package/dist/web/assets/{treeView-D4JQ5SDB-BC4PBy2z.js → treeView-D4JQ5SDB-DMkXgni_.js} +1 -1
  124. package/dist/web/assets/{treemap-SAJKECNS-C-L3y3B0.js → treemap-SAJKECNS-BFVUPZHm.js} +1 -1
  125. package/dist/web/assets/{usecaseDiagram-WPOLBNNX-DqReWsLT.js → usecaseDiagram-WPOLBNNX-BY0Ux9fE.js} +1 -1
  126. package/dist/web/assets/{vennDiagram-Q3Y3IDCW-RB21WgMG.js → vennDiagram-Q3Y3IDCW-DTSz-zyI.js} +1 -1
  127. package/dist/web/assets/{wardley-7MLQ67FV-CAGdvTyZ.js → wardley-7MLQ67FV-DEoiPn37.js} +1 -1
  128. package/dist/web/assets/{wardleyDiagram-IVAIDKWA-DXN5Mh5B.js → wardleyDiagram-IVAIDKWA-CJWnMB5u.js} +1 -1
  129. package/dist/web/assets/{xychartDiagram-4URNHDU4-Y2Tpnzwb.js → xychartDiagram-4URNHDU4-X8rgPB9G.js} +1 -1
  130. package/dist/web/index.html +2 -2
  131. package/dist/web/notification-worker.js +33 -0
  132. package/package.json +4 -4
  133. package/dist/web/assets/channel-DKYuZv8c.js +0 -1
  134. package/dist/web/assets/flowDiagram-IUGLLWBU-AdTZW4EM.js +0 -1
  135. package/dist/web/assets/index-BayHb2le.js +0 -156
  136. package/dist/web/assets/index-qYBdGqKM.css +0 -1
  137. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-Cp-6Y0VO.js +0 -8
@@ -0,0 +1,12 @@
1
+ import { join, resolve } from "node:path";
2
+ import { packageRoot } from "./paths.js";
3
+ const runningRuntime = () => ({
4
+ node: process.execPath,
5
+ nodeVersion: process.versions.node,
6
+ root: resolve(packageRoot),
7
+ entry: join(packageRoot, "bin/covro.mjs")
8
+ });
9
+ export {
10
+ runningRuntime
11
+ };
12
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cli/runtime.ts"],
4
+ "sourcesContent": ["import { join, resolve } from 'node:path';\nimport { packageRoot } from './paths.js';\nimport type { RuntimeIdentity } from '../shared/updates.js';\n\nexport const runningRuntime = (): RuntimeIdentity => ({\n node: process.execPath,\n nodeVersion: process.versions.node,\n root: resolve(packageRoot),\n entry: join(packageRoot, 'bin/covro.mjs'),\n});\n"],
5
+ "mappings": "AAAA,SAAS,MAAM,eAAe;AAC9B,SAAS,mBAAmB;AAGrB,MAAM,iBAAiB,OAAwB;AAAA,EACpD,MAAM,QAAQ;AAAA,EACd,aAAa,QAAQ,SAAS;AAAA,EAC9B,MAAM,QAAQ,WAAW;AAAA,EACzB,OAAO,KAAK,aAAa,eAAe;AAC1C;",
6
+ "names": []
7
+ }
@@ -7,8 +7,8 @@ import { stopAndWait } from "./control.js";
7
7
  import { saveJson } from "../updates/files.js";
8
8
  import { ensureConfig, packageRoot } from "./paths.js";
9
9
  import { macOSLoginService } from "./background.js";
10
+ import { launchRuntime, systemdQuote as unit } from "./runtime-launch.js";
10
11
  const exec = promisify(execFile);
11
- const unit = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
12
12
  async function service(location, install) {
13
13
  if (!["darwin", "linux"].includes(process.platform))
14
14
  throw new Error(
@@ -29,15 +29,18 @@ async function service(location, install) {
29
29
  const filename = join(directory, `${label}.service`);
30
30
  if (install) {
31
31
  await mkdir(directory, { recursive: true });
32
- if (/[\r\n]/.test([entry, location.config, location.home, process.env.PATH].join("")))
32
+ const runtime = await launchRuntime(location, entry);
33
+ if (/[\r\n]/.test(
34
+ [runtime.node, runtime.entry, location.config, location.home, runtime.path].join("")
35
+ ))
33
36
  throw new Error("\u670D\u52A1\u8DEF\u5F84\u548C PATH \u4E0D\u80FD\u5305\u542B\u6362\u884C");
34
37
  await writeFile(
35
38
  filename,
36
39
  `[Unit]
37
40
  Description=Covro
38
41
  [Service]
39
- ExecStart=${[process.execPath, entry, "run", "--config", location.config].map(unit).join(" ")}
40
- Environment=${unit(`COVRO_HOME=${location.home}`)} ${unit(`PATH=${process.env.PATH ?? "/usr/bin:/bin"}`)}
42
+ ExecStart=${[runtime.node, runtime.entry, "run", "--config", location.config].map(unit).join(" ")}
43
+ Environment=${unit(`COVRO_HOME=${location.home}`)} ${unit(`PATH=${runtime.path}`)}
41
44
  Restart=on-failure
42
45
  RestartSec=30
43
46
  [Install]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cli/service.ts"],
4
- "sourcesContent": ["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { stopAndWait } from './control.js';\nimport { saveJson } from '../updates/files.js';\nimport { ensureConfig, packageRoot, type CovroPaths } from './paths.js';\nimport { macOSLoginService } from './background.js';\n\nconst exec = promisify(execFile);\nconst unit = (value: string) =>\n `\"${value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"').replaceAll('%', '%%')}\"`;\n\nexport async function service(location: CovroPaths, install: boolean) {\n if (!['darwin', 'linux'].includes(process.platform))\n throw new Error(\n '\u767B\u5F55\u81EA\u542F\u76EE\u524D\u652F\u6301 macOS launchd \u548C Linux systemd --user\uFF1B\u53EF\u4F7F\u7528 covro start \u540E\u53F0\u8FD0\u884C\u3002',\n );\n const label = `dev.covro.${location.key}`;\n const entry = join(packageRoot, 'bin/covro.mjs');\n if (process.platform === 'darwin') {\n if (install) await ensureConfig(location);\n await macOSLoginService(location, entry, install);\n return;\n }\n if (install) {\n await stopAndWait(location);\n await mkdir(location.state, { recursive: true, mode: 0o700 });\n }\n const directory = join(homedir(), '.config/systemd/user');\n const filename = join(directory, `${label}.service`);\n if (install) {\n await mkdir(directory, { recursive: true });\n if (/[\\r\\n]/.test([entry, location.config, location.home, process.env.PATH].join('')))\n throw new Error('\u670D\u52A1\u8DEF\u5F84\u548C PATH \u4E0D\u80FD\u5305\u542B\u6362\u884C');\n await writeFile(\n filename,\n `[Unit]\\nDescription=Covro\\n[Service]\\nExecStart=${[process.execPath, entry, 'run', '--config', location.config].map(unit).join(' ')}\\nEnvironment=${unit(`COVRO_HOME=${location.home}`)} ${unit(`PATH=${process.env.PATH ?? '/usr/bin:/bin'}`)}\\nRestart=on-failure\\nRestartSec=30\\n[Install]\\nWantedBy=default.target\\n`,\n { mode: 0o600 },\n );\n await exec('systemctl', ['--user', 'daemon-reload']);\n await exec('systemctl', ['--user', 'enable', '--now', `${label}.service`]);\n await saveJson(join(location.state, 'service.json'), { platform: 'linux', label });\n } else {\n await exec('systemctl', ['--user', 'disable', '--now', `${label}.service`]);\n await rm(filename);\n await rm(join(location.state, 'service.json'), { force: true });\n await exec('systemctl', ['--user', 'daemon-reload']);\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,OAAO,IAAI,iBAAiB;AACrC,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,cAAc,mBAAoC;AAC3D,SAAS,yBAAyB;AAElC,MAAM,OAAO,UAAU,QAAQ;AAC/B,MAAM,OAAO,CAAC,UACZ,IAAI,MAAM,WAAW,MAAM,MAAM,EAAE,WAAW,KAAK,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAEjF,eAAsB,QAAQ,UAAsB,SAAkB;AACpE,MAAI,CAAC,CAAC,UAAU,OAAO,EAAE,SAAS,QAAQ,QAAQ;AAChD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,QAAQ,aAAa,SAAS,GAAG;AACvC,QAAM,QAAQ,KAAK,aAAa,eAAe;AAC/C,MAAI,QAAQ,aAAa,UAAU;AACjC,QAAI,QAAS,OAAM,aAAa,QAAQ;AACxC,UAAM,kBAAkB,UAAU,OAAO,OAAO;AAChD;AAAA,EACF;AACA,MAAI,SAAS;AACX,UAAM,YAAY,QAAQ;AAC1B,UAAM,MAAM,SAAS,OAAO,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,EAC9D;AACA,QAAM,YAAY,KAAK,QAAQ,GAAG,sBAAsB;AACxD,QAAM,WAAW,KAAK,WAAW,GAAG,KAAK,UAAU;AACnD,MAAI,SAAS;AACX,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAI,SAAS,KAAK,CAAC,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;AAClF,YAAM,IAAI,MAAM,0EAAmB;AACrC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA;AAAA;AAAA,YAAmD,CAAC,QAAQ,UAAU,OAAO,OAAO,YAAY,SAAS,MAAM,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG,CAAC;AAAA,cAAiB,KAAK,cAAc,SAAS,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,QAAQ,IAAI,QAAQ,eAAe,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAC/O,EAAE,MAAM,IAAM;AAAA,IAChB;AACA,UAAM,KAAK,aAAa,CAAC,UAAU,eAAe,CAAC;AACnD,UAAM,KAAK,aAAa,CAAC,UAAU,UAAU,SAAS,GAAG,KAAK,UAAU,CAAC;AACzE,UAAM,SAAS,KAAK,SAAS,OAAO,cAAc,GAAG,EAAE,UAAU,SAAS,MAAM,CAAC;AAAA,EACnF,OAAO;AACL,UAAM,KAAK,aAAa,CAAC,UAAU,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC;AAC1E,UAAM,GAAG,QAAQ;AACjB,UAAM,GAAG,KAAK,SAAS,OAAO,cAAc,GAAG,EAAE,OAAO,KAAK,CAAC;AAC9D,UAAM,KAAK,aAAa,CAAC,UAAU,eAAe,CAAC;AAAA,EACrD;AACF;",
4
+ "sourcesContent": ["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { stopAndWait } from './control.js';\nimport { saveJson } from '../updates/files.js';\nimport { ensureConfig, packageRoot, type CovroPaths } from './paths.js';\nimport { macOSLoginService } from './background.js';\nimport { launchRuntime, systemdQuote as unit } from './runtime-launch.js';\n\nconst exec = promisify(execFile);\n\nexport async function service(location: CovroPaths, install: boolean) {\n if (!['darwin', 'linux'].includes(process.platform))\n throw new Error(\n '\u767B\u5F55\u81EA\u542F\u76EE\u524D\u652F\u6301 macOS launchd \u548C Linux systemd --user\uFF1B\u53EF\u4F7F\u7528 covro start \u540E\u53F0\u8FD0\u884C\u3002',\n );\n const label = `dev.covro.${location.key}`;\n const entry = join(packageRoot, 'bin/covro.mjs');\n if (process.platform === 'darwin') {\n if (install) await ensureConfig(location);\n await macOSLoginService(location, entry, install);\n return;\n }\n if (install) {\n await stopAndWait(location);\n await mkdir(location.state, { recursive: true, mode: 0o700 });\n }\n const directory = join(homedir(), '.config/systemd/user');\n const filename = join(directory, `${label}.service`);\n if (install) {\n await mkdir(directory, { recursive: true });\n const runtime = await launchRuntime(location, entry);\n if (\n /[\\r\\n]/.test(\n [runtime.node, runtime.entry, location.config, location.home, runtime.path].join(''),\n )\n )\n throw new Error('\u670D\u52A1\u8DEF\u5F84\u548C PATH \u4E0D\u80FD\u5305\u542B\u6362\u884C');\n await writeFile(\n filename,\n `[Unit]\\nDescription=Covro\\n[Service]\\nExecStart=${[runtime.node, runtime.entry, 'run', '--config', location.config].map(unit).join(' ')}\\nEnvironment=${unit(`COVRO_HOME=${location.home}`)} ${unit(`PATH=${runtime.path}`)}\\nRestart=on-failure\\nRestartSec=30\\n[Install]\\nWantedBy=default.target\\n`,\n { mode: 0o600 },\n );\n await exec('systemctl', ['--user', 'daemon-reload']);\n await exec('systemctl', ['--user', 'enable', '--now', `${label}.service`]);\n await saveJson(join(location.state, 'service.json'), { platform: 'linux', label });\n } else {\n await exec('systemctl', ['--user', 'disable', '--now', `${label}.service`]);\n await rm(filename);\n await rm(join(location.state, 'service.json'), { force: true });\n await exec('systemctl', ['--user', 'daemon-reload']);\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,OAAO,IAAI,iBAAiB;AACrC,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,cAAc,mBAAoC;AAC3D,SAAS,yBAAyB;AAClC,SAAS,eAAe,gBAAgB,YAAY;AAEpD,MAAM,OAAO,UAAU,QAAQ;AAE/B,eAAsB,QAAQ,UAAsB,SAAkB;AACpE,MAAI,CAAC,CAAC,UAAU,OAAO,EAAE,SAAS,QAAQ,QAAQ;AAChD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,QAAQ,aAAa,SAAS,GAAG;AACvC,QAAM,QAAQ,KAAK,aAAa,eAAe;AAC/C,MAAI,QAAQ,aAAa,UAAU;AACjC,QAAI,QAAS,OAAM,aAAa,QAAQ;AACxC,UAAM,kBAAkB,UAAU,OAAO,OAAO;AAChD;AAAA,EACF;AACA,MAAI,SAAS;AACX,UAAM,YAAY,QAAQ;AAC1B,UAAM,MAAM,SAAS,OAAO,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,EAC9D;AACA,QAAM,YAAY,KAAK,QAAQ,GAAG,sBAAsB;AACxD,QAAM,WAAW,KAAK,WAAW,GAAG,KAAK,UAAU;AACnD,MAAI,SAAS;AACX,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,UAAM,UAAU,MAAM,cAAc,UAAU,KAAK;AACnD,QACE,SAAS;AAAA,MACP,CAAC,QAAQ,MAAM,QAAQ,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,IAAI,EAAE,KAAK,EAAE;AAAA,IACrF;AAEA,YAAM,IAAI,MAAM,0EAAmB;AACrC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA;AAAA;AAAA,YAAmD,CAAC,QAAQ,MAAM,QAAQ,OAAO,OAAO,YAAY,SAAS,MAAM,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG,CAAC;AAAA,cAAiB,KAAK,cAAc,SAAS,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,QAAQ,IAAI,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAC5N,EAAE,MAAM,IAAM;AAAA,IAChB;AACA,UAAM,KAAK,aAAa,CAAC,UAAU,eAAe,CAAC;AACnD,UAAM,KAAK,aAAa,CAAC,UAAU,UAAU,SAAS,GAAG,KAAK,UAAU,CAAC;AACzE,UAAM,SAAS,KAAK,SAAS,OAAO,cAAc,GAAG,EAAE,UAAU,SAAS,MAAM,CAAC;AAAA,EACnF,OAAO;AACL,UAAM,KAAK,aAAa,CAAC,UAAU,WAAW,SAAS,GAAG,KAAK,UAAU,CAAC;AAC1E,UAAM,GAAG,QAAQ;AACjB,UAAM,GAAG,KAAK,SAAS,OAAO,cAAc,GAAG,EAAE,OAAO,KAAK,CAAC;AAC9D,UAAM,KAAK,aAAa,CAAC,UAAU,eAAe,CAAC;AAAA,EACrD;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,132 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { z } from "zod";
3
+ import { CodexError, isRecord } from "./transport.js";
4
+ const nullable = (value) => value.nullish().transform((v) => v ?? null);
5
+ const text = nullable(z.string());
6
+ const number = nullable(z.number().finite());
7
+ const boolean = nullable(z.boolean());
8
+ const timestamp = nullable(z.number().finite().min(0).max(864e10));
9
+ const window = nullable(
10
+ z.object({
11
+ usedPercent: number,
12
+ windowDurationMins: nullable(z.number().finite().nonnegative()),
13
+ resetsAt: timestamp
14
+ })
15
+ );
16
+ const group = z.object({
17
+ limitId: text,
18
+ limitName: text,
19
+ normalModelSlug: text,
20
+ planType: text,
21
+ primary: window,
22
+ secondary: window,
23
+ credits: nullable(z.object({ hasCredits: boolean, unlimited: boolean, balance: text })),
24
+ individualLimit: nullable(
25
+ z.object({
26
+ limit: text,
27
+ used: text,
28
+ remainingPercent: number,
29
+ resetsAt: timestamp
30
+ })
31
+ ),
32
+ spendControlReached: boolean,
33
+ rateLimitReachedType: text
34
+ });
35
+ const response = z.object({
36
+ rateLimits: nullable(group),
37
+ rateLimitsByLimitId: nullable(z.record(z.string(), group)),
38
+ ordinaryUsageAllowed: boolean,
39
+ rateLimitResetCredits: nullable(
40
+ z.object({ availableCount: nullable(z.number().int().nonnegative()) })
41
+ )
42
+ });
43
+ function accountUsageValues(input) {
44
+ const value = response.parse(input);
45
+ const groups = Object.entries(value.rateLimitsByLimitId ?? {}).map(
46
+ ([id, entry]) => ({ ...entry, limitId: entry.limitId ?? id })
47
+ );
48
+ if (value.rateLimits && (!groups.length || value.rateLimits.limitId !== null && !groups.some((entry) => entry.limitId === value.rateLimits?.limitId))) {
49
+ groups.unshift(value.rateLimits);
50
+ }
51
+ return {
52
+ groups,
53
+ ordinaryUsageAllowed: value.ordinaryUsageAllowed,
54
+ resetCreditsAvailable: value.rateLimitResetCredits?.availableCount ?? null
55
+ };
56
+ }
57
+ class AccountUsageReader {
58
+ constructor(source) {
59
+ this.source = source;
60
+ }
61
+ source;
62
+ sequence = 0;
63
+ identity;
64
+ value = this.empty("offline");
65
+ snapshot() {
66
+ return structuredClone(this.value);
67
+ }
68
+ empty(status) {
69
+ return {
70
+ scope: randomUUID(),
71
+ status,
72
+ refreshing: false,
73
+ updatedAt: null,
74
+ groups: [],
75
+ ordinaryUsageAllowed: null,
76
+ resetCreditsAvailable: null
77
+ };
78
+ }
79
+ invalidate(status) {
80
+ this.sequence++;
81
+ this.identity = void 0;
82
+ this.value = this.empty(status);
83
+ this.source.changed();
84
+ }
85
+ async refresh() {
86
+ const sequence = ++this.sequence;
87
+ this.value = { ...this.value, refreshing: true };
88
+ this.source.changed();
89
+ try {
90
+ const result = await this.source.account();
91
+ if (sequence !== this.sequence) return this.snapshot();
92
+ if (!isRecord(result) || !Object.hasOwn(result, "account") || typeof result.requiresOpenaiAuth !== "boolean")
93
+ throw new Error("Invalid account response");
94
+ const identity = JSON.stringify(result.account);
95
+ if (this.identity !== void 0 && identity !== this.identity) {
96
+ this.value = this.empty("loading");
97
+ this.source.changed();
98
+ }
99
+ this.identity = identity;
100
+ this.source.authenticated(result.account !== null || !result.requiresOpenaiAuth);
101
+ if (!result.account) {
102
+ this.value = {
103
+ ...this.empty(result.requiresOpenaiAuth ? "signedOut" : "unsupported"),
104
+ scope: this.value.scope
105
+ };
106
+ } else if (result.account.type !== "chatgpt") {
107
+ this.value = { ...this.empty("unsupported"), scope: this.value.scope };
108
+ } else {
109
+ const values = accountUsageValues(await this.source.limits());
110
+ if (sequence !== this.sequence) return this.snapshot();
111
+ this.value = {
112
+ ...this.value,
113
+ ...values,
114
+ status: "ready",
115
+ refreshing: false,
116
+ updatedAt: Date.now()
117
+ };
118
+ }
119
+ } catch (error) {
120
+ if (sequence !== this.sequence) return this.snapshot();
121
+ const unsupported = error instanceof CodexError && (error.rpcCode === -32601 || error.code === "PROTOCOL_INCOMPATIBLE");
122
+ this.value = unsupported ? { ...this.empty("unsupported"), scope: this.value.scope } : { ...this.value, status: "error", refreshing: false };
123
+ }
124
+ if (sequence === this.sequence) this.source.changed();
125
+ return this.snapshot();
126
+ }
127
+ }
128
+ export {
129
+ AccountUsageReader,
130
+ accountUsageValues
131
+ };
132
+ //# sourceMappingURL=account-usage.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/codex/account-usage.ts"],
4
+ "sourcesContent": ["import { randomUUID } from 'node:crypto';\nimport { z } from 'zod';\nimport type { GetAccountResponse } from './generated/v2/GetAccountResponse.js';\nimport type { AccountUsage, UsageGroup } from '../shared/account-usage.js';\nimport { CodexError, isRecord } from './transport.js';\n\nconst nullable = <T extends z.ZodType>(value: T) => value.nullish().transform((v) => v ?? null);\nconst text = nullable(z.string());\nconst number = nullable(z.number().finite());\nconst boolean = nullable(z.boolean());\nconst timestamp = nullable(z.number().finite().min(0).max(8.64e12));\nconst window = nullable(\n z.object({\n usedPercent: number,\n windowDurationMins: nullable(z.number().finite().nonnegative()),\n resetsAt: timestamp,\n }),\n);\nconst group = z.object({\n limitId: text,\n limitName: text,\n normalModelSlug: text,\n planType: text,\n primary: window,\n secondary: window,\n credits: nullable(z.object({ hasCredits: boolean, unlimited: boolean, balance: text })),\n individualLimit: nullable(\n z.object({\n limit: text,\n used: text,\n remainingPercent: number,\n resetsAt: timestamp,\n }),\n ),\n spendControlReached: boolean,\n rateLimitReachedType: text,\n});\nconst response = z.object({\n rateLimits: nullable(group),\n rateLimitsByLimitId: nullable(z.record(z.string(), group)),\n ordinaryUsageAllowed: boolean,\n rateLimitResetCredits: nullable(\n z.object({ availableCount: nullable(z.number().int().nonnegative()) }),\n ),\n});\n\nexport function accountUsageValues(input: unknown) {\n const value = response.parse(input);\n const groups: UsageGroup[] = Object.entries(value.rateLimitsByLimitId ?? {}).map(\n ([id, entry]) => ({ ...entry, limitId: entry.limitId ?? id }),\n );\n // The legacy bucket mirrors a map entry. Keep it only when it adds a distinct bucket.\n if (\n value.rateLimits &&\n (!groups.length ||\n (value.rateLimits.limitId !== null &&\n !groups.some((entry) => entry.limitId === value.rateLimits?.limitId)))\n ) {\n groups.unshift(value.rateLimits);\n }\n return {\n groups,\n ordinaryUsageAllowed: value.ordinaryUsageAllowed,\n resetCreditsAvailable: value.rateLimitResetCredits?.availableCount ?? null,\n };\n}\n\n/** Owns freshness and identity boundaries. Sparse notifications trigger a full read. */\nexport class AccountUsageReader {\n private sequence = 0;\n private identity?: string;\n private value: AccountUsage = this.empty('offline');\n constructor(\n private readonly source: {\n account: () => Promise<GetAccountResponse>;\n limits: () => Promise<unknown>;\n changed: () => void;\n authenticated: (value: boolean) => void;\n },\n ) {}\n\n snapshot(): AccountUsage {\n return structuredClone(this.value);\n }\n\n private empty(status: AccountUsage['status']): AccountUsage {\n return {\n scope: randomUUID(),\n status,\n refreshing: false,\n updatedAt: null,\n groups: [],\n ordinaryUsageAllowed: null,\n resetCreditsAvailable: null,\n };\n }\n\n invalidate(status: 'offline' | 'loading'): void {\n this.sequence++;\n this.identity = undefined;\n this.value = this.empty(status);\n this.source.changed();\n }\n\n async refresh(): Promise<AccountUsage> {\n const sequence = ++this.sequence;\n this.value = { ...this.value, refreshing: true };\n this.source.changed();\n try {\n const result = await this.source.account();\n if (sequence !== this.sequence) return this.snapshot();\n if (\n !isRecord(result) ||\n !Object.hasOwn(result, 'account') ||\n typeof result.requiresOpenaiAuth !== 'boolean'\n )\n throw new Error('Invalid account response');\n const identity = JSON.stringify(result.account);\n if (this.identity !== undefined && identity !== this.identity) {\n this.value = this.empty('loading');\n this.source.changed();\n }\n this.identity = identity;\n this.source.authenticated(result.account !== null || !result.requiresOpenaiAuth);\n if (!result.account) {\n this.value = {\n ...this.empty(result.requiresOpenaiAuth ? 'signedOut' : 'unsupported'),\n scope: this.value.scope,\n };\n } else if (result.account.type !== 'chatgpt') {\n this.value = { ...this.empty('unsupported'), scope: this.value.scope };\n } else {\n const values = accountUsageValues(await this.source.limits());\n if (sequence !== this.sequence) return this.snapshot();\n this.value = {\n ...this.value,\n ...values,\n status: 'ready',\n refreshing: false,\n updatedAt: Date.now(),\n };\n }\n } catch (error) {\n if (sequence !== this.sequence) return this.snapshot();\n const unsupported =\n error instanceof CodexError &&\n (error.rpcCode === -32601 || error.code === 'PROTOCOL_INCOMPATIBLE');\n this.value = unsupported\n ? { ...this.empty('unsupported'), scope: this.value.scope }\n : { ...this.value, status: 'error', refreshing: false };\n }\n if (sequence === this.sequence) this.source.changed();\n return this.snapshot();\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,4 +1,5 @@
1
1
  import { CODEX_COMPATIBILITY } from "./compatibility.js";
2
+ import { AccountUsageReader } from "./account-usage.js";
2
3
  import { SHELL_TIMEOUT_MS, SHELL_OUTPUT_BYTES } from "../shared/shell.js";
3
4
  import { spawn, execFile } from "node:child_process";
4
5
  import { randomUUID } from "node:crypto";
@@ -67,11 +68,13 @@ const CAPABILITIES = [
67
68
  "turn/steer",
68
69
  "turn/interrupt",
69
70
  "model/list",
71
+ "skills/list",
70
72
  "config/read",
71
73
  "config/batchWrite",
72
74
  "configRequirements/read",
73
75
  "experimentalFeature/list",
74
- "account/read"
76
+ "account/read",
77
+ "account/rateLimits/read"
75
78
  ];
76
79
  function permissionPathLabel(path) {
77
80
  if (path.type === "path") return path.path;
@@ -98,6 +101,21 @@ class CodexAdapter {
98
101
  this.options = options;
99
102
  }
100
103
  options;
104
+ accountUsage = new AccountUsageReader({
105
+ account: () => this.call("account/read", { refreshToken: false }),
106
+ limits: () => this.call("account/rateLimits/read", { excludeResetCreditDetails: true }),
107
+ changed: () => this.publishRuntime(),
108
+ authenticated: (value) => {
109
+ this.state.authenticated = value;
110
+ }
111
+ });
112
+ async refreshAccountUsage() {
113
+ if (!this.ready) {
114
+ this.accountUsage.invalidate("offline");
115
+ return this.accountUsage.snapshot();
116
+ }
117
+ return this.accountUsage.refresh();
118
+ }
101
119
  commandOutputs = /* @__PURE__ */ new Map();
102
120
  epoch = randomUUID();
103
121
  child;
@@ -137,7 +155,7 @@ class CodexAdapter {
137
155
  return this.state.ready;
138
156
  }
139
157
  diagnostics() {
140
- return structuredClone(this.state);
158
+ return { ...structuredClone(this.state), accountUsage: this.accountUsage.snapshot() };
141
159
  }
142
160
  onEvent(listener) {
143
161
  this.listeners.add(listener);
@@ -172,6 +190,7 @@ class CodexAdapter {
172
190
  error: void 0,
173
191
  capabilities: []
174
192
  };
193
+ this.accountUsage.invalidate("loading");
175
194
  this.publishRuntime();
176
195
  try {
177
196
  const env = {
@@ -235,6 +254,7 @@ class CodexAdapter {
235
254
  this.tokenUsage.clear();
236
255
  this.denials.clear();
237
256
  this.state.connection = "unavailable";
257
+ this.accountUsage.invalidate("offline");
238
258
  this.state.error = error.message;
239
259
  this.expireActions();
240
260
  this.publishRuntime();
@@ -319,6 +339,7 @@ class CodexAdapter {
319
339
  this.state.connection = "ready";
320
340
  this.state.capabilities = CAPABILITIES.filter((method) => !this.disabled.has(method));
321
341
  this.publishRuntime();
342
+ void this.refreshAccountUsage();
322
343
  } catch (error) {
323
344
  const failure = asCodexError(error);
324
345
  this.state.ready = false;
@@ -332,6 +353,7 @@ class CodexAdapter {
332
353
  }
333
354
  async stop() {
334
355
  this.stopped = true;
356
+ this.accountUsage.invalidate("offline");
335
357
  clearTimeout(this.restartTimer);
336
358
  this.restartTimer = void 0;
337
359
  await this.starting?.catch(() => {
@@ -855,7 +877,18 @@ class CodexAdapter {
855
877
  );
856
878
  }
857
879
  }
858
- async startTurn(id, cwd, text, settings, images) {
880
+ async listSkills(cwd, forceReload = false) {
881
+ const result = await this.call("skills/list", { cwds: [cwd], forceReload });
882
+ const entries = result.data.filter((entry) => entry.cwd === cwd);
883
+ if (entries.length !== 1)
884
+ throw new AppError(
885
+ "SKILLS_READ_FAILED",
886
+ "Codex returned no unambiguous skill catalog for this directory",
887
+ 502
888
+ );
889
+ return entries[0];
890
+ }
891
+ async startTurn(id, cwd, text, settings, images, skills) {
859
892
  this.validateSettings(settings);
860
893
  await this.validatePermissionSettings(cwd, settings, id);
861
894
  const turn = mapTurn(
@@ -863,7 +896,7 @@ class CodexAdapter {
863
896
  (await this.call("turn/start", {
864
897
  threadId: id,
865
898
  cwd,
866
- input: taskInput(text, images),
899
+ input: taskInput(text, images, skills),
867
900
  ...turnSettings(cwd, settings),
868
901
  ...collaborationSelection(settings, this.permissionState.get(id))
869
902
  })).turn
@@ -959,6 +992,14 @@ class CodexAdapter {
959
992
  const event = message;
960
993
  const p = event.params;
961
994
  switch (event.method) {
995
+ case "account/updated":
996
+ this.state.authenticated = null;
997
+ this.accountUsage.invalidate("loading");
998
+ if (this.ready) void this.refreshAccountUsage();
999
+ break;
1000
+ case "account/rateLimits/updated":
1001
+ if (this.ready) void this.refreshAccountUsage();
1002
+ break;
962
1003
  case "command/exec/outputDelta": {
963
1004
  const { processId, stream, deltaBase64, capReached } = event.params;
964
1005
  this.commandOutputs.get(processId)?.(