@rulemetric/cli 0.2.1 → 0.2.2
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.
- package/dist/base-command.js +13 -52
- package/dist/base-command.js.map +7 -1
- package/dist/chunk-2AM54TUK.js +59 -0
- package/dist/chunk-2AM54TUK.js.map +7 -0
- package/dist/chunk-3TIMQ3O6.js +96 -0
- package/dist/chunk-3TIMQ3O6.js.map +7 -0
- package/dist/chunk-4BHDHHKL.js +48 -0
- package/dist/chunk-4BHDHHKL.js.map +7 -0
- package/dist/chunk-4D537GXE.js +99 -0
- package/dist/chunk-4D537GXE.js.map +7 -0
- package/dist/chunk-4SCZK7AL.js +129 -0
- package/dist/chunk-4SCZK7AL.js.map +7 -0
- package/dist/chunk-4WFE4PFP.js +61 -0
- package/dist/chunk-4WFE4PFP.js.map +7 -0
- package/dist/chunk-52WIYRZH.js +73 -0
- package/dist/chunk-52WIYRZH.js.map +7 -0
- package/dist/chunk-7FAA3YNB.js +1549 -0
- package/dist/chunk-7FAA3YNB.js.map +7 -0
- package/dist/chunk-7NYKWN7U.js +12 -0
- package/dist/chunk-7NYKWN7U.js.map +7 -0
- package/dist/chunk-AULP2OWH.js +99 -0
- package/dist/chunk-AULP2OWH.js.map +7 -0
- package/dist/chunk-B5KNTGMJ.js +1788 -0
- package/dist/chunk-B5KNTGMJ.js.map +7 -0
- package/dist/chunk-BD7CY42U.js +23 -0
- package/dist/chunk-BD7CY42U.js.map +7 -0
- package/dist/chunk-BO76WKJR.js +42 -0
- package/dist/chunk-BO76WKJR.js.map +7 -0
- package/dist/chunk-BRD5RUGM.js +53 -0
- package/dist/chunk-BRD5RUGM.js.map +7 -0
- package/dist/chunk-BT6Z6545.js +43 -0
- package/dist/chunk-BT6Z6545.js.map +7 -0
- package/dist/chunk-BZDKEQKU.js +39 -0
- package/dist/chunk-BZDKEQKU.js.map +7 -0
- package/dist/chunk-CROYS75W.js +161 -0
- package/dist/chunk-CROYS75W.js.map +7 -0
- package/dist/chunk-DGHWRQXL.js +17 -0
- package/dist/chunk-DGHWRQXL.js.map +7 -0
- package/dist/chunk-DQ3KELXD.js +74 -0
- package/dist/chunk-DQ3KELXD.js.map +7 -0
- package/dist/chunk-DTFXCHHI.js +108 -0
- package/dist/chunk-DTFXCHHI.js.map +7 -0
- package/dist/chunk-DU73QUS3.js +75 -0
- package/dist/chunk-DU73QUS3.js.map +7 -0
- package/dist/chunk-EHZJ6OXD.js +307 -0
- package/dist/chunk-EHZJ6OXD.js.map +7 -0
- package/dist/chunk-EJOI2ZGU.js +109 -0
- package/dist/chunk-EJOI2ZGU.js.map +7 -0
- package/dist/chunk-EKJ2CABV.js +76 -0
- package/dist/chunk-EKJ2CABV.js.map +7 -0
- package/dist/chunk-EKP32DLN.js +16 -0
- package/dist/chunk-EKP32DLN.js.map +7 -0
- package/dist/chunk-EOOP6WTC.js +148 -0
- package/dist/chunk-EOOP6WTC.js.map +7 -0
- package/dist/chunk-ERPMDAO3.js +20 -0
- package/dist/chunk-ERPMDAO3.js.map +7 -0
- package/dist/chunk-FTJRMUID.js +96 -0
- package/dist/chunk-FTJRMUID.js.map +7 -0
- package/dist/chunk-FZKLLNDS.js +228 -0
- package/dist/chunk-FZKLLNDS.js.map +7 -0
- package/dist/chunk-GQCISMAH.js +157 -0
- package/dist/chunk-GQCISMAH.js.map +7 -0
- package/dist/chunk-IGXX624H.js +55 -0
- package/dist/chunk-IGXX624H.js.map +7 -0
- package/dist/chunk-IJGF2ETG.js +68 -0
- package/dist/chunk-IJGF2ETG.js.map +7 -0
- package/dist/chunk-IWYCRLEK.js +220 -0
- package/dist/chunk-IWYCRLEK.js.map +7 -0
- package/dist/chunk-J7N3DLH6.js +117 -0
- package/dist/chunk-J7N3DLH6.js.map +7 -0
- package/dist/chunk-JX5UI6RW.js +99 -0
- package/dist/chunk-JX5UI6RW.js.map +7 -0
- package/dist/chunk-K3BFZ7KG.js +154 -0
- package/dist/chunk-K3BFZ7KG.js.map +7 -0
- package/dist/chunk-KHJUQFIK.js +51 -0
- package/dist/chunk-KHJUQFIK.js.map +7 -0
- package/dist/chunk-KRBQLMOP.js +41 -0
- package/dist/chunk-KRBQLMOP.js.map +7 -0
- package/dist/chunk-KZRFUXGF.js +145 -0
- package/dist/chunk-KZRFUXGF.js.map +7 -0
- package/dist/chunk-L674RNKQ.js +492 -0
- package/dist/chunk-L674RNKQ.js.map +7 -0
- package/dist/chunk-N52AHNBH.js +47 -0
- package/dist/chunk-N52AHNBH.js.map +7 -0
- package/dist/chunk-NIDLJO6F.js +228 -0
- package/dist/chunk-NIDLJO6F.js.map +7 -0
- package/dist/chunk-NSBPE2FW.js +17 -0
- package/dist/chunk-NSBPE2FW.js.map +7 -0
- package/dist/chunk-OGVORIFM.js +70 -0
- package/dist/chunk-OGVORIFM.js.map +7 -0
- package/dist/chunk-OQSQC7VB.js +77 -0
- package/dist/chunk-OQSQC7VB.js.map +7 -0
- package/dist/chunk-PHLMIZKM.js +153 -0
- package/dist/chunk-PHLMIZKM.js.map +7 -0
- package/dist/chunk-PQU7GZ7A.js +92 -0
- package/dist/chunk-PQU7GZ7A.js.map +7 -0
- package/dist/chunk-PXVQLD7S.js +196 -0
- package/dist/chunk-PXVQLD7S.js.map +7 -0
- package/dist/chunk-QD6X4L4L.js +79 -0
- package/dist/chunk-QD6X4L4L.js.map +7 -0
- package/dist/chunk-QJQS6TUN.js +44 -0
- package/dist/chunk-QJQS6TUN.js.map +7 -0
- package/dist/chunk-QJXAULRC.js +191 -0
- package/dist/chunk-QJXAULRC.js.map +7 -0
- package/dist/chunk-QN34TGD3.js +83 -0
- package/dist/chunk-QN34TGD3.js.map +7 -0
- package/dist/chunk-R5MFHGHR.js +122 -0
- package/dist/chunk-R5MFHGHR.js.map +7 -0
- package/dist/chunk-RH7NHVSK.js +16 -0
- package/dist/chunk-RH7NHVSK.js.map +7 -0
- package/dist/chunk-RJ7BHDLM.js +121 -0
- package/dist/chunk-RJ7BHDLM.js.map +7 -0
- package/dist/chunk-RQ2TMLKG.js +142 -0
- package/dist/chunk-RQ2TMLKG.js.map +7 -0
- package/dist/chunk-S56LOTGQ.js +63 -0
- package/dist/chunk-S56LOTGQ.js.map +7 -0
- package/dist/chunk-UF73WX2J.js +49 -0
- package/dist/chunk-UF73WX2J.js.map +7 -0
- package/dist/chunk-W53GKIZQ.js +50 -0
- package/dist/chunk-W53GKIZQ.js.map +7 -0
- package/dist/chunk-WA4MWYRW.js +254 -0
- package/dist/chunk-WA4MWYRW.js.map +7 -0
- package/dist/chunk-WFULKPEQ.js +269 -0
- package/dist/chunk-WFULKPEQ.js.map +7 -0
- package/dist/chunk-XC6M4CSW.js +44 -0
- package/dist/chunk-XC6M4CSW.js.map +7 -0
- package/dist/chunk-XPUEGHXN.js +243 -0
- package/dist/chunk-XPUEGHXN.js.map +7 -0
- package/dist/chunk-XZXS2W24.js +148 -0
- package/dist/chunk-XZXS2W24.js.map +7 -0
- package/dist/chunk-YBNW7ARH.js +167 -0
- package/dist/chunk-YBNW7ARH.js.map +7 -0
- package/dist/chunk-YNIH3KMU.js +121 -0
- package/dist/chunk-YNIH3KMU.js.map +7 -0
- package/dist/commands/antigravity/backfill.js +135 -0
- package/dist/commands/antigravity/backfill.js.map +7 -0
- package/dist/commands/auth/create-key.js +48 -33
- package/dist/commands/auth/create-key.js.map +7 -1
- package/dist/commands/auth/login.js +58 -46
- package/dist/commands/auth/login.js.map +7 -1
- package/dist/commands/auth/logout.js +28 -13
- package/dist/commands/auth/logout.js.map +7 -1
- package/dist/commands/auth/revoke-key.js +32 -18
- package/dist/commands/auth/revoke-key.js.map +7 -1
- package/dist/commands/auth/status.js +40 -22
- package/dist/commands/auth/status.js.map +7 -1
- package/dist/commands/catalog/index.js +50 -34
- package/dist/commands/catalog/index.js.map +7 -1
- package/dist/commands/catalog/recommend.js +41 -26
- package/dist/commands/catalog/recommend.js.map +7 -1
- package/dist/commands/convert.js +72 -54
- package/dist/commands/convert.js.map +7 -1
- package/dist/commands/converters.js +52 -38
- package/dist/commands/converters.js.map +7 -1
- package/dist/commands/crons/list.js +50 -24
- package/dist/commands/crons/list.js.map +7 -1
- package/dist/commands/crons/run.js +72 -47
- package/dist/commands/crons/run.js.map +7 -1
- package/dist/commands/dashboard.js +45 -24
- package/dist/commands/dashboard.js.map +7 -1
- package/dist/commands/eval-targets/create.js +51 -39
- package/dist/commands/eval-targets/create.js.map +7 -1
- package/dist/commands/eval-targets/list.js +52 -35
- package/dist/commands/eval-targets/list.js.map +7 -1
- package/dist/commands/evals/agent.js +292 -0
- package/dist/commands/evals/agent.js.map +7 -0
- package/dist/commands/evals/benchmark.js +70 -51
- package/dist/commands/evals/benchmark.js.map +7 -1
- package/dist/commands/evals/compare.js +90 -78
- package/dist/commands/evals/compare.js.map +7 -1
- package/dist/commands/evals/create.js +64 -50
- package/dist/commands/evals/create.js.map +7 -1
- package/dist/commands/evals/optimize-description.js +225 -222
- package/dist/commands/evals/optimize-description.js.map +7 -1
- package/dist/commands/evals/optimize.js +206 -196
- package/dist/commands/evals/optimize.js.map +7 -1
- package/dist/commands/evals/run.js +178 -164
- package/dist/commands/evals/run.js.map +7 -1
- package/dist/commands/gateway/ensure.js +33 -19
- package/dist/commands/gateway/ensure.js.map +7 -1
- package/dist/commands/hooks/install.js +335 -275
- package/dist/commands/hooks/install.js.map +7 -1
- package/dist/commands/hooks/run.js +72 -53
- package/dist/commands/hooks/run.js.map +7 -1
- package/dist/commands/hooks/uninstall.js +117 -94
- package/dist/commands/hooks/uninstall.js.map +7 -1
- package/dist/commands/import.js +63 -53
- package/dist/commands/import.js.map +7 -1
- package/dist/commands/instructions/create.js +71 -58
- package/dist/commands/instructions/create.js.map +7 -1
- package/dist/commands/instructions/delete.js +53 -36
- package/dist/commands/instructions/delete.js.map +7 -1
- package/dist/commands/instructions/fork.js +33 -19
- package/dist/commands/instructions/fork.js.map +7 -1
- package/dist/commands/instructions/get.js +66 -49
- package/dist/commands/instructions/get.js.map +7 -1
- package/dist/commands/instructions/list.js +63 -46
- package/dist/commands/instructions/list.js.map +7 -1
- package/dist/commands/instructions/promote.js +41 -27
- package/dist/commands/instructions/promote.js.map +7 -1
- package/dist/commands/instructions/pull.js +37 -21
- package/dist/commands/instructions/pull.js.map +7 -1
- package/dist/commands/instructions/upstream.js +36 -21
- package/dist/commands/instructions/upstream.js.map +7 -1
- package/dist/commands/instructions/versions.js +51 -33
- package/dist/commands/instructions/versions.js.map +7 -1
- package/dist/commands/launcher.js +39 -0
- package/dist/commands/launcher.js.map +7 -0
- package/dist/commands/org/current.js +74 -68
- package/dist/commands/org/current.js.map +7 -1
- package/dist/commands/org/list.js +50 -36
- package/dist/commands/org/list.js.map +7 -1
- package/dist/commands/org/switch.js +69 -51
- package/dist/commands/org/switch.js.map +7 -1
- package/dist/commands/packs/add-instruction.js +36 -22
- package/dist/commands/packs/add-instruction.js.map +7 -1
- package/dist/commands/packs/apply.js +38 -24
- package/dist/commands/packs/apply.js.map +7 -1
- package/dist/commands/packs/create.js +47 -33
- package/dist/commands/packs/create.js.map +7 -1
- package/dist/commands/packs/fork.js +33 -19
- package/dist/commands/packs/fork.js.map +7 -1
- package/dist/commands/packs/get.js +54 -35
- package/dist/commands/packs/get.js.map +7 -1
- package/dist/commands/packs/list.js +64 -47
- package/dist/commands/packs/list.js.map +7 -1
- package/dist/commands/packs/remove-instruction.js +34 -20
- package/dist/commands/packs/remove-instruction.js.map +7 -1
- package/dist/commands/proxy/env.js +126 -116
- package/dist/commands/proxy/env.js.map +7 -1
- package/dist/commands/proxy/logs.js +83 -74
- package/dist/commands/proxy/logs.js.map +7 -1
- package/dist/commands/proxy/restart.js +34 -36
- package/dist/commands/proxy/restart.js.map +7 -1
- package/dist/commands/proxy/setup.js +432 -375
- package/dist/commands/proxy/setup.js.map +7 -1
- package/dist/commands/proxy/start.js +289 -289
- package/dist/commands/proxy/start.js.map +7 -1
- package/dist/commands/proxy/status.js +74 -64
- package/dist/commands/proxy/status.js.map +7 -1
- package/dist/commands/proxy/stop.js +81 -75
- package/dist/commands/proxy/stop.js.map +7 -1
- package/dist/commands/research/backfill.js +58 -0
- package/dist/commands/research/backfill.js.map +7 -0
- package/dist/commands/research/tail-transcript.js +69 -0
- package/dist/commands/research/tail-transcript.js.map +7 -0
- package/dist/commands/service/install.js +639 -405
- package/dist/commands/service/install.js.map +7 -1
- package/dist/commands/service/status.js +178 -111
- package/dist/commands/service/status.js.map +7 -1
- package/dist/commands/service/uninstall.js +85 -110
- package/dist/commands/service/uninstall.js.map +7 -1
- package/dist/commands/sessions/analyze.js +46 -25
- package/dist/commands/sessions/analyze.js.map +7 -1
- package/dist/commands/sessions/end.js +81 -79
- package/dist/commands/sessions/end.js.map +7 -1
- package/dist/commands/sessions/import.js +44 -27
- package/dist/commands/sessions/import.js.map +7 -1
- package/dist/commands/sessions/list.js +46 -33
- package/dist/commands/sessions/list.js.map +7 -1
- package/dist/commands/sessions/start.js +88 -87
- package/dist/commands/sessions/start.js.map +7 -1
- package/dist/commands/signals/report.js +42 -34
- package/dist/commands/signals/report.js.map +7 -1
- package/dist/commands/skills/export-approved.js +44 -30
- package/dist/commands/skills/export-approved.js.map +7 -1
- package/dist/commands/skills/install.js +99 -84
- package/dist/commands/skills/install.js.map +7 -1
- package/dist/commands/skills/list.js +59 -42
- package/dist/commands/skills/list.js.map +7 -1
- package/dist/commands/skills/publish.js +95 -78
- package/dist/commands/skills/publish.js.map +7 -1
- package/dist/commands/skills/search.js +68 -53
- package/dist/commands/skills/search.js.map +7 -1
- package/dist/commands/skills/update.js +52 -39
- package/dist/commands/skills/update.js.map +7 -1
- package/dist/commands/suggestions/accept.js +82 -59
- package/dist/commands/suggestions/accept.js.map +7 -1
- package/dist/commands/suggestions/dismiss.js +44 -26
- package/dist/commands/suggestions/dismiss.js.map +7 -1
- package/dist/commands/suggestions/list.js +59 -39
- package/dist/commands/suggestions/list.js.map +7 -1
- package/dist/commands/suggestions/refresh.js +26 -11
- package/dist/commands/suggestions/refresh.js.map +7 -1
- package/dist/cursor-BGQJ4CWI.js +134 -0
- package/dist/cursor-BGQJ4CWI.js.map +7 -0
- package/dist/dashboard/Dashboard.js +229 -126
- package/dist/dashboard/Dashboard.js.map +7 -1
- package/dist/dashboard/data.js +13 -137
- package/dist/dashboard/data.js.map +7 -1
- package/dist/dashboard/launcher/ActiveJobsList.js +10 -0
- package/dist/dashboard/launcher/ActiveJobsList.js.map +7 -0
- package/dist/dashboard/launcher/LauncherOverlay.js +14 -0
- package/dist/dashboard/launcher/LauncherOverlay.js.map +7 -0
- package/dist/dashboard/launcher/NewLaunchForm.js +10 -0
- package/dist/dashboard/launcher/NewLaunchForm.js.map +7 -0
- package/dist/dashboard/launcher/api.js +14 -0
- package/dist/dashboard/launcher/api.js.map +7 -0
- package/dist/dashboard/launcher/tool-labels.js +10 -0
- package/dist/dashboard/launcher/tool-labels.js.map +7 -0
- package/dist/dashboard/launcher/types.js +1 -0
- package/dist/dashboard/launcher/types.js.map +7 -0
- package/dist/dashboard/launcher/useLaunchJobs.js +9 -0
- package/dist/dashboard/launcher/useLaunchJobs.js.map +7 -0
- package/dist/dashboard/panels/friction.js +10 -22
- package/dist/dashboard/panels/friction.js.map +7 -1
- package/dist/dashboard/panels/insights.js +10 -109
- package/dist/dashboard/panels/insights.js.map +7 -1
- package/dist/dashboard/panels/instructions.js +10 -17
- package/dist/dashboard/panels/instructions.js.map +7 -1
- package/dist/dashboard/panels/outcomes.js +9 -28
- package/dist/dashboard/panels/outcomes.js.map +7 -1
- package/dist/dashboard/panels/overview.js +10 -20
- package/dist/dashboard/panels/overview.js.map +7 -1
- package/dist/dashboard/panels/shared.js +18 -61
- package/dist/dashboard/panels/shared.js.map +7 -1
- package/dist/dashboard/types.js +23 -26
- package/dist/dashboard/types.js.map +7 -1
- package/dist/dist-CSUYFYKI.js +52 -0
- package/dist/dist-CSUYFYKI.js.map +7 -0
- package/dist/index.js +8 -2
- package/dist/index.js.map +7 -1
- package/dist/lib/active-org-refresh.js +15 -108
- package/dist/lib/active-org-refresh.js.map +7 -1
- package/dist/lib/active-org.js +15 -95
- package/dist/lib/active-org.js.map +7 -1
- package/dist/lib/agent-loop.js +44 -0
- package/dist/lib/agent-loop.js.map +7 -0
- package/dist/lib/antigravity-transcript.js +22 -0
- package/dist/lib/antigravity-transcript.js.map +7 -0
- package/dist/lib/api-client.js +21 -92
- package/dist/lib/api-client.js.map +7 -1
- package/dist/lib/auth.js +26 -137
- package/dist/lib/auth.js.map +7 -1
- package/dist/lib/detect-languages.js +8 -113
- package/dist/lib/detect-languages.js.map +7 -1
- package/dist/lib/detect-tmux.js +9 -0
- package/dist/lib/detect-tmux.js.map +7 -0
- package/dist/lib/eval-analyzer.js +9 -89
- package/dist/lib/eval-analyzer.js.map +7 -1
- package/dist/lib/eval-benchmark.js +12 -92
- package/dist/lib/eval-benchmark.js.map +7 -1
- package/dist/lib/eval-conversation-handler.js +13 -200
- package/dist/lib/eval-conversation-handler.js.map +7 -1
- package/dist/lib/eval-executor.js +8 -83
- package/dist/lib/eval-executor.js.map +7 -1
- package/dist/lib/eval-grader.js +9 -123
- package/dist/lib/eval-grader.js.map +7 -1
- package/dist/lib/eval-meta-judge.js +9 -116
- package/dist/lib/eval-meta-judge.js.map +7 -1
- package/dist/lib/eval-trigger-tester.js +11 -96
- package/dist/lib/eval-trigger-tester.js.map +7 -1
- package/dist/lib/eval-worktree.js +8 -87
- package/dist/lib/eval-worktree.js.map +7 -1
- package/dist/lib/gateway-entry.js +20 -18
- package/dist/lib/gateway-entry.js.map +7 -1
- package/dist/lib/gateway-lifecycle.js +22 -97
- package/dist/lib/gateway-lifecycle.js.map +7 -1
- package/dist/lib/gateway.js +12 -216
- package/dist/lib/gateway.js.map +7 -1
- package/dist/lib/handlers/cron-close-stale-sessions.js +18 -7
- package/dist/lib/handlers/cron-close-stale-sessions.js.map +7 -1
- package/dist/lib/handlers/cron-data-integrity-audit.js +21 -15
- package/dist/lib/handlers/cron-data-integrity-audit.js.map +7 -1
- package/dist/lib/handlers/cron-refresh-skills.js +7 -90
- package/dist/lib/handlers/cron-refresh-skills.js.map +7 -1
- package/dist/lib/handlers/cron-suggest-instructions.js +14 -158
- package/dist/lib/handlers/cron-suggest-instructions.js.map +7 -1
- package/dist/lib/handlers/process-announcement.js +11 -0
- package/dist/lib/handlers/process-announcement.js.map +7 -0
- package/dist/lib/handlers/process-changelog.js +11 -0
- package/dist/lib/handlers/process-changelog.js.map +7 -0
- package/dist/lib/handlers/process-conversation.js +14 -35
- package/dist/lib/handlers/process-conversation.js.map +7 -1
- package/dist/lib/handlers/process-eval.js +15 -207
- package/dist/lib/handlers/process-eval.js.map +7 -1
- package/dist/lib/handlers/process-insights.js +14 -300
- package/dist/lib/handlers/process-insights.js.map +7 -1
- package/dist/lib/handlers/process-launch.js +16 -41
- package/dist/lib/handlers/process-launch.js.map +7 -1
- package/dist/lib/handlers/process-run-cleanup.js +13 -0
- package/dist/lib/handlers/process-run-cleanup.js.map +7 -0
- package/dist/lib/handlers/process-send-message.js +10 -0
- package/dist/lib/handlers/process-send-message.js.map +7 -0
- package/dist/lib/handlers/process-session-goal.js +11 -74
- package/dist/lib/handlers/process-session-goal.js.map +7 -1
- package/dist/lib/hooks-config.js +52 -544
- package/dist/lib/hooks-config.js.map +7 -1
- package/dist/lib/insights-prompts.js +12 -145
- package/dist/lib/insights-prompts.js.map +7 -1
- package/dist/lib/job-helpers.js +1 -0
- package/dist/lib/job-helpers.js.map +7 -0
- package/dist/lib/llm-client.js +16 -274
- package/dist/lib/llm-client.js.map +7 -1
- package/dist/lib/manual-tasks.js +22 -0
- package/dist/lib/manual-tasks.js.map +7 -0
- package/dist/lib/output.js +12 -36
- package/dist/lib/output.js.map +7 -1
- package/dist/lib/permanent-job-error.js +10 -23
- package/dist/lib/permanent-job-error.js.map +7 -1
- package/dist/lib/provider-aggregator.js +57 -55
- package/dist/lib/provider-aggregator.js.map +7 -1
- package/dist/lib/research-client.js +12 -0
- package/dist/lib/research-client.js.map +7 -0
- package/dist/lib/skills-loader.js +8 -51
- package/dist/lib/skills-loader.js.map +7 -1
- package/dist/lib/statusline-shim.js +16 -0
- package/dist/lib/statusline-shim.js.map +7 -0
- package/dist/lib/terminal-target-heartbeat.js +15 -0
- package/dist/lib/terminal-target-heartbeat.js.map +7 -0
- package/dist/lib/tmux.js +16 -0
- package/dist/lib/tmux.js.map +7 -0
- package/dist/lib/transcript-rate-limit-watcher.js +22 -0
- package/dist/lib/transcript-rate-limit-watcher.js.map +7 -0
- package/dist/lib/types.js +8 -7
- package/dist/lib/types.js.map +7 -1
- package/dist/lib/version-check.js +10 -106
- package/dist/lib/version-check.js.map +7 -1
- package/dist/lib/which.js +8 -0
- package/dist/lib/which.js.map +7 -0
- package/dist/lib/worktree.js +17 -0
- package/dist/lib/worktree.js.map +7 -0
- package/dist/opencode-IQ7X5YMJ.js +190 -0
- package/dist/opencode-IQ7X5YMJ.js.map +7 -0
- package/oclif.manifest.json +299 -66
- package/package.json +27 -11
- package/dist/base-command.d.ts +0 -12
- package/dist/base-command.d.ts.map +0 -1
- package/dist/commands/auth/create-key.d.ts +0 -11
- package/dist/commands/auth/create-key.d.ts.map +0 -1
- package/dist/commands/auth/login.d.ts +0 -11
- package/dist/commands/auth/login.d.ts.map +0 -1
- package/dist/commands/auth/logout.d.ts +0 -7
- package/dist/commands/auth/logout.d.ts.map +0 -1
- package/dist/commands/auth/revoke-key.d.ts +0 -10
- package/dist/commands/auth/revoke-key.d.ts.map +0 -1
- package/dist/commands/auth/status.d.ts +0 -7
- package/dist/commands/auth/status.d.ts.map +0 -1
- package/dist/commands/catalog/index.d.ts +0 -11
- package/dist/commands/catalog/index.d.ts.map +0 -1
- package/dist/commands/catalog/recommend.d.ts +0 -9
- package/dist/commands/catalog/recommend.d.ts.map +0 -1
- package/dist/commands/convert.d.ts +0 -15
- package/dist/commands/convert.d.ts.map +0 -1
- package/dist/commands/converters.d.ts +0 -12
- package/dist/commands/converters.d.ts.map +0 -1
- package/dist/commands/crons/list.d.ts +0 -7
- package/dist/commands/crons/list.d.ts.map +0 -1
- package/dist/commands/crons/run.d.ts +0 -13
- package/dist/commands/crons/run.d.ts.map +0 -1
- package/dist/commands/dashboard.d.ts +0 -10
- package/dist/commands/dashboard.d.ts.map +0 -1
- package/dist/commands/eval-targets/create.d.ts +0 -14
- package/dist/commands/eval-targets/create.d.ts.map +0 -1
- package/dist/commands/eval-targets/list.d.ts +0 -10
- package/dist/commands/eval-targets/list.d.ts.map +0 -1
- package/dist/commands/evals/benchmark.d.ts +0 -13
- package/dist/commands/evals/benchmark.d.ts.map +0 -1
- package/dist/commands/evals/compare.d.ts +0 -15
- package/dist/commands/evals/compare.d.ts.map +0 -1
- package/dist/commands/evals/create.d.ts +0 -17
- package/dist/commands/evals/create.d.ts.map +0 -1
- package/dist/commands/evals/listen.d.ts +0 -37
- package/dist/commands/evals/listen.d.ts.map +0 -1
- package/dist/commands/evals/listen.js +0 -188
- package/dist/commands/evals/listen.js.map +0 -1
- package/dist/commands/evals/listen.test.d.ts +0 -2
- package/dist/commands/evals/listen.test.d.ts.map +0 -1
- package/dist/commands/evals/listen.test.js +0 -48
- package/dist/commands/evals/listen.test.js.map +0 -1
- package/dist/commands/evals/optimize-description.d.ts +0 -22
- package/dist/commands/evals/optimize-description.d.ts.map +0 -1
- package/dist/commands/evals/optimize.d.ts +0 -22
- package/dist/commands/evals/optimize.d.ts.map +0 -1
- package/dist/commands/evals/run.d.ts +0 -21
- package/dist/commands/evals/run.d.ts.map +0 -1
- package/dist/commands/gateway/ensure.d.ts +0 -7
- package/dist/commands/gateway/ensure.d.ts.map +0 -1
- package/dist/commands/hooks/install.d.ts +0 -16
- package/dist/commands/hooks/install.d.ts.map +0 -1
- package/dist/commands/hooks/run.d.ts +0 -11
- package/dist/commands/hooks/run.d.ts.map +0 -1
- package/dist/commands/hooks/uninstall.d.ts +0 -7
- package/dist/commands/hooks/uninstall.d.ts.map +0 -1
- package/dist/commands/import.d.ts +0 -17
- package/dist/commands/import.d.ts.map +0 -1
- package/dist/commands/instructions/create.d.ts +0 -17
- package/dist/commands/instructions/create.d.ts.map +0 -1
- package/dist/commands/instructions/delete.d.ts +0 -13
- package/dist/commands/instructions/delete.d.ts.map +0 -1
- package/dist/commands/instructions/fork.d.ts +0 -10
- package/dist/commands/instructions/fork.d.ts.map +0 -1
- package/dist/commands/instructions/get.d.ts +0 -15
- package/dist/commands/instructions/get.d.ts.map +0 -1
- package/dist/commands/instructions/list.d.ts +0 -12
- package/dist/commands/instructions/list.d.ts.map +0 -1
- package/dist/commands/instructions/promote.d.ts +0 -14
- package/dist/commands/instructions/promote.d.ts.map +0 -1
- package/dist/commands/instructions/pull.d.ts +0 -9
- package/dist/commands/instructions/pull.d.ts.map +0 -1
- package/dist/commands/instructions/upstream.d.ts +0 -9
- package/dist/commands/instructions/upstream.d.ts.map +0 -1
- package/dist/commands/instructions/versions.d.ts +0 -12
- package/dist/commands/instructions/versions.d.ts.map +0 -1
- package/dist/commands/org/current.d.ts +0 -7
- package/dist/commands/org/current.d.ts.map +0 -1
- package/dist/commands/org/list.d.ts +0 -7
- package/dist/commands/org/list.d.ts.map +0 -1
- package/dist/commands/org/switch.d.ts +0 -13
- package/dist/commands/org/switch.d.ts.map +0 -1
- package/dist/commands/packs/add-instruction.d.ts +0 -11
- package/dist/commands/packs/add-instruction.d.ts.map +0 -1
- package/dist/commands/packs/apply.d.ts +0 -13
- package/dist/commands/packs/apply.d.ts.map +0 -1
- package/dist/commands/packs/create.d.ts +0 -13
- package/dist/commands/packs/create.d.ts.map +0 -1
- package/dist/commands/packs/fork.d.ts +0 -10
- package/dist/commands/packs/fork.d.ts.map +0 -1
- package/dist/commands/packs/get.d.ts +0 -10
- package/dist/commands/packs/get.d.ts.map +0 -1
- package/dist/commands/packs/list.d.ts +0 -22
- package/dist/commands/packs/list.d.ts.map +0 -1
- package/dist/commands/packs/remove-instruction.d.ts +0 -11
- package/dist/commands/packs/remove-instruction.d.ts.map +0 -1
- package/dist/commands/proxy/env.d.ts +0 -14
- package/dist/commands/proxy/env.d.ts.map +0 -1
- package/dist/commands/proxy/logs.d.ts +0 -11
- package/dist/commands/proxy/logs.d.ts.map +0 -1
- package/dist/commands/proxy/restart.d.ts +0 -11
- package/dist/commands/proxy/restart.d.ts.map +0 -1
- package/dist/commands/proxy/setup.d.ts +0 -23
- package/dist/commands/proxy/setup.d.ts.map +0 -1
- package/dist/commands/proxy/start.d.ts +0 -17
- package/dist/commands/proxy/start.d.ts.map +0 -1
- package/dist/commands/proxy/status.d.ts +0 -7
- package/dist/commands/proxy/status.d.ts.map +0 -1
- package/dist/commands/proxy/stop.d.ts +0 -8
- package/dist/commands/proxy/stop.d.ts.map +0 -1
- package/dist/commands/service/install.d.ts +0 -33
- package/dist/commands/service/install.d.ts.map +0 -1
- package/dist/commands/service/install.test.d.ts +0 -2
- package/dist/commands/service/install.test.d.ts.map +0 -1
- package/dist/commands/service/install.test.js +0 -345
- package/dist/commands/service/install.test.js.map +0 -1
- package/dist/commands/service/status.d.ts +0 -6
- package/dist/commands/service/status.d.ts.map +0 -1
- package/dist/commands/service/uninstall.d.ts +0 -6
- package/dist/commands/service/uninstall.d.ts.map +0 -1
- package/dist/commands/sessions/analyze.d.ts +0 -10
- package/dist/commands/sessions/analyze.d.ts.map +0 -1
- package/dist/commands/sessions/end.d.ts +0 -9
- package/dist/commands/sessions/end.d.ts.map +0 -1
- package/dist/commands/sessions/import.d.ts +0 -13
- package/dist/commands/sessions/import.d.ts.map +0 -1
- package/dist/commands/sessions/list.d.ts +0 -11
- package/dist/commands/sessions/list.d.ts.map +0 -1
- package/dist/commands/sessions/start.d.ts +0 -11
- package/dist/commands/sessions/start.d.ts.map +0 -1
- package/dist/commands/signals/report.d.ts +0 -10
- package/dist/commands/signals/report.d.ts.map +0 -1
- package/dist/commands/signals/report.test.d.ts +0 -2
- package/dist/commands/signals/report.test.d.ts.map +0 -1
- package/dist/commands/signals/report.test.js +0 -65
- package/dist/commands/signals/report.test.js.map +0 -1
- package/dist/commands/skills/export-approved.d.ts +0 -10
- package/dist/commands/skills/export-approved.d.ts.map +0 -1
- package/dist/commands/skills/install.d.ts +0 -15
- package/dist/commands/skills/install.d.ts.map +0 -1
- package/dist/commands/skills/list.d.ts +0 -11
- package/dist/commands/skills/list.d.ts.map +0 -1
- package/dist/commands/skills/publish.d.ts +0 -17
- package/dist/commands/skills/publish.d.ts.map +0 -1
- package/dist/commands/skills/search.d.ts +0 -17
- package/dist/commands/skills/search.d.ts.map +0 -1
- package/dist/commands/skills/update.d.ts +0 -10
- package/dist/commands/skills/update.d.ts.map +0 -1
- package/dist/commands/suggestions/accept.d.ts +0 -16
- package/dist/commands/suggestions/accept.d.ts.map +0 -1
- package/dist/commands/suggestions/accept.test.d.ts +0 -2
- package/dist/commands/suggestions/accept.test.d.ts.map +0 -1
- package/dist/commands/suggestions/accept.test.js +0 -52
- package/dist/commands/suggestions/accept.test.js.map +0 -1
- package/dist/commands/suggestions/dismiss.d.ts +0 -10
- package/dist/commands/suggestions/dismiss.d.ts.map +0 -1
- package/dist/commands/suggestions/list.d.ts +0 -10
- package/dist/commands/suggestions/list.d.ts.map +0 -1
- package/dist/commands/suggestions/refresh.d.ts +0 -7
- package/dist/commands/suggestions/refresh.d.ts.map +0 -1
- package/dist/dashboard/Dashboard.d.ts +0 -3
- package/dist/dashboard/Dashboard.d.ts.map +0 -1
- package/dist/dashboard/data.d.ts +0 -11
- package/dist/dashboard/data.d.ts.map +0 -1
- package/dist/dashboard/panels/friction.d.ts +0 -7
- package/dist/dashboard/panels/friction.d.ts.map +0 -1
- package/dist/dashboard/panels/insights.d.ts +0 -8
- package/dist/dashboard/panels/insights.d.ts.map +0 -1
- package/dist/dashboard/panels/instructions.d.ts +0 -9
- package/dist/dashboard/panels/instructions.d.ts.map +0 -1
- package/dist/dashboard/panels/outcomes.d.ts +0 -7
- package/dist/dashboard/panels/outcomes.d.ts.map +0 -1
- package/dist/dashboard/panels/overview.d.ts +0 -8
- package/dist/dashboard/panels/overview.d.ts.map +0 -1
- package/dist/dashboard/panels/shared.d.ts +0 -17
- package/dist/dashboard/panels/shared.d.ts.map +0 -1
- package/dist/dashboard/types.d.ts +0 -80
- package/dist/dashboard/types.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/active-org-refresh.d.ts +0 -22
- package/dist/lib/active-org-refresh.d.ts.map +0 -1
- package/dist/lib/active-org-refresh.test.d.ts +0 -2
- package/dist/lib/active-org-refresh.test.d.ts.map +0 -1
- package/dist/lib/active-org-refresh.test.js +0 -190
- package/dist/lib/active-org-refresh.test.js.map +0 -1
- package/dist/lib/active-org.d.ts +0 -43
- package/dist/lib/active-org.d.ts.map +0 -1
- package/dist/lib/active-org.test.d.ts +0 -2
- package/dist/lib/active-org.test.d.ts.map +0 -1
- package/dist/lib/active-org.test.js +0 -147
- package/dist/lib/active-org.test.js.map +0 -1
- package/dist/lib/api-client.d.ts +0 -17
- package/dist/lib/api-client.d.ts.map +0 -1
- package/dist/lib/api-client.test.d.ts +0 -2
- package/dist/lib/api-client.test.d.ts.map +0 -1
- package/dist/lib/api-client.test.js +0 -161
- package/dist/lib/api-client.test.js.map +0 -1
- package/dist/lib/auth.d.ts +0 -27
- package/dist/lib/auth.d.ts.map +0 -1
- package/dist/lib/auth.test.d.ts +0 -2
- package/dist/lib/auth.test.d.ts.map +0 -1
- package/dist/lib/auth.test.js +0 -110
- package/dist/lib/auth.test.js.map +0 -1
- package/dist/lib/cron-registry.d.ts +0 -47
- package/dist/lib/cron-registry.d.ts.map +0 -1
- package/dist/lib/cron-registry.js +0 -102
- package/dist/lib/cron-registry.js.map +0 -1
- package/dist/lib/cron-registry.test.d.ts +0 -2
- package/dist/lib/cron-registry.test.d.ts.map +0 -1
- package/dist/lib/cron-registry.test.js +0 -136
- package/dist/lib/cron-registry.test.js.map +0 -1
- package/dist/lib/cron-runner.d.ts +0 -16
- package/dist/lib/cron-runner.d.ts.map +0 -1
- package/dist/lib/cron-runner.js +0 -68
- package/dist/lib/cron-runner.js.map +0 -1
- package/dist/lib/detect-languages.d.ts +0 -7
- package/dist/lib/detect-languages.d.ts.map +0 -1
- package/dist/lib/detect-languages.test.d.ts +0 -2
- package/dist/lib/detect-languages.test.d.ts.map +0 -1
- package/dist/lib/detect-languages.test.js +0 -29
- package/dist/lib/detect-languages.test.js.map +0 -1
- package/dist/lib/eval-analyzer.d.ts +0 -23
- package/dist/lib/eval-analyzer.d.ts.map +0 -1
- package/dist/lib/eval-benchmark.d.ts +0 -17
- package/dist/lib/eval-benchmark.d.ts.map +0 -1
- package/dist/lib/eval-conversation-handler.d.ts +0 -9
- package/dist/lib/eval-conversation-handler.d.ts.map +0 -1
- package/dist/lib/eval-executor.d.ts +0 -21
- package/dist/lib/eval-executor.d.ts.map +0 -1
- package/dist/lib/eval-executor.test.d.ts +0 -2
- package/dist/lib/eval-executor.test.d.ts.map +0 -1
- package/dist/lib/eval-executor.test.js +0 -8
- package/dist/lib/eval-executor.test.js.map +0 -1
- package/dist/lib/eval-grader.d.ts +0 -38
- package/dist/lib/eval-grader.d.ts.map +0 -1
- package/dist/lib/eval-grader.test.d.ts +0 -2
- package/dist/lib/eval-grader.test.d.ts.map +0 -1
- package/dist/lib/eval-grader.test.js +0 -8
- package/dist/lib/eval-grader.test.js.map +0 -1
- package/dist/lib/eval-meta-judge.d.ts +0 -28
- package/dist/lib/eval-meta-judge.d.ts.map +0 -1
- package/dist/lib/eval-trigger-tester.d.ts +0 -19
- package/dist/lib/eval-trigger-tester.d.ts.map +0 -1
- package/dist/lib/eval-worktree.d.ts +0 -11
- package/dist/lib/eval-worktree.d.ts.map +0 -1
- package/dist/lib/eval-worktree.test.d.ts +0 -2
- package/dist/lib/eval-worktree.test.d.ts.map +0 -1
- package/dist/lib/eval-worktree.test.js +0 -68
- package/dist/lib/eval-worktree.test.js.map +0 -1
- package/dist/lib/gateway-entry.d.ts +0 -3
- package/dist/lib/gateway-entry.d.ts.map +0 -1
- package/dist/lib/gateway-lifecycle.d.ts +0 -9
- package/dist/lib/gateway-lifecycle.d.ts.map +0 -1
- package/dist/lib/gateway.d.ts +0 -11
- package/dist/lib/gateway.d.ts.map +0 -1
- package/dist/lib/graphile-worker-runner.d.ts +0 -124
- package/dist/lib/graphile-worker-runner.d.ts.map +0 -1
- package/dist/lib/graphile-worker-runner.js +0 -530
- package/dist/lib/graphile-worker-runner.js.map +0 -1
- package/dist/lib/graphile-worker-runner.test.d.ts +0 -2
- package/dist/lib/graphile-worker-runner.test.d.ts.map +0 -1
- package/dist/lib/graphile-worker-runner.test.js +0 -153
- package/dist/lib/graphile-worker-runner.test.js.map +0 -1
- package/dist/lib/handlers/cron-close-stale-sessions.d.ts +0 -3
- package/dist/lib/handlers/cron-close-stale-sessions.d.ts.map +0 -1
- package/dist/lib/handlers/cron-data-integrity-audit.d.ts +0 -3
- package/dist/lib/handlers/cron-data-integrity-audit.d.ts.map +0 -1
- package/dist/lib/handlers/cron-refresh-skills.d.ts +0 -3
- package/dist/lib/handlers/cron-refresh-skills.d.ts.map +0 -1
- package/dist/lib/handlers/cron-refresh-skills.test.d.ts +0 -2
- package/dist/lib/handlers/cron-refresh-skills.test.d.ts.map +0 -1
- package/dist/lib/handlers/cron-refresh-skills.test.js +0 -114
- package/dist/lib/handlers/cron-refresh-skills.test.js.map +0 -1
- package/dist/lib/handlers/cron-regenerate-insights.d.ts +0 -3
- package/dist/lib/handlers/cron-regenerate-insights.d.ts.map +0 -1
- package/dist/lib/handlers/cron-regenerate-insights.js +0 -6
- package/dist/lib/handlers/cron-regenerate-insights.js.map +0 -1
- package/dist/lib/handlers/cron-suggest-instructions.d.ts +0 -3
- package/dist/lib/handlers/cron-suggest-instructions.d.ts.map +0 -1
- package/dist/lib/handlers/cron-suggest-instructions.test.d.ts +0 -2
- package/dist/lib/handlers/cron-suggest-instructions.test.d.ts.map +0 -1
- package/dist/lib/handlers/cron-suggest-instructions.test.js +0 -80
- package/dist/lib/handlers/cron-suggest-instructions.test.js.map +0 -1
- package/dist/lib/handlers/process-conversation.d.ts +0 -35
- package/dist/lib/handlers/process-conversation.d.ts.map +0 -1
- package/dist/lib/handlers/process-eval.d.ts +0 -32
- package/dist/lib/handlers/process-eval.d.ts.map +0 -1
- package/dist/lib/handlers/process-insights.d.ts +0 -39
- package/dist/lib/handlers/process-insights.d.ts.map +0 -1
- package/dist/lib/handlers/process-launch.d.ts +0 -29
- package/dist/lib/handlers/process-launch.d.ts.map +0 -1
- package/dist/lib/handlers/process-session-goal.d.ts +0 -29
- package/dist/lib/handlers/process-session-goal.d.ts.map +0 -1
- package/dist/lib/handlers/process-session-goal.test.d.ts +0 -2
- package/dist/lib/handlers/process-session-goal.test.d.ts.map +0 -1
- package/dist/lib/handlers/process-session-goal.test.js +0 -134
- package/dist/lib/handlers/process-session-goal.test.js.map +0 -1
- package/dist/lib/hooks-config.d.ts +0 -119
- package/dist/lib/hooks-config.d.ts.map +0 -1
- package/dist/lib/hooks-config.test.d.ts +0 -2
- package/dist/lib/hooks-config.test.d.ts.map +0 -1
- package/dist/lib/hooks-config.test.js +0 -231
- package/dist/lib/hooks-config.test.js.map +0 -1
- package/dist/lib/insights-prompts.d.ts +0 -13
- package/dist/lib/insights-prompts.d.ts.map +0 -1
- package/dist/lib/llm-client.d.ts +0 -26
- package/dist/lib/llm-client.d.ts.map +0 -1
- package/dist/lib/llm-client.test.d.ts +0 -2
- package/dist/lib/llm-client.test.d.ts.map +0 -1
- package/dist/lib/llm-client.test.js +0 -62
- package/dist/lib/llm-client.test.js.map +0 -1
- package/dist/lib/mirror-writer-db.d.ts +0 -12
- package/dist/lib/mirror-writer-db.d.ts.map +0 -1
- package/dist/lib/mirror-writer-db.js +0 -51
- package/dist/lib/mirror-writer-db.js.map +0 -1
- package/dist/lib/mirror-writer.d.ts +0 -35
- package/dist/lib/mirror-writer.d.ts.map +0 -1
- package/dist/lib/mirror-writer.js +0 -27
- package/dist/lib/mirror-writer.js.map +0 -1
- package/dist/lib/mirror-writer.test.d.ts +0 -2
- package/dist/lib/mirror-writer.test.d.ts.map +0 -1
- package/dist/lib/mirror-writer.test.js +0 -47
- package/dist/lib/mirror-writer.test.js.map +0 -1
- package/dist/lib/output.d.ts +0 -4
- package/dist/lib/output.d.ts.map +0 -1
- package/dist/lib/output.test.d.ts +0 -2
- package/dist/lib/output.test.d.ts.map +0 -1
- package/dist/lib/output.test.js +0 -71
- package/dist/lib/output.test.js.map +0 -1
- package/dist/lib/permanent-job-error.d.ts +0 -17
- package/dist/lib/permanent-job-error.d.ts.map +0 -1
- package/dist/lib/permanent-job-error.test.d.ts +0 -2
- package/dist/lib/permanent-job-error.test.d.ts.map +0 -1
- package/dist/lib/permanent-job-error.test.js +0 -29
- package/dist/lib/permanent-job-error.test.js.map +0 -1
- package/dist/lib/provider-aggregator.d.ts +0 -24
- package/dist/lib/provider-aggregator.d.ts.map +0 -1
- package/dist/lib/provider-aggregator.test.d.ts +0 -2
- package/dist/lib/provider-aggregator.test.d.ts.map +0 -1
- package/dist/lib/provider-aggregator.test.js +0 -103
- package/dist/lib/provider-aggregator.test.js.map +0 -1
- package/dist/lib/skills-loader.d.ts +0 -6
- package/dist/lib/skills-loader.d.ts.map +0 -1
- package/dist/lib/types.d.ts +0 -48
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/version-check.d.ts +0 -11
- package/dist/lib/version-check.d.ts.map +0 -1
- package/dist/test-helpers.d.ts +0 -58
- package/dist/test-helpers.d.ts.map +0 -1
- package/dist/test-helpers.js +0 -58
- package/dist/test-helpers.js.map +0 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// src/lib/transcript-rate-limit-watcher.ts
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
var KNOWN_TIMEZONES = /* @__PURE__ */ new Set([
|
|
6
|
+
"America/Phoenix",
|
|
7
|
+
"America/Los_Angeles",
|
|
8
|
+
"America/Denver",
|
|
9
|
+
"America/Chicago",
|
|
10
|
+
"America/New_York",
|
|
11
|
+
"America/Anchorage",
|
|
12
|
+
"America/Toronto",
|
|
13
|
+
"America/Vancouver",
|
|
14
|
+
"America/Mexico_City",
|
|
15
|
+
"America/Sao_Paulo",
|
|
16
|
+
"Europe/London",
|
|
17
|
+
"Europe/Berlin",
|
|
18
|
+
"Europe/Paris",
|
|
19
|
+
"Europe/Madrid",
|
|
20
|
+
"Europe/Amsterdam",
|
|
21
|
+
"Europe/Zurich",
|
|
22
|
+
"Europe/Stockholm",
|
|
23
|
+
"Europe/Athens",
|
|
24
|
+
"Asia/Tokyo",
|
|
25
|
+
"Asia/Shanghai",
|
|
26
|
+
"Asia/Hong_Kong",
|
|
27
|
+
"Asia/Singapore",
|
|
28
|
+
"Asia/Kolkata",
|
|
29
|
+
"Asia/Dubai",
|
|
30
|
+
"Asia/Jerusalem",
|
|
31
|
+
"Australia/Sydney",
|
|
32
|
+
"Australia/Melbourne",
|
|
33
|
+
"Pacific/Auckland",
|
|
34
|
+
"Pacific/Honolulu",
|
|
35
|
+
"UTC"
|
|
36
|
+
]);
|
|
37
|
+
function getTimezoneOffsetMinutes(date, timeZone) {
|
|
38
|
+
try {
|
|
39
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
40
|
+
timeZone,
|
|
41
|
+
hour12: false,
|
|
42
|
+
year: "numeric",
|
|
43
|
+
month: "2-digit",
|
|
44
|
+
day: "2-digit",
|
|
45
|
+
hour: "2-digit",
|
|
46
|
+
minute: "2-digit",
|
|
47
|
+
second: "2-digit"
|
|
48
|
+
});
|
|
49
|
+
const parts = dtf.formatToParts(date);
|
|
50
|
+
const get = (t) => parts.find((p) => p.type === t)?.value;
|
|
51
|
+
const y = Number(get("year"));
|
|
52
|
+
const mo = Number(get("month"));
|
|
53
|
+
const d = Number(get("day"));
|
|
54
|
+
let h = Number(get("hour"));
|
|
55
|
+
const mi = Number(get("minute"));
|
|
56
|
+
const s = Number(get("second"));
|
|
57
|
+
if (h === 24) h = 0;
|
|
58
|
+
const asUtc = Date.UTC(y, mo - 1, d, h, mi, s);
|
|
59
|
+
return Math.round((asUtc - date.getTime()) / 6e4);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function parseResetsAtFromMessage(text, observedAt) {
|
|
65
|
+
const match = text.match(
|
|
66
|
+
/reset(?:s|\s+at)?\s+(?:at\s+)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\s*(?:\(([^)]+)\))?/i
|
|
67
|
+
);
|
|
68
|
+
if (!match) return null;
|
|
69
|
+
let hour = parseInt(match[1], 10);
|
|
70
|
+
const minute = match[2] ? parseInt(match[2], 10) : 0;
|
|
71
|
+
const ampm = match[3]?.toLowerCase();
|
|
72
|
+
const tzRaw = match[4]?.trim();
|
|
73
|
+
if (ampm === "pm" && hour < 12) hour += 12;
|
|
74
|
+
if (ampm === "am" && hour === 12) hour = 0;
|
|
75
|
+
if (Number.isNaN(hour) || Number.isNaN(minute) || hour > 23 || minute > 59) return null;
|
|
76
|
+
const timeZone = tzRaw && KNOWN_TIMEZONES.has(tzRaw) ? tzRaw : "UTC";
|
|
77
|
+
const offsetMin = getTimezoneOffsetMinutes(observedAt, timeZone);
|
|
78
|
+
if (offsetMin == null) return null;
|
|
79
|
+
let candidate;
|
|
80
|
+
try {
|
|
81
|
+
const dtf = new Intl.DateTimeFormat("en-CA", {
|
|
82
|
+
timeZone,
|
|
83
|
+
year: "numeric",
|
|
84
|
+
month: "2-digit",
|
|
85
|
+
day: "2-digit"
|
|
86
|
+
});
|
|
87
|
+
const parts = dtf.formatToParts(observedAt);
|
|
88
|
+
const y = Number(parts.find((p) => p.type === "year")?.value);
|
|
89
|
+
const mo = Number(parts.find((p) => p.type === "month")?.value);
|
|
90
|
+
const d = Number(parts.find((p) => p.type === "day")?.value);
|
|
91
|
+
const utcMs = Date.UTC(y, mo - 1, d, hour, minute, 0) - offsetMin * 6e4;
|
|
92
|
+
candidate = new Date(utcMs);
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (candidate.getTime() <= observedAt.getTime()) {
|
|
97
|
+
candidate = new Date(candidate.getTime() + 24 * 60 * 60 * 1e3);
|
|
98
|
+
}
|
|
99
|
+
return candidate;
|
|
100
|
+
}
|
|
101
|
+
function pickLimitType(observedAt, resetsAt) {
|
|
102
|
+
if (!resetsAt) return "five_hour_percent";
|
|
103
|
+
const deltaMs = resetsAt.getTime() - observedAt.getTime();
|
|
104
|
+
const FIVE_H_30 = 5.5 * 60 * 60 * 1e3;
|
|
105
|
+
return deltaMs <= FIVE_H_30 ? "five_hour_percent" : "seven_day_percent";
|
|
106
|
+
}
|
|
107
|
+
function extractText(entry) {
|
|
108
|
+
const candidates = [];
|
|
109
|
+
if (entry.content) candidates.push(entry.content);
|
|
110
|
+
if (entry.message?.content) candidates.push(entry.message.content);
|
|
111
|
+
for (const c of candidates) {
|
|
112
|
+
if (typeof c === "string") return c;
|
|
113
|
+
if (Array.isArray(c)) {
|
|
114
|
+
for (const part of c) {
|
|
115
|
+
if (part && typeof part === "object" && "text" in part) {
|
|
116
|
+
const t = part.text;
|
|
117
|
+
if (typeof t === "string") return t;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
function lineToObservation(line, transcriptPath) {
|
|
125
|
+
const trimmed = line.trim();
|
|
126
|
+
if (!trimmed) return null;
|
|
127
|
+
let entry;
|
|
128
|
+
try {
|
|
129
|
+
entry = JSON.parse(trimmed);
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const is429 = entry.apiErrorStatus === 429 || entry.error === "rate_limit" || entry.isApiErrorMessage === true;
|
|
134
|
+
if (!is429) return null;
|
|
135
|
+
const text = extractText(entry);
|
|
136
|
+
const looksLikeRateLimit = entry.apiErrorStatus === 429 || entry.error === "rate_limit" || /rate.?limit|usage limit|out of (?:extra )?usage|resets?/i.test(text);
|
|
137
|
+
if (!looksLikeRateLimit) return null;
|
|
138
|
+
const observedAt = entry.timestamp ? new Date(entry.timestamp) : /* @__PURE__ */ new Date();
|
|
139
|
+
const safeObservedAt = isNaN(observedAt.getTime()) ? /* @__PURE__ */ new Date() : observedAt;
|
|
140
|
+
const resetsAt = text ? parseResetsAtFromMessage(text, safeObservedAt) : null;
|
|
141
|
+
const limitType = pickLimitType(safeObservedAt, resetsAt);
|
|
142
|
+
return {
|
|
143
|
+
provider: "anthropic",
|
|
144
|
+
plan: "unknown",
|
|
145
|
+
limitType,
|
|
146
|
+
value: 100,
|
|
147
|
+
unit: "percentage",
|
|
148
|
+
comparator: "=",
|
|
149
|
+
resetsAt,
|
|
150
|
+
sourceType: "self_observed_429",
|
|
151
|
+
sourceUrl: transcriptPath ?? null,
|
|
152
|
+
sourceEvidence: {
|
|
153
|
+
line: trimmed,
|
|
154
|
+
sessionId: entry.sessionId ?? null,
|
|
155
|
+
transcriptPath: transcriptPath ?? null
|
|
156
|
+
},
|
|
157
|
+
confidence: 0.9,
|
|
158
|
+
observedAt: safeObservedAt
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function tailJsonl(filepath, fromOffset) {
|
|
162
|
+
let stat;
|
|
163
|
+
try {
|
|
164
|
+
stat = await fs.stat(filepath);
|
|
165
|
+
} catch {
|
|
166
|
+
return { observations: [], newOffset: fromOffset };
|
|
167
|
+
}
|
|
168
|
+
let start = fromOffset;
|
|
169
|
+
if (stat.size < fromOffset) start = 0;
|
|
170
|
+
if (stat.size === start) return { observations: [], newOffset: start };
|
|
171
|
+
let fh;
|
|
172
|
+
try {
|
|
173
|
+
fh = await fs.open(filepath, "r");
|
|
174
|
+
} catch {
|
|
175
|
+
return { observations: [], newOffset: fromOffset };
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const length = stat.size - start;
|
|
179
|
+
const buf = Buffer.alloc(length);
|
|
180
|
+
await fh.read(buf, 0, length, start);
|
|
181
|
+
const text = buf.toString("utf-8");
|
|
182
|
+
const lastNewline = text.lastIndexOf("\n");
|
|
183
|
+
let consumed;
|
|
184
|
+
let newOffset;
|
|
185
|
+
if (lastNewline === -1) {
|
|
186
|
+
return { observations: [], newOffset: start };
|
|
187
|
+
}
|
|
188
|
+
consumed = text.slice(0, lastNewline + 1);
|
|
189
|
+
newOffset = start + Buffer.byteLength(consumed, "utf-8");
|
|
190
|
+
const observations = [];
|
|
191
|
+
for (const line of consumed.split("\n")) {
|
|
192
|
+
const obs = lineToObservation(line, filepath);
|
|
193
|
+
if (obs) observations.push(obs);
|
|
194
|
+
}
|
|
195
|
+
return { observations, newOffset };
|
|
196
|
+
} finally {
|
|
197
|
+
await fh.close();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async function* walkJsonl(dir) {
|
|
201
|
+
let entries;
|
|
202
|
+
try {
|
|
203
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
204
|
+
} catch {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
for (const e of entries) {
|
|
208
|
+
const full = path.join(dir, e.name);
|
|
209
|
+
if (e.isDirectory()) {
|
|
210
|
+
yield* walkJsonl(full);
|
|
211
|
+
} else if (e.isFile() && e.name.endsWith(".jsonl")) {
|
|
212
|
+
yield full;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function scanAllTranscripts(claudeDir = path.join(os.homedir(), ".claude")) {
|
|
217
|
+
const projectsDir = path.join(claudeDir, "projects");
|
|
218
|
+
const out = [];
|
|
219
|
+
for await (const file of walkJsonl(projectsDir)) {
|
|
220
|
+
const { observations } = await tailJsonl(file, 0);
|
|
221
|
+
out.push(...observations);
|
|
222
|
+
}
|
|
223
|
+
return out;
|
|
224
|
+
}
|
|
225
|
+
function offsetCachePath() {
|
|
226
|
+
return path.join(os.homedir(), ".config", "rulemetric", "transcript-offsets.json");
|
|
227
|
+
}
|
|
228
|
+
async function loadOffsets() {
|
|
229
|
+
try {
|
|
230
|
+
const raw = await fs.readFile(offsetCachePath(), "utf-8");
|
|
231
|
+
const parsed = JSON.parse(raw);
|
|
232
|
+
if (parsed && typeof parsed === "object") return parsed;
|
|
233
|
+
return {};
|
|
234
|
+
} catch {
|
|
235
|
+
return {};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function saveOffsets(offsets) {
|
|
239
|
+
const p = offsetCachePath();
|
|
240
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
241
|
+
await fs.writeFile(p, JSON.stringify(offsets, null, 2), "utf-8");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export {
|
|
245
|
+
parseResetsAtFromMessage,
|
|
246
|
+
pickLimitType,
|
|
247
|
+
lineToObservation,
|
|
248
|
+
tailJsonl,
|
|
249
|
+
scanAllTranscripts,
|
|
250
|
+
offsetCachePath,
|
|
251
|
+
loadOffsets,
|
|
252
|
+
saveOffsets
|
|
253
|
+
};
|
|
254
|
+
//# sourceMappingURL=chunk-WA4MWYRW.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/transcript-rate-limit-watcher.ts"],
|
|
4
|
+
"sourcesContent": ["// Forward-only watcher for Claude Code transcripts (~/.claude/projects/**/*.jsonl).\n//\n// Two modes:\n// * tailJsonl(path, offset) \u2014 read new bytes since `offset`, emit 429 obs\n// * scanAllTranscripts() \u2014 walk every transcript end-to-end (opt-in backfill)\n//\n// Each rate-limit line surfaces in Claude Code as a synthetic assistant message:\n// {\n// \"type\": \"assistant\",\n// \"isApiErrorMessage\": true,\n// \"apiErrorStatus\": 429,\n// \"error\": \"rate_limit\",\n// \"content\": [{ \"type\": \"text\",\n// \"text\": \"You're out of extra usage \u00B7 resets 12:50pm (America/Phoenix)\" }],\n// \"timestamp\": \"2026-06-02T19:43:00Z\"\n// }\n//\n// We translate each into a ParsedObservation matching the camelCase contract\n// from Phase 2 (`packages/usage-research/src/adapters/types.ts`).\n//\n// Heuristic for limitType: if resetsAt - observedAt fits within 5h30m, it's\n// the 5-hour cap; otherwise (up to 8 days out) it's the 7-day cap. This is\n// best-effort \u2014 the docs scraper + fusion job is the authoritative\n// disambiguator. See concerns at end of file.\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nexport interface ParsedObservation {\n provider: 'anthropic';\n plan: string;\n limitType: 'five_hour_percent' | 'seven_day_percent';\n value: number;\n unit: 'percentage';\n comparator: '=' | '>=' | '<=';\n resetsAt: Date | string | null;\n sourceType: 'self_observed_429';\n sourceUrl: string | null;\n sourceEvidence: unknown;\n confidence: number;\n observedAt: Date | string;\n}\n\n// Common Claude-Code-surfaced IANA timezones the synthetic message uses.\n// Anything we recognise gets parsed in that TZ; otherwise we fall back to\n// local-clock interpretation.\nconst KNOWN_TIMEZONES = new Set<string>([\n 'America/Phoenix',\n 'America/Los_Angeles',\n 'America/Denver',\n 'America/Chicago',\n 'America/New_York',\n 'America/Anchorage',\n 'America/Toronto',\n 'America/Vancouver',\n 'America/Mexico_City',\n 'America/Sao_Paulo',\n 'Europe/London',\n 'Europe/Berlin',\n 'Europe/Paris',\n 'Europe/Madrid',\n 'Europe/Amsterdam',\n 'Europe/Zurich',\n 'Europe/Stockholm',\n 'Europe/Athens',\n 'Asia/Tokyo',\n 'Asia/Shanghai',\n 'Asia/Hong_Kong',\n 'Asia/Singapore',\n 'Asia/Kolkata',\n 'Asia/Dubai',\n 'Asia/Jerusalem',\n 'Australia/Sydney',\n 'Australia/Melbourne',\n 'Pacific/Auckland',\n 'Pacific/Honolulu',\n 'UTC',\n]);\n\n/**\n * Compute the offset (in minutes east of UTC) for `date` in `timeZone`.\n * Returns null if the timeZone is unknown to Intl.\n */\nfunction getTimezoneOffsetMinutes(date: Date, timeZone: string): number | null {\n try {\n const dtf = new Intl.DateTimeFormat('en-US', {\n timeZone,\n hour12: false,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n const parts = dtf.formatToParts(date);\n const get = (t: string) => parts.find((p) => p.type === t)?.value;\n const y = Number(get('year'));\n const mo = Number(get('month'));\n const d = Number(get('day'));\n let h = Number(get('hour'));\n const mi = Number(get('minute'));\n const s = Number(get('second'));\n if (h === 24) h = 0;\n const asUtc = Date.UTC(y, mo - 1, d, h, mi, s);\n return Math.round((asUtc - date.getTime()) / 60000);\n } catch {\n return null;\n }\n}\n\n/**\n * Parse \"resets HH:MMam/pm (TZ)\" out of a synthetic 429 message.\n *\n * Strategy:\n * 1. Pull HH:MM, am/pm, optional (timezone) via regex.\n * 2. Pick the wall-clock TZ \u2014 recognised IANA name or UTC fallback.\n * 3. Compute the next occurrence of HH:MM (today or tomorrow, whichever is\n * strictly after `observedAt`) interpreted in that TZ.\n */\nexport function parseResetsAtFromMessage(text: string, observedAt: Date): Date | null {\n // Accept \"resets\" or \"reset at\" or \"resets at\"; allow optional minutes.\n const match = text.match(\n /reset(?:s|\\s+at)?\\s+(?:at\\s+)?(\\d{1,2})(?::(\\d{2}))?\\s*(am|pm)?\\s*(?:\\(([^)]+)\\))?/i,\n );\n if (!match) return null;\n\n let hour = parseInt(match[1], 10);\n const minute = match[2] ? parseInt(match[2], 10) : 0;\n const ampm = match[3]?.toLowerCase();\n const tzRaw = match[4]?.trim();\n\n if (ampm === 'pm' && hour < 12) hour += 12;\n if (ampm === 'am' && hour === 12) hour = 0;\n if (Number.isNaN(hour) || Number.isNaN(minute) || hour > 23 || minute > 59) return null;\n\n const timeZone = tzRaw && KNOWN_TIMEZONES.has(tzRaw) ? tzRaw : 'UTC';\n\n // Probe the TZ offset *near* observedAt so we land on the right DST side.\n const offsetMin = getTimezoneOffsetMinutes(observedAt, timeZone);\n if (offsetMin == null) return null;\n\n // Build today-in-TZ Y/M/D from observedAt rendered in that TZ.\n let candidate: Date;\n try {\n const dtf = new Intl.DateTimeFormat('en-CA', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n const parts = dtf.formatToParts(observedAt);\n const y = Number(parts.find((p) => p.type === 'year')?.value);\n const mo = Number(parts.find((p) => p.type === 'month')?.value);\n const d = Number(parts.find((p) => p.type === 'day')?.value);\n // Wall-clock target HH:MM in TZ \u2192 UTC epoch.\n const utcMs = Date.UTC(y, mo - 1, d, hour, minute, 0) - offsetMin * 60000;\n candidate = new Date(utcMs);\n } catch {\n return null;\n }\n\n // If the candidate is at or before observedAt, the reset is tomorrow.\n if (candidate.getTime() <= observedAt.getTime()) {\n candidate = new Date(candidate.getTime() + 24 * 60 * 60 * 1000);\n }\n\n return candidate;\n}\n\n/** Distinguish 5-hour vs 7-day window from the reset distance. */\nexport function pickLimitType(\n observedAt: Date,\n resetsAt: Date | null,\n): 'five_hour_percent' | 'seven_day_percent' {\n if (!resetsAt) return 'five_hour_percent';\n const deltaMs = resetsAt.getTime() - observedAt.getTime();\n const FIVE_H_30 = 5.5 * 60 * 60 * 1000;\n return deltaMs <= FIVE_H_30 ? 'five_hour_percent' : 'seven_day_percent';\n}\n\ninterface TranscriptEntry {\n type?: string;\n isApiErrorMessage?: boolean;\n apiErrorStatus?: number;\n error?: string;\n timestamp?: string;\n sessionId?: string;\n content?: unknown;\n message?: { content?: unknown };\n}\n\nfunction extractText(entry: TranscriptEntry): string {\n // Synthetic 429 lines we've seen surface text in two places:\n // 1. top-level `content: [{ type: 'text', text }]`\n // 2. `message.content: ...` (mirrors the assistant.message shape)\n const candidates: unknown[] = [];\n if (entry.content) candidates.push(entry.content);\n if (entry.message?.content) candidates.push(entry.message.content);\n\n for (const c of candidates) {\n if (typeof c === 'string') return c;\n if (Array.isArray(c)) {\n for (const part of c) {\n if (part && typeof part === 'object' && 'text' in part) {\n const t = (part as { text?: unknown }).text;\n if (typeof t === 'string') return t;\n }\n }\n }\n }\n return '';\n}\n\n/**\n * Turn one JSONL line into a ParsedObservation, or null for non-429 lines\n * (and for malformed JSON).\n */\nexport function lineToObservation(\n line: string,\n transcriptPath?: string,\n): ParsedObservation | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n let entry: TranscriptEntry;\n try {\n entry = JSON.parse(trimmed) as TranscriptEntry;\n } catch {\n return null;\n }\n\n // Must look like a synthetic 429.\n const is429 =\n entry.apiErrorStatus === 429 ||\n entry.error === 'rate_limit' ||\n entry.isApiErrorMessage === true;\n if (!is429) return null;\n\n const text = extractText(entry);\n // Final filter: the message body must mention a reset OR the apiErrorStatus\n // must be 429. (Some isApiErrorMessage lines are 5xx \u2014 skip those.)\n const looksLikeRateLimit =\n entry.apiErrorStatus === 429 ||\n entry.error === 'rate_limit' ||\n /rate.?limit|usage limit|out of (?:extra )?usage|resets?/i.test(text);\n if (!looksLikeRateLimit) return null;\n\n const observedAt = entry.timestamp ? new Date(entry.timestamp) : new Date();\n const safeObservedAt = isNaN(observedAt.getTime()) ? new Date() : observedAt;\n const resetsAt = text ? parseResetsAtFromMessage(text, safeObservedAt) : null;\n const limitType = pickLimitType(safeObservedAt, resetsAt);\n\n return {\n provider: 'anthropic',\n plan: 'unknown',\n limitType,\n value: 100,\n unit: 'percentage',\n comparator: '=',\n resetsAt,\n sourceType: 'self_observed_429',\n sourceUrl: transcriptPath ?? null,\n sourceEvidence: {\n line: trimmed,\n sessionId: entry.sessionId ?? null,\n transcriptPath: transcriptPath ?? null,\n },\n confidence: 0.9,\n observedAt: safeObservedAt,\n };\n}\n\nexport interface TailResult {\n observations: ParsedObservation[];\n newOffset: number;\n}\n\n/**\n * Read the file from byte `fromOffset` onward, parse complete lines, emit any\n * 429 observations, and return the new offset (positioned at the last complete\n * newline \u2014 partial trailing lines are kept for the next tail).\n */\nexport async function tailJsonl(filepath: string, fromOffset: number): Promise<TailResult> {\n let stat;\n try {\n stat = await fs.stat(filepath);\n } catch {\n return { observations: [], newOffset: fromOffset };\n }\n\n // If the file got truncated/rotated, restart from 0.\n let start = fromOffset;\n if (stat.size < fromOffset) start = 0;\n if (stat.size === start) return { observations: [], newOffset: start };\n\n let fh;\n try {\n fh = await fs.open(filepath, 'r');\n } catch {\n return { observations: [], newOffset: fromOffset };\n }\n\n try {\n const length = stat.size - start;\n const buf = Buffer.alloc(length);\n await fh.read(buf, 0, length, start);\n const text = buf.toString('utf-8');\n\n // Find the last newline so we don't half-eat a line still being written.\n const lastNewline = text.lastIndexOf('\\n');\n let consumed: string;\n let newOffset: number;\n if (lastNewline === -1) {\n // No complete line yet.\n return { observations: [], newOffset: start };\n }\n consumed = text.slice(0, lastNewline + 1);\n // The byte length of the consumed slice \u2014 not the char length \u2014 drives the\n // next offset. JSONL transcripts are ASCII-dominant but the reset message\n // contains the \"\u00B7\" character (2 bytes UTF-8), so byteLength matters.\n newOffset = start + Buffer.byteLength(consumed, 'utf-8');\n\n const observations: ParsedObservation[] = [];\n for (const line of consumed.split('\\n')) {\n const obs = lineToObservation(line, filepath);\n if (obs) observations.push(obs);\n }\n return { observations, newOffset };\n } finally {\n await fh.close();\n }\n}\n\nasync function* walkJsonl(dir: string): AsyncGenerator<string> {\n let entries;\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n yield* walkJsonl(full);\n } else if (e.isFile() && e.name.endsWith('.jsonl')) {\n yield full;\n }\n }\n}\n\n/**\n * Scan every Claude Code transcript under `claudeDir` end-to-end. Used by the\n * opt-in `rulemetric research backfill` command \u2014 forward-only tail is the\n * default capture path.\n */\nexport async function scanAllTranscripts(\n claudeDir: string = path.join(os.homedir(), '.claude'),\n): Promise<ParsedObservation[]> {\n const projectsDir = path.join(claudeDir, 'projects');\n const out: ParsedObservation[] = [];\n for await (const file of walkJsonl(projectsDir)) {\n const { observations } = await tailJsonl(file, 0);\n out.push(...observations);\n }\n return out;\n}\n\n// \u2500\u2500 Offset cache \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Stored at ~/.config/rulemetric/transcript-offsets.json. Plain JSON of\n// `{ <absolute_path>: <byte_offset> }`. Read+rewrite is fine \u2014 the file\n// stays tiny (a few hundred bytes per session).\n\nexport function offsetCachePath(): string {\n return path.join(os.homedir(), '.config', 'rulemetric', 'transcript-offsets.json');\n}\n\nexport async function loadOffsets(): Promise<Record<string, number>> {\n try {\n const raw = await fs.readFile(offsetCachePath(), 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object') return parsed as Record<string, number>;\n return {};\n } catch {\n return {};\n }\n}\n\nexport async function saveOffsets(offsets: Record<string, number>): Promise<void> {\n const p = offsetCachePath();\n await fs.mkdir(path.dirname(p), { recursive: true });\n await fs.writeFile(p, JSON.stringify(offsets, null, 2), 'utf-8');\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import {
|
|
2
|
+
startTerminalTargetHeartbeat
|
|
3
|
+
} from "./chunk-JX5UI6RW.js";
|
|
4
|
+
import {
|
|
5
|
+
processInsights
|
|
6
|
+
} from "./chunk-XPUEGHXN.js";
|
|
7
|
+
import {
|
|
8
|
+
processLaunch
|
|
9
|
+
} from "./chunk-4WFE4PFP.js";
|
|
10
|
+
import {
|
|
11
|
+
processRunCleanup
|
|
12
|
+
} from "./chunk-AULP2OWH.js";
|
|
13
|
+
import {
|
|
14
|
+
processSendMessage
|
|
15
|
+
} from "./chunk-W53GKIZQ.js";
|
|
16
|
+
import {
|
|
17
|
+
processSessionGoal
|
|
18
|
+
} from "./chunk-IGXX624H.js";
|
|
19
|
+
import {
|
|
20
|
+
processAnnouncement
|
|
21
|
+
} from "./chunk-GQCISMAH.js";
|
|
22
|
+
import {
|
|
23
|
+
processConversation
|
|
24
|
+
} from "./chunk-BD7CY42U.js";
|
|
25
|
+
import {
|
|
26
|
+
processEval
|
|
27
|
+
} from "./chunk-QJXAULRC.js";
|
|
28
|
+
import {
|
|
29
|
+
isPermanentJobError
|
|
30
|
+
} from "./chunk-DGHWRQXL.js";
|
|
31
|
+
import {
|
|
32
|
+
cronRefreshSkills
|
|
33
|
+
} from "./chunk-RQ2TMLKG.js";
|
|
34
|
+
import {
|
|
35
|
+
cronSuggestInstructions
|
|
36
|
+
} from "./chunk-YBNW7ARH.js";
|
|
37
|
+
import {
|
|
38
|
+
ApiError,
|
|
39
|
+
apiGet,
|
|
40
|
+
apiPost
|
|
41
|
+
} from "./chunk-EJOI2ZGU.js";
|
|
42
|
+
|
|
43
|
+
// src/lib/agent-loop.ts
|
|
44
|
+
var HANDLERS = {
|
|
45
|
+
process_eval: processEval,
|
|
46
|
+
process_insights: processInsights,
|
|
47
|
+
process_launch: processLaunch,
|
|
48
|
+
process_send_message: processSendMessage,
|
|
49
|
+
process_conversation: processConversation,
|
|
50
|
+
// agent_jobs kinds (Phase 4c Stage 3b, migration 00083). processSessionGoal
|
|
51
|
+
// and processAnnouncement take an optional deps object in the helpers
|
|
52
|
+
// position — every key is optional, so JobHelpers passing through is
|
|
53
|
+
// harmless and they fall back to their defaults.
|
|
54
|
+
process_session_goal: processSessionGoal,
|
|
55
|
+
process_announcement: processAnnouncement,
|
|
56
|
+
// Multi-session orchestration ("runs") worktree cleanup (Task 5.2). agent_jobs
|
|
57
|
+
// kind — no mirror table. Enqueued by POST /api/runs/:id/cleanup; prunes the
|
|
58
|
+
// worktrees of a run's ended sessions, guarding against uncommitted work.
|
|
59
|
+
process_run_cleanup: processRunCleanup,
|
|
60
|
+
cron_suggest_instructions: cronSuggestInstructions,
|
|
61
|
+
// Dropped by accident in the Phase 4c graphile→agent_jobs migration: the
|
|
62
|
+
// handler survived but lost its registration + schedule, so the skills
|
|
63
|
+
// registry froze (last refresh 2026-05-21) and the suggest cron marked
|
|
64
|
+
// every suggestion stale on each run. Re-scheduled by migration 00086.
|
|
65
|
+
cron_refresh_skills: cronRefreshSkills
|
|
66
|
+
};
|
|
67
|
+
var CAPABILITIES = Object.keys(HANDLERS);
|
|
68
|
+
var DEFAULT_POLL_WAIT_MS = 3e4;
|
|
69
|
+
var DEFAULT_HEARTBEAT_MS = 3e4;
|
|
70
|
+
var PRESENCE_HEARTBEAT_MS = 3e4;
|
|
71
|
+
var BACKOFF_INITIAL_MS = 250;
|
|
72
|
+
var BACKOFF_MAX_MS = 5e3;
|
|
73
|
+
var PRESENCE_CLIENT_NAME = `thin-agent-${process.pid}`;
|
|
74
|
+
function startPresenceHeartbeat(capabilities, signal, log) {
|
|
75
|
+
const send = (status) => {
|
|
76
|
+
void apiPost("/api/workers/heartbeat", {
|
|
77
|
+
workerType: "cli-worker",
|
|
78
|
+
clientName: PRESENCE_CLIENT_NAME,
|
|
79
|
+
workerVersion: "0.1.0",
|
|
80
|
+
currentJobId: null,
|
|
81
|
+
inFlightCount: 0,
|
|
82
|
+
lastError: null,
|
|
83
|
+
status,
|
|
84
|
+
metadata: { capabilities, mode: "thin-agent" }
|
|
85
|
+
}).catch((err) => {
|
|
86
|
+
structuredLog(log, {
|
|
87
|
+
event: "presence_heartbeat_error",
|
|
88
|
+
error: err instanceof Error ? err.message : String(err)
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
send("alive");
|
|
93
|
+
const timer = setInterval(() => send("alive"), PRESENCE_HEARTBEAT_MS);
|
|
94
|
+
signal.addEventListener("abort", () => {
|
|
95
|
+
clearInterval(timer);
|
|
96
|
+
send("shutting_down");
|
|
97
|
+
}, { once: true });
|
|
98
|
+
}
|
|
99
|
+
function structuredLog(log, event) {
|
|
100
|
+
try {
|
|
101
|
+
log(JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...event }));
|
|
102
|
+
} catch {
|
|
103
|
+
log(`[agent-loop] log_error event=${event["event"]}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function abortableSleep(ms, signal) {
|
|
107
|
+
if (signal.aborted) return Promise.resolve(false);
|
|
108
|
+
if (ms <= 0) return Promise.resolve(true);
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
const timer = setTimeout(() => {
|
|
111
|
+
signal.removeEventListener("abort", onAbort);
|
|
112
|
+
resolve(true);
|
|
113
|
+
}, ms);
|
|
114
|
+
const onAbort = () => {
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
signal.removeEventListener("abort", onAbort);
|
|
117
|
+
resolve(false);
|
|
118
|
+
};
|
|
119
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async function pollForWork(capabilities, waitMs) {
|
|
123
|
+
const qs = `capabilities=${encodeURIComponent(capabilities.join(","))}&waitMs=${waitMs}`;
|
|
124
|
+
const result = await apiGet(`/api/work/next?${qs}`);
|
|
125
|
+
if (result == null || typeof result === "string") return null;
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
function makeHelpers(attempts, log) {
|
|
129
|
+
return {
|
|
130
|
+
logger: {
|
|
131
|
+
info: (msg) => log(msg),
|
|
132
|
+
warn: (msg) => log(msg),
|
|
133
|
+
error: (msg) => log(msg)
|
|
134
|
+
},
|
|
135
|
+
job: { attempts }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function runOne(job, heartbeatIntervalMs, log) {
|
|
139
|
+
const handler = HANDLERS[job.kind];
|
|
140
|
+
const startedAt = Date.now();
|
|
141
|
+
structuredLog(log, {
|
|
142
|
+
event: "claim",
|
|
143
|
+
jobId: job.id,
|
|
144
|
+
kind: job.kind,
|
|
145
|
+
attempts: job.attempts
|
|
146
|
+
});
|
|
147
|
+
if (!handler) {
|
|
148
|
+
const msg = `unknown kind: ${job.kind}`;
|
|
149
|
+
structuredLog(log, {
|
|
150
|
+
event: "fail",
|
|
151
|
+
jobId: job.id,
|
|
152
|
+
kind: job.kind,
|
|
153
|
+
terminal: true,
|
|
154
|
+
error: msg
|
|
155
|
+
});
|
|
156
|
+
await apiPost(`/api/work/${job.id}/fail`, {
|
|
157
|
+
leaseToken: job.leaseToken,
|
|
158
|
+
error: msg,
|
|
159
|
+
terminal: true
|
|
160
|
+
}).catch(() => {
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const heartbeatTimer = setInterval(() => {
|
|
165
|
+
structuredLog(log, { event: "heartbeat", jobId: job.id });
|
|
166
|
+
apiPost(`/api/work/${job.id}/heartbeat`, {
|
|
167
|
+
leaseToken: job.leaseToken
|
|
168
|
+
}).catch((err) => {
|
|
169
|
+
structuredLog(log, {
|
|
170
|
+
event: "heartbeat_error",
|
|
171
|
+
jobId: job.id,
|
|
172
|
+
error: err instanceof Error ? err.message : String(err)
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}, heartbeatIntervalMs);
|
|
176
|
+
try {
|
|
177
|
+
const helpers = makeHelpers(job.attempts, log);
|
|
178
|
+
const result = await handler(job.payload, helpers) ?? {};
|
|
179
|
+
clearInterval(heartbeatTimer);
|
|
180
|
+
structuredLog(log, {
|
|
181
|
+
event: "complete",
|
|
182
|
+
jobId: job.id,
|
|
183
|
+
kind: job.kind,
|
|
184
|
+
durationMs: Date.now() - startedAt
|
|
185
|
+
});
|
|
186
|
+
await apiPost(`/api/work/${job.id}/complete`, {
|
|
187
|
+
leaseToken: job.leaseToken,
|
|
188
|
+
result
|
|
189
|
+
});
|
|
190
|
+
} catch (err) {
|
|
191
|
+
clearInterval(heartbeatTimer);
|
|
192
|
+
const terminal = isPermanentJobError(err);
|
|
193
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
194
|
+
structuredLog(log, {
|
|
195
|
+
event: "fail",
|
|
196
|
+
jobId: job.id,
|
|
197
|
+
kind: job.kind,
|
|
198
|
+
durationMs: Date.now() - startedAt,
|
|
199
|
+
terminal,
|
|
200
|
+
error: message
|
|
201
|
+
});
|
|
202
|
+
await apiPost(`/api/work/${job.id}/fail`, {
|
|
203
|
+
leaseToken: job.leaseToken,
|
|
204
|
+
error: message,
|
|
205
|
+
terminal
|
|
206
|
+
}).catch((postErr) => {
|
|
207
|
+
structuredLog(log, {
|
|
208
|
+
event: "fail_post_error",
|
|
209
|
+
jobId: job.id,
|
|
210
|
+
error: postErr instanceof Error ? postErr.message : String(postErr)
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async function runAgentLoop(opts) {
|
|
216
|
+
const log = opts.log ?? (() => void 0);
|
|
217
|
+
const pollWaitMs = opts.pollWaitMs ?? DEFAULT_POLL_WAIT_MS;
|
|
218
|
+
const heartbeatIntervalMs = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_MS;
|
|
219
|
+
const capabilities = opts.capabilities ?? CAPABILITIES;
|
|
220
|
+
let backoffMs = BACKOFF_INITIAL_MS;
|
|
221
|
+
structuredLog(log, {
|
|
222
|
+
event: "agent_start",
|
|
223
|
+
capabilities,
|
|
224
|
+
pollWaitMs,
|
|
225
|
+
heartbeatIntervalMs
|
|
226
|
+
});
|
|
227
|
+
startPresenceHeartbeat(capabilities, opts.signal, log);
|
|
228
|
+
void startTerminalTargetHeartbeat({ signal: opts.signal, log }).catch((err) => {
|
|
229
|
+
structuredLog(log, {
|
|
230
|
+
event: "tt_heartbeat_fatal",
|
|
231
|
+
error: err instanceof Error ? err.message : String(err)
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
while (!opts.signal.aborted) {
|
|
235
|
+
let job = null;
|
|
236
|
+
try {
|
|
237
|
+
job = await pollForWork(capabilities, pollWaitMs);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const status = err instanceof ApiError ? err.statusCode : void 0;
|
|
240
|
+
structuredLog(log, {
|
|
241
|
+
event: "poll_error",
|
|
242
|
+
status,
|
|
243
|
+
error: err instanceof Error ? err.message : String(err)
|
|
244
|
+
});
|
|
245
|
+
const completed = await abortableSleep(backoffMs, opts.signal);
|
|
246
|
+
if (!completed) break;
|
|
247
|
+
backoffMs = Math.min(backoffMs * 2, BACKOFF_MAX_MS);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (!job) {
|
|
251
|
+
structuredLog(log, { event: "poll_204" });
|
|
252
|
+
const completed = await abortableSleep(backoffMs, opts.signal);
|
|
253
|
+
if (!completed) break;
|
|
254
|
+
backoffMs = Math.min(backoffMs * 2, BACKOFF_MAX_MS);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
backoffMs = BACKOFF_INITIAL_MS;
|
|
258
|
+
await runOne(job, heartbeatIntervalMs, log);
|
|
259
|
+
}
|
|
260
|
+
structuredLog(log, { event: "agent_stop" });
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export {
|
|
264
|
+
HANDLERS,
|
|
265
|
+
CAPABILITIES,
|
|
266
|
+
pollForWork,
|
|
267
|
+
runAgentLoop
|
|
268
|
+
};
|
|
269
|
+
//# sourceMappingURL=chunk-WFULKPEQ.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/agent-loop.ts"],
|
|
4
|
+
"sourcesContent": ["// Phase 4b thin-agent migration: the parallel-run worker loop that replaces\n// graphile-worker's LISTEN/NOTIFY pickup with HTTP long-polling against the\n// Phase 4a /api/work endpoints. See docs/plans/2026-05-25-thin-agent-migration.md.\n//\n// This file is invoked exclusively by `rulemetric evals agent` \u2014 the only\n// worker mode since Phase 4c deleted the graphile path.\n//\n// Lifecycle for one cycle:\n// 1. Long-poll GET /api/work/next?capabilities=...&waitMs=...\n// 2. If 204 (returned as \"\" by api-client because no JSON body), increment\n// a small backoff capped at 5s and re-poll.\n// 3. If 200, dispatch by `kind` to the matching handler from HANDLERS.\n// 4. Start a heartbeat timer that POSTs /api/work/:id/heartbeat at\n// heartbeatIntervalMs while the handler runs.\n// 5. On success: POST /api/work/:id/complete with { result, leaseToken }.\n// On PermanentJobError: POST /fail with terminal=true (server will not\n// requeue regardless of attempts). On any other error: POST /fail with\n// terminal=false (server requeues if attempts < max).\n//\n// Abort behavior: an AbortSignal short-circuits the next long-poll and any\n// backoff sleep. An in-flight handler can't be cancelled (it has already\n// spawned `claude` subprocesses), so we await it to natural completion and\n// then exit. This matches listen.ts's 10s shutdown grace pattern, except we\n// don't need an outer hard-kill timer here \u2014 the caller (the oclif command)\n// owns the process.exit.\n\nimport type { JobHelpers } from './job-helpers.js';\nimport { apiGet, apiPost, ApiError } from './api-client.js';\nimport { isPermanentJobError } from './permanent-job-error.js';\nimport { processEval } from './handlers/process-eval.js';\nimport { processInsights } from './handlers/process-insights.js';\nimport { processLaunch } from './handlers/process-launch.js';\nimport { processConversation } from './handlers/process-conversation.js';\nimport { processSendMessage } from './handlers/process-send-message.js';\nimport { processSessionGoal } from './handlers/process-session-goal.js';\nimport { processAnnouncement } from './handlers/process-announcement.js';\nimport { processRunCleanup } from './handlers/process-run-cleanup.js';\nimport { cronSuggestInstructions } from './handlers/cron-suggest-instructions.js';\nimport { cronRefreshSkills } from './handlers/cron-refresh-skills.js';\nimport { startTerminalTargetHeartbeat } from './terminal-target-heartbeat.js';\n\n// Handler dispatch table. Keys MUST match the API's CAPABILITY_TO_TABLE keys\n// in apps/api/src/routes/work.ts; mismatches would cause the API to silently\n// drop the capability and starve this kind of work.\ntype Handler = (\n payload: Record<string, unknown>,\n helpers: JobHelpers,\n) => Promise<Record<string, unknown> | undefined | void>;\n\nexport const HANDLERS: Record<string, Handler> = {\n process_eval: processEval as unknown as Handler,\n process_insights: processInsights as unknown as Handler,\n process_launch: processLaunch as unknown as Handler,\n process_send_message: processSendMessage as unknown as Handler,\n process_conversation: processConversation as unknown as Handler,\n // agent_jobs kinds (Phase 4c Stage 3b, migration 00083). processSessionGoal\n // and processAnnouncement take an optional deps object in the helpers\n // position \u2014 every key is optional, so JobHelpers passing through is\n // harmless and they fall back to their defaults.\n process_session_goal: processSessionGoal as unknown as Handler,\n process_announcement: processAnnouncement as unknown as Handler,\n // Multi-session orchestration (\"runs\") worktree cleanup (Task 5.2). agent_jobs\n // kind \u2014 no mirror table. Enqueued by POST /api/runs/:id/cleanup; prunes the\n // worktrees of a run's ended sessions, guarding against uncommitted work.\n process_run_cleanup: processRunCleanup as unknown as Handler,\n cron_suggest_instructions: cronSuggestInstructions as unknown as Handler,\n // Dropped by accident in the Phase 4c graphile\u2192agent_jobs migration: the\n // handler survived but lost its registration + schedule, so the skills\n // registry froze (last refresh 2026-05-21) and the suggest cron marked\n // every suggestion stale on each run. Re-scheduled by migration 00086.\n cron_refresh_skills: cronRefreshSkills as unknown as Handler,\n};\n\nexport const CAPABILITIES: readonly string[] = Object.keys(HANDLERS);\n\ninterface NextWorkResponse {\n id: string;\n kind: string;\n payload: Record<string, unknown>;\n attempts: number;\n leaseToken: string;\n leaseDurationSeconds: number;\n table: string;\n}\n\nexport interface RunAgentLoopOptions {\n signal: AbortSignal;\n log?: (msg: string) => void;\n /** Long-poll wait passed to GET /api/work/next?waitMs= */\n pollWaitMs?: number;\n /** How often to POST /api/work/:id/heartbeat while a handler runs */\n heartbeatIntervalMs?: number;\n /** Capability list to advertise. Defaults to all known handlers. */\n capabilities?: readonly string[];\n}\n\nconst DEFAULT_POLL_WAIT_MS = 30_000;\nconst DEFAULT_HEARTBEAT_MS = 30_000;\nconst PRESENCE_HEARTBEAT_MS = 30_000;\nconst BACKOFF_INITIAL_MS = 250;\nconst BACKOFF_MAX_MS = 5_000;\n\n// Stable per-process identifier so worker_connections groups the same agent\n// across heartbeats (the unique key is (userId, workerType, clientName)).\nconst PRESENCE_CLIENT_NAME = `thin-agent-${process.pid}`;\n\n/**\n * Background presence heartbeat. Posts to /api/workers/heartbeat every 30s so\n * worker_connections has a fresh row \u2014 that's what the dashboard's\n * useWorkerStatus reads to decide \"Worker online\" for live-send gating.\n * Distinct from the per-job heartbeat in runOne, which only extends a\n * specific job's lease. The graphile-worker runner had this since day one;\n * the thin agent was missing it, so the dashboard showed \"Worker offline\"\n * even when the agent was actively processing jobs.\n */\nfunction startPresenceHeartbeat(\n capabilities: readonly string[],\n signal: AbortSignal,\n log: (msg: string) => void,\n): void {\n const send = (status: 'alive' | 'shutting_down') => {\n void apiPost('/api/workers/heartbeat', {\n workerType: 'cli-worker',\n clientName: PRESENCE_CLIENT_NAME,\n workerVersion: '0.1.0',\n currentJobId: null,\n inFlightCount: 0,\n lastError: null,\n status,\n metadata: { capabilities, mode: 'thin-agent' },\n }).catch((err) => {\n structuredLog(log, {\n event: 'presence_heartbeat_error',\n error: err instanceof Error ? err.message : String(err),\n });\n });\n };\n send('alive');\n const timer = setInterval(() => send('alive'), PRESENCE_HEARTBEAT_MS);\n signal.addEventListener('abort', () => {\n clearInterval(timer);\n send('shutting_down');\n }, { once: true });\n}\n\nfunction structuredLog(\n log: (msg: string) => void,\n event: Record<string, unknown>,\n): void {\n try {\n log(JSON.stringify({ ts: new Date().toISOString(), ...event }));\n } catch {\n // JSON.stringify can throw on a circular structure; fall back to a\n // best-effort string so a log failure never takes down the loop.\n log(`[agent-loop] log_error event=${event['event']}`);\n }\n}\n\n/** Sleep that resolves early when the abort signal fires. Returns true if\n * the full duration elapsed, false if aborted. */\nfunction abortableSleep(ms: number, signal: AbortSignal): Promise<boolean> {\n if (signal.aborted) return Promise.resolve(false);\n if (ms <= 0) return Promise.resolve(true);\n return new Promise<boolean>((resolve) => {\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve(true);\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n signal.removeEventListener('abort', onAbort);\n resolve(false);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** Poll once for work. Returns the parsed response or null on 204. api-client\n * returns \"\" for an empty response body (Content-Type is not JSON on 204), so\n * we use that as the 204 sentinel. */\nexport async function pollForWork(\n capabilities: readonly string[],\n waitMs: number,\n): Promise<NextWorkResponse | null> {\n const qs = `capabilities=${encodeURIComponent(capabilities.join(','))}&waitMs=${waitMs}`;\n const result = await apiGet<NextWorkResponse | string>(`/api/work/next?${qs}`);\n if (result == null || typeof result === 'string') return null;\n return result;\n}\n\n/** Construct a minimal JobHelpers shim. Handlers only touch\n * helpers.logger.{info,warn,error}(msg) and helpers.job.attempts \u2014 verified\n * by grep against apps/cli/src/lib/handlers/. We cast through `unknown` so\n * TS accepts the structurally smaller object as the full JobHelpers type;\n * pulling graphile-worker into this hot path would defeat the Phase 4c\n * cleanup that removes the dep entirely. */\nfunction makeHelpers(attempts: number, log: (msg: string) => void): JobHelpers {\n return {\n logger: {\n info: (msg: string) => log(msg),\n warn: (msg: string) => log(msg),\n error: (msg: string) => log(msg),\n },\n job: { attempts },\n };\n}\n\nasync function runOne(\n job: NextWorkResponse,\n heartbeatIntervalMs: number,\n log: (msg: string) => void,\n): Promise<void> {\n const handler = HANDLERS[job.kind];\n const startedAt = Date.now();\n structuredLog(log, {\n event: 'claim',\n jobId: job.id,\n kind: job.kind,\n attempts: job.attempts,\n });\n\n // Defensive: if the API returned a kind the agent doesn't know about\n // (capability filter mismatch, schema drift), fail terminally so the row\n // doesn't bounce forever. The /api/work/next filter should already prevent\n // this, but failing closed at the dispatcher means a single new kind on\n // the API side can't wedge an older agent.\n if (!handler) {\n const msg = `unknown kind: ${job.kind}`;\n structuredLog(log, {\n event: 'fail',\n jobId: job.id,\n kind: job.kind,\n terminal: true,\n error: msg,\n });\n await apiPost(`/api/work/${job.id}/fail`, {\n leaseToken: job.leaseToken,\n error: msg,\n terminal: true,\n }).catch(() => {\n // best-effort: the lease will expire and the reconciler reclaims it\n });\n return;\n }\n\n // Heartbeat timer. Starts after the first heartbeatIntervalMs elapses so\n // we don't spam an extra request for sub-second jobs. Errors are swallowed\n // \u2014 a single failed heartbeat doesn't abort the run; the server's\n // 5-minute lease gives us up to ten chances at 30s intervals before we\n // lose the claim.\n const heartbeatTimer = setInterval(() => {\n structuredLog(log, { event: 'heartbeat', jobId: job.id });\n apiPost(`/api/work/${job.id}/heartbeat`, {\n leaseToken: job.leaseToken,\n }).catch((err) => {\n structuredLog(log, {\n event: 'heartbeat_error',\n jobId: job.id,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }, heartbeatIntervalMs);\n\n try {\n const helpers = makeHelpers(job.attempts, log);\n const result = (await handler(job.payload, helpers)) ?? {};\n clearInterval(heartbeatTimer);\n structuredLog(log, {\n event: 'complete',\n jobId: job.id,\n kind: job.kind,\n durationMs: Date.now() - startedAt,\n });\n await apiPost(`/api/work/${job.id}/complete`, {\n leaseToken: job.leaseToken,\n result,\n });\n } catch (err) {\n clearInterval(heartbeatTimer);\n const terminal = isPermanentJobError(err);\n const message = err instanceof Error ? err.message : String(err);\n structuredLog(log, {\n event: 'fail',\n jobId: job.id,\n kind: job.kind,\n durationMs: Date.now() - startedAt,\n terminal,\n error: message,\n });\n await apiPost(`/api/work/${job.id}/fail`, {\n leaseToken: job.leaseToken,\n error: message,\n terminal,\n }).catch((postErr) => {\n structuredLog(log, {\n event: 'fail_post_error',\n jobId: job.id,\n error: postErr instanceof Error ? postErr.message : String(postErr),\n });\n });\n }\n}\n\nexport async function runAgentLoop(opts: RunAgentLoopOptions): Promise<void> {\n const log = opts.log ?? (() => undefined);\n const pollWaitMs = opts.pollWaitMs ?? DEFAULT_POLL_WAIT_MS;\n const heartbeatIntervalMs = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_MS;\n const capabilities = opts.capabilities ?? CAPABILITIES;\n\n let backoffMs = BACKOFF_INITIAL_MS;\n structuredLog(log, {\n event: 'agent_start',\n capabilities,\n pollWaitMs,\n heartbeatIntervalMs,\n });\n\n // Background presence heartbeat \u2014 writes to worker_connections so the\n // dashboard's \"Worker online\" indicator turns on. Fire-and-forget; failures\n // are logged but don't block the work poll.\n startPresenceHeartbeat(capabilities, opts.signal, log);\n\n // Fire-and-forget the terminal-target liveness heartbeat. It runs on its\n // own interval (default 60s) and shuts down on the same abort signal.\n // Errors are caught internally \u2014 we don't await it so a slow tmux probe\n // can't delay the work poll.\n void startTerminalTargetHeartbeat({ signal: opts.signal, log }).catch((err) => {\n structuredLog(log, {\n event: 'tt_heartbeat_fatal',\n error: err instanceof Error ? err.message : String(err),\n });\n });\n\n while (!opts.signal.aborted) {\n let job: NextWorkResponse | null = null;\n try {\n job = await pollForWork(capabilities, pollWaitMs);\n } catch (err) {\n // Network/API errors during poll: log + backoff. The API may be\n // restarting, the laptop may have just woken, etc. Don't crash the\n // loop \u2014 that's the whole point of this migration.\n const status = err instanceof ApiError ? err.statusCode : undefined;\n structuredLog(log, {\n event: 'poll_error',\n status,\n error: err instanceof Error ? err.message : String(err),\n });\n const completed = await abortableSleep(backoffMs, opts.signal);\n if (!completed) break;\n backoffMs = Math.min(backoffMs * 2, BACKOFF_MAX_MS);\n continue;\n }\n\n if (!job) {\n structuredLog(log, { event: 'poll_204' });\n const completed = await abortableSleep(backoffMs, opts.signal);\n if (!completed) break;\n backoffMs = Math.min(backoffMs * 2, BACKOFF_MAX_MS);\n continue;\n }\n\n // Got work \u2014 reset the backoff and run it. An in-flight handler is\n // intentionally not abort-cancellable; we await its natural completion\n // even if the signal fires mid-run.\n backoffMs = BACKOFF_INITIAL_MS;\n await runOne(job, heartbeatIntervalMs, log);\n }\n\n structuredLog(log, { event: 'agent_stop' });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HBar,
|
|
3
|
+
Panel,
|
|
4
|
+
fit,
|
|
5
|
+
friendlyLabel
|
|
6
|
+
} from "./chunk-DQ3KELXD.js";
|
|
7
|
+
import {
|
|
8
|
+
ORANGE,
|
|
9
|
+
RED
|
|
10
|
+
} from "./chunk-QJQS6TUN.js";
|
|
11
|
+
|
|
12
|
+
// src/dashboard/panels/friction.tsx
|
|
13
|
+
import { Text } from "ink";
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
function FrictionPanel({ api, width, barWidth }) {
|
|
16
|
+
if (!api) {
|
|
17
|
+
return /* @__PURE__ */ jsx(Panel, { title: "Friction Points", color: RED, width, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "API offline \u2014 no friction data" }) });
|
|
18
|
+
}
|
|
19
|
+
const friction = api.friction ?? {};
|
|
20
|
+
const sorted = Object.entries(friction).sort(([, a], [, b]) => b - a);
|
|
21
|
+
if (sorted.length === 0) {
|
|
22
|
+
return /* @__PURE__ */ jsx(Panel, { title: "Friction Points", color: ORANGE, width, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No friction detected \u2014 nice!" }) });
|
|
23
|
+
}
|
|
24
|
+
const max = sorted[0][1];
|
|
25
|
+
const total = sorted.reduce((s, [, v]) => s + v, 0);
|
|
26
|
+
const nw = Math.max(8, width - barWidth - 20);
|
|
27
|
+
return /* @__PURE__ */ jsx(Panel, { title: `Friction Points (${total} incidents)`, color: RED, width, children: sorted.map(([key, value]) => {
|
|
28
|
+
const pct = total > 0 ? Math.round(value / total * 100) : 0;
|
|
29
|
+
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
|
|
30
|
+
/* @__PURE__ */ jsx(HBar, { value, max, width: barWidth }),
|
|
31
|
+
/* @__PURE__ */ jsxs(Text, { color: ORANGE, children: [
|
|
32
|
+
" ",
|
|
33
|
+
fit(friendlyLabel(key), nw)
|
|
34
|
+
] }),
|
|
35
|
+
/* @__PURE__ */ jsx(Text, { children: String(value).padStart(5) }),
|
|
36
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: String(pct + "%").padStart(5) })
|
|
37
|
+
] }, key);
|
|
38
|
+
}) });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
FrictionPanel
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=chunk-XC6M4CSW.js.map
|