@tekmidian/pai 0.42.5 → 0.42.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +9 -9
- package/README.md +26 -8
- package/dist/{aibroker-client-BP74gGwD.mjs → aibroker-client-Bn9SnGMa.mjs} +3 -3
- package/dist/{aibroker-client-BP74gGwD.mjs.map → aibroker-client-Bn9SnGMa.mjs.map} +1 -1
- package/dist/{aibroker-client-C6m71p6O.mjs → aibroker-client-D5NT0S1N.mjs} +1 -1
- package/dist/{auto-route-_5zzJz5q.mjs → auto-route-CcD0OWWB.mjs} +4 -4
- package/dist/{auto-route-_5zzJz5q.mjs.map → auto-route-CcD0OWWB.mjs.map} +1 -1
- package/dist/{chain-DTII7xeL.mjs → chain-BbcfP77K.mjs} +5 -4
- package/dist/{chain-DTII7xeL.mjs.map → chain-BbcfP77K.mjs.map} +1 -1
- package/dist/cli/index.mjs +23 -21
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.d.mts.map +1 -1
- package/dist/cli/program.mjs +23 -21
- package/dist/{clusters-j0ZuNYp9.mjs → clusters-Cw_P6lO-.mjs} +2 -2
- package/dist/{clusters-j0ZuNYp9.mjs.map → clusters-Cw_P6lO-.mjs.map} +1 -1
- package/dist/{config-B64vFg14.mjs → config-DCu8THKi.mjs} +41 -9
- package/dist/{config-B64vFg14.mjs.map → config-DCu8THKi.mjs.map} +1 -1
- package/dist/config-DeqFqa1N.mjs +3 -0
- package/dist/config-DxMZjpvY.mjs +1289 -0
- package/dist/config-DxMZjpvY.mjs.map +1 -0
- package/dist/context-handover-cache-B9NKSjwR.mjs +3242 -0
- package/dist/context-handover-cache-B9NKSjwR.mjs.map +1 -0
- package/dist/daemon/index.mjs +23 -22
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/daemon-BNjbVsQU.mjs +24 -0
- package/dist/{daemon-B8N1egl0.mjs → daemon-BppziPi6.mjs} +52 -38
- package/dist/daemon-BppziPi6.mjs.map +1 -0
- package/dist/daemon-mcp/index.mjs +144 -117
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/db-BOBfewFH.mjs +3 -0
- package/dist/{db-a1ixZQjr.mjs → db-DJ8rk0VM.mjs} +15 -6
- package/dist/{db-a1ixZQjr.mjs.map → db-DJ8rk0VM.mjs.map} +1 -1
- package/dist/db-DbY2O8QO.mjs +3 -0
- package/dist/{db-Ca5qfsMC.mjs → db-Ddns80yf.mjs} +15 -6
- package/dist/{db-Ca5qfsMC.mjs.map → db-Ddns80yf.mjs.map} +1 -1
- package/dist/{detect-CdaA48EI.mjs → detect-Bf2z-oKB.mjs} +1 -1
- package/dist/{detect-CdaA48EI.mjs.map → detect-Bf2z-oKB.mjs.map} +1 -1
- package/dist/detector-CkwkXuGh.mjs +5 -0
- package/dist/{detector-C73Nxm94.mjs → detector-DWXkeTlk.mjs} +2 -2
- package/dist/{detector-C73Nxm94.mjs.map → detector-DWXkeTlk.mjs.map} +1 -1
- package/dist/{embeddings-CEBGrzwu.mjs → embeddings-ClqKtLZ8.mjs} +1 -1
- package/dist/{embeddings-DOLZnT1X.mjs → embeddings-DvRKcQyt.mjs} +1 -1
- package/dist/{embeddings-DOLZnT1X.mjs.map → embeddings-DvRKcQyt.mjs.map} +1 -1
- package/dist/factory-47Qf_df7.mjs +3 -0
- package/dist/{factory-DEb9NmHJ.mjs → factory-DNYAqjH0.mjs} +8 -8
- package/dist/{factory-DEb9NmHJ.mjs.map → factory-DNYAqjH0.mjs.map} +1 -1
- package/dist/{fallback-oJl3BaIN.mjs → fallback-Cwt4hmh5.mjs} +182 -122
- package/dist/fallback-Cwt4hmh5.mjs.map +1 -0
- package/dist/{helpers-IjZkXBhj.mjs → helpers-crDEr6S2.mjs} +1 -1
- package/dist/{helpers-IjZkXBhj.mjs.map → helpers-crDEr6S2.mjs.map} +1 -1
- package/dist/hooks/capture-all-events.mjs +117 -34
- package/dist/hooks/capture-all-events.mjs.map +4 -4
- package/dist/hooks/capture-session-summary.mjs +110 -33
- package/dist/hooks/capture-session-summary.mjs.map +4 -4
- package/dist/hooks/capture-tool-output.mjs +105 -28
- package/dist/hooks/capture-tool-output.mjs.map +4 -4
- package/dist/hooks/cleanup-session-files.mjs +54 -13
- package/dist/hooks/cleanup-session-files.mjs.map +2 -2
- package/dist/hooks/context-compression-hook.mjs +7565 -122
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/initialize-session.mjs +55 -14
- package/dist/hooks/initialize-session.mjs.map +2 -2
- package/dist/hooks/inject-observations.mjs +79 -18
- package/dist/hooks/inject-observations.mjs.map +3 -3
- package/dist/hooks/load-core-context.mjs +55 -14
- package/dist/hooks/load-core-context.mjs.map +2 -2
- package/dist/hooks/load-project-context.mjs +185 -103
- package/dist/hooks/load-project-context.mjs.map +4 -4
- package/dist/hooks/mcp-deferred-gate.mjs +54 -13
- package/dist/hooks/mcp-deferred-gate.mjs.map +2 -2
- package/dist/hooks/mcp-deferred-reminder.mjs +9 -0
- package/dist/hooks/mcp-deferred-reminder.mjs.map +3 -3
- package/dist/hooks/observe.mjs +54 -13
- package/dist/hooks/observe.mjs.map +2 -2
- package/dist/hooks/post-compact-inject.mjs +7419 -16
- package/dist/hooks/post-compact-inject.mjs.map +4 -4
- package/dist/hooks/route-agents-to-worker.mjs +7778 -171
- package/dist/hooks/route-agents-to-worker.mjs.map +4 -4
- package/dist/hooks/route-edits-to-worker.mjs +90 -0
- package/dist/hooks/route-edits-to-worker.mjs.map +7 -0
- package/dist/hooks/security-validator.mjs +147 -6
- package/dist/hooks/security-validator.mjs.map +4 -4
- package/dist/hooks/session-commands.mjs +9 -0
- package/dist/hooks/session-commands.mjs.map +3 -3
- package/dist/hooks/stop-hook.mjs +182 -105
- package/dist/hooks/stop-hook.mjs.map +4 -4
- package/dist/hooks/subagent-stop-hook.mjs +3 -0
- package/dist/hooks/subagent-stop-hook.mjs.map +1 -1
- package/dist/hooks/sync-todo-to-md.mjs +54 -13
- package/dist/hooks/sync-todo-to-md.mjs.map +2 -2
- package/dist/hooks/update-tab-on-action.mjs +3 -0
- package/dist/hooks/update-tab-on-action.mjs.map +1 -1
- package/dist/hooks/update-tab-titles.mjs +3 -0
- package/dist/hooks/update-tab-titles.mjs.map +1 -1
- package/dist/hooks/whisper-reinject.mjs +3 -0
- package/dist/hooks/whisper-reinject.mjs.map +1 -1
- package/dist/hooks/whisper-rules.mjs +134 -29
- package/dist/hooks/whisper-rules.mjs.map +4 -4
- package/dist/hooks/worker-proxy.mjs +7737 -117
- package/dist/hooks/worker-proxy.mjs.map +4 -4
- package/dist/hooks/worker-status-line.mjs +7791 -144
- package/dist/hooks/worker-status-line.mjs.map +4 -4
- package/dist/hooks/worker-supervision.mjs +7721 -115
- package/dist/hooks/worker-supervision.mjs.map +4 -4
- package/dist/index.d.mts +4 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +10 -10
- package/dist/{indexer-backend-BPTzKFZU.mjs → indexer-backend-CdvCJCkD.mjs} +3 -3
- package/dist/{indexer-backend-BPTzKFZU.mjs.map → indexer-backend-CdvCJCkD.mjs.map} +1 -1
- package/dist/{ipc-client-BmypMNYk.mjs → ipc-client-C6NryMMb.mjs} +2 -2
- package/dist/{ipc-client-BmypMNYk.mjs.map → ipc-client-C6NryMMb.mjs.map} +1 -1
- package/dist/{kg-entity-r8duqhi9.mjs → kg-entity-BSjM5xZh.mjs} +1 -1
- package/dist/{kg-entity-r8duqhi9.mjs.map → kg-entity-BSjM5xZh.mjs.map} +1 -1
- package/dist/{latent-ideas-CtSca4qG.mjs → latent-ideas-BfL4nCQ3.mjs} +4 -4
- package/dist/{latent-ideas-CtSca4qG.mjs.map → latent-ideas-BfL4nCQ3.mjs.map} +1 -1
- package/dist/{link-boost-Bucnz3n8.mjs → link-boost-C5PaNdzm.mjs} +1 -1
- package/dist/{link-boost-Bucnz3n8.mjs.map → link-boost-C5PaNdzm.mjs.map} +1 -1
- package/dist/main-resolver-CnfnWa8C.mjs +7 -0
- package/dist/{main-resolver-DnkxPYkr.mjs → main-resolver-DvYu9jbl.mjs} +21 -11
- package/dist/main-resolver-DvYu9jbl.mjs.map +1 -0
- package/dist/{migrate-Cjzeefn9.mjs → migrate-CfERwXhY.mjs} +2 -2
- package/dist/{migrate-Cjzeefn9.mjs.map → migrate-CfERwXhY.mjs.map} +1 -1
- package/dist/{neighborhood-CM7Jgb51.mjs → neighborhood-CETR_P4y.mjs} +2 -2
- package/dist/{neighborhood-CM7Jgb51.mjs.map → neighborhood-CETR_P4y.mjs.map} +1 -1
- package/dist/{note-context-DCwE2A-M.mjs → note-context-DCcRWBoN.mjs} +1 -1
- package/dist/{note-context-DCwE2A-M.mjs.map → note-context-DCcRWBoN.mjs.map} +1 -1
- package/dist/pai-home-ChAOupZc.mjs +164 -0
- package/dist/pai-home-ChAOupZc.mjs.map +1 -0
- package/dist/{pai-marker-CHtbJMwJ.mjs → pai-marker-B20KqhA8.mjs} +1 -1
- package/dist/{pai-marker-CHtbJMwJ.mjs.map → pai-marker-B20KqhA8.mjs.map} +1 -1
- package/dist/{planner-D5Ui7DAm.mjs → planner-pXRc-8yt.mjs} +7 -6
- package/dist/{planner-D5Ui7DAm.mjs.map → planner-pXRc-8yt.mjs.map} +1 -1
- package/dist/{postgres-CtOzfoQU.mjs → postgres-CUSXWgTG.mjs} +2 -2
- package/dist/{postgres-CtOzfoQU.mjs.map → postgres-CUSXWgTG.mjs.map} +1 -1
- package/dist/{program-zpoYnJGz.mjs → program-LLNPpxlj.mjs} +8308 -6065
- package/dist/program-LLNPpxlj.mjs.map +1 -0
- package/dist/query-feedback-C7rSfiXU.mjs +3 -0
- package/dist/{query-feedback-Dqz-HC__.mjs → query-feedback-CYyOGi3y.mjs} +20 -6
- package/dist/query-feedback-CYyOGi3y.mjs.map +1 -0
- package/dist/{reranker-CwTCNsgA.mjs → reranker-B5qUTamW.mjs} +1 -1
- package/dist/{reranker-xPm04PXx.mjs → reranker-HHmhZk6v.mjs} +1 -1
- package/dist/{reranker-xPm04PXx.mjs.map → reranker-HHmhZk6v.mjs.map} +1 -1
- package/dist/router-CremHKTI.mjs +3 -0
- package/dist/{router-DD6D4j31.mjs → router-DBAZfE7X.mjs} +2 -2
- package/dist/{router-DD6D4j31.mjs.map → router-DBAZfE7X.mjs.map} +1 -1
- package/dist/{run-D7K5UALn.mjs → run-DDdT9teG.mjs} +530 -210
- package/dist/run-DDdT9teG.mjs.map +1 -0
- package/dist/{runtime-paths-rni52zHX.mjs → runtime-paths-B0P1TvUr.mjs} +1 -1
- package/dist/{runtime-paths-rni52zHX.mjs.map → runtime-paths-B0P1TvUr.mjs.map} +1 -1
- package/dist/{search-Rpk1cSBC.mjs → search-B69cQwDB.mjs} +3 -3
- package/dist/{search-Rpk1cSBC.mjs.map → search-B69cQwDB.mjs.map} +1 -1
- package/dist/{search-CfPpJAWQ.mjs → search-fb-5ovj4.mjs} +2 -2
- package/dist/{server-D4vAieF4.mjs → server-Ch99xt5K.mjs} +15 -14
- package/dist/server-Ch99xt5K.mjs.map +1 -0
- package/dist/skills/Advisor/SKILL.md +3 -3
- package/dist/skills/Providers/SKILL.md +30 -0
- package/dist/skills/Reconstruct/SKILL.md +1 -1
- package/dist/skills/VaultContext/SKILL.md +1 -1
- package/dist/skills/Whisper/SKILL.md +3 -3
- package/dist/skills/Worker/SKILL.md +1 -1
- package/dist/{sources-CS43CpuS.mjs → sources-KBGEA_E6.mjs} +2 -2
- package/dist/{sources-CS43CpuS.mjs.map → sources-KBGEA_E6.mjs.map} +1 -1
- package/dist/{sqlite-Cq3gJcq9.mjs → sqlite-By6r2YhZ.mjs} +3 -3
- package/dist/{sqlite-Cq3gJcq9.mjs.map → sqlite-By6r2YhZ.mjs.map} +1 -1
- package/dist/{state-CY6I-Hnc.mjs → state-DnYGRmS7.mjs} +1 -1
- package/dist/{state-BRdB-Bf1.mjs → state-PJrgfDLW.mjs} +1 -1
- package/dist/{state-BRdB-Bf1.mjs.map → state-PJrgfDLW.mjs.map} +1 -1
- package/dist/{stop-words-Hfu8u22w.mjs → stop-words-BaMEGVeY.mjs} +1 -1
- package/dist/{stop-words-Hfu8u22w.mjs.map → stop-words-BaMEGVeY.mjs.map} +1 -1
- package/dist/{sync-BWbe8JTg.mjs → sync-Btcb6xA4.mjs} +3 -3
- package/dist/{sync-BWbe8JTg.mjs.map → sync-Btcb6xA4.mjs.map} +1 -1
- package/dist/{themes-B7h9YDiy.mjs → themes-BVoAnLZj.mjs} +3 -3
- package/dist/{themes-B7h9YDiy.mjs.map → themes-BVoAnLZj.mjs.map} +1 -1
- package/dist/{tools-BW3NLMPk.mjs → tools-BradfQk7.mjs} +4 -3
- package/dist/{tools-LlzcV_eK.mjs → tools-UrSHIe29.mjs} +30 -233
- package/dist/tools-UrSHIe29.mjs.map +1 -0
- package/dist/{trace-u4hT-pLD.mjs → trace-Cy8quQTm.mjs} +1 -1
- package/dist/{trace-u4hT-pLD.mjs.map → trace-Cy8quQTm.mjs.map} +1 -1
- package/dist/{utils-DhMex3Ox.mjs → utils-BD8g8oSf.mjs} +1 -1
- package/dist/{utils-9Err2RBW.mjs → utils-CJymHkYm.mjs} +1 -1
- package/dist/{utils-9Err2RBW.mjs.map → utils-CJymHkYm.mjs.map} +1 -1
- package/dist/{vault-indexer-mata9S7b.mjs → vault-indexer-C5i-OAyr.mjs} +2 -2
- package/dist/{vault-indexer-mata9S7b.mjs.map → vault-indexer-C5i-OAyr.mjs.map} +1 -1
- package/dist/wakeup-TnGjJY3I.mjs +218 -0
- package/dist/wakeup-TnGjJY3I.mjs.map +1 -0
- package/dist/work-queue-worker-BA5IDBwQ.mjs +567 -0
- package/dist/work-queue-worker-BA5IDBwQ.mjs.map +1 -0
- package/dist/work-queue-worker-DLM2wlqM.mjs +14 -0
- package/dist/{zettelkasten-F0D_XfQ4.mjs → zettelkasten-BBjA7GcP.mjs} +4 -4
- package/dist/{zettelkasten-F0D_XfQ4.mjs.map → zettelkasten-BBjA7GcP.mjs.map} +1 -1
- package/docs/commands/README.md +30 -3
- package/docs/commands/audit.md +88 -0
- package/docs/commands/backup.md +2 -2
- package/docs/commands/clear-names.md +1 -1
- package/docs/commands/config.md +59 -0
- package/docs/commands/daemon.md +1 -1
- package/docs/commands/db.md +1 -1
- package/docs/commands/end.md +1 -1
- package/docs/commands/help.md +1 -1
- package/docs/commands/identity.md +1 -1
- package/docs/commands/kg.md +1 -1
- package/docs/commands/launch.md +45 -0
- package/docs/commands/mcp.md +1 -1
- package/docs/commands/memory.md +3 -3
- package/docs/commands/notify.md +1 -1
- package/docs/commands/observation.md +1 -1
- package/docs/commands/obsidian.md +1 -1
- package/docs/commands/pause.md +1 -1
- package/docs/commands/project.md +46 -1
- package/docs/commands/projects.md +46 -1
- package/docs/commands/registry.md +1 -1
- package/docs/commands/restore.md +1 -1
- package/docs/commands/session.md +1 -1
- package/docs/commands/sessions.md +1 -1
- package/docs/commands/setup.md +1 -1
- package/docs/commands/shell-init.md +1 -1
- package/docs/commands/skill.md +1 -1
- package/docs/commands/task.md +1 -1
- package/docs/commands/topic.md +1 -1
- package/docs/commands/update.md +1 -1
- package/docs/commands/worker.md +95 -6
- package/docs/commands/zettel.md +1 -1
- package/docs/provider-abstraction.md +1 -1
- package/docs/provider-independence-details.md +8 -5
- package/docs/task-bus.md +1 -1
- package/docs/worker.md +136 -83
- package/docs/workers-config.md +446 -0
- package/package.json +4 -2
- package/scripts/build-hooks.mjs +56 -3
- package/src/hooks/pre-compact.sh +5 -2
- package/src/hooks/session-stop.sh +29 -4
- package/src/hooks/ts/capture-all-events.ts +3 -3
- package/src/hooks/ts/lib/advisor-budget.test.ts +98 -0
- package/src/hooks/ts/lib/advisor-budget.ts +90 -0
- package/src/hooks/ts/lib/agent-gate.test.ts +101 -0
- package/src/hooks/ts/lib/agent-gate.ts +112 -0
- package/src/hooks/ts/lib/context-fill.ts +2 -2
- package/src/hooks/ts/lib/edit-gate.test.ts +52 -0
- package/src/hooks/ts/lib/edit-gate.ts +51 -0
- package/src/hooks/ts/lib/mcp-deferred-reminder.test.ts +8 -0
- package/src/hooks/ts/lib/pai-paths.test.ts +93 -0
- package/src/hooks/ts/lib/pai-paths.ts +168 -24
- package/src/hooks/ts/lib/project-utils/index.ts +1 -0
- package/src/hooks/ts/lib/project-utils/paths.ts +5 -4
- package/src/hooks/ts/lib/project-utils.ts +1 -0
- package/src/hooks/ts/post-tool-use/capture-tool-output.ts +2 -2
- package/src/hooks/ts/pre-compact/context-compression-hook.ts +1 -1
- package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +46 -99
- package/src/hooks/ts/pre-tool-use/route-edits-to-worker.test.ts +47 -0
- package/src/hooks/ts/pre-tool-use/route-edits-to-worker.ts +96 -0
- package/src/hooks/ts/pre-tool-use/security-validator.ts +2 -1
- package/src/hooks/ts/session-end/capture-session-summary.ts +4 -4
- package/src/hooks/ts/session-start/initialize-session.ts +3 -3
- package/src/hooks/ts/session-start/inject-observations.test.ts +56 -0
- package/src/hooks/ts/session-start/inject-observations.ts +28 -8
- package/src/hooks/ts/session-start/load-core-context.ts +4 -4
- package/src/hooks/ts/session-start/load-project-context.ts +2 -2
- package/src/hooks/ts/session-start/mcp-deferred-reminder.ts +2 -0
- package/src/hooks/ts/session-start/session-commands.ts +4 -0
- package/src/hooks/ts/session-start/session-start-worker-guard.test.ts +36 -0
- package/src/hooks/ts/stop/stop-hook.ts +6 -11
- package/src/hooks/ts/user-prompt/whisper-rules.test.ts +49 -0
- package/src/hooks/ts/user-prompt/whisper-rules.ts +88 -47
- package/statusline-command.sh +277 -116
- package/templates/agent-prefs.example.md +8 -8
- package/templates/claude-md.template.md +1 -1
- package/templates/voices.example.json +3 -3
- package/dist/config-C_ErGddD.mjs +0 -3
- package/dist/config-_lQI_W08.mjs +0 -640
- package/dist/config-_lQI_W08.mjs.map +0 -1
- package/dist/context-handover-cache-pNFdBNrU.mjs +0 -1548
- package/dist/context-handover-cache-pNFdBNrU.mjs.map +0 -1
- package/dist/daemon-B8N1egl0.mjs.map +0 -1
- package/dist/daemon-DHfyoTlk.mjs +0 -23
- package/dist/db-O-cyAPfS.mjs +0 -3
- package/dist/db-XEwJbuGO.mjs +0 -3
- package/dist/detector-C-7KRi42.mjs +0 -5
- package/dist/factory-Dbo8yNPi.mjs +0 -3
- package/dist/fallback-oJl3BaIN.mjs.map +0 -1
- package/dist/main-resolver-BAfOMppW.mjs +0 -7
- package/dist/main-resolver-DnkxPYkr.mjs.map +0 -1
- package/dist/program-zpoYnJGz.mjs.map +0 -1
- package/dist/query-feedback-DGoVRaWD.mjs +0 -3
- package/dist/query-feedback-Dqz-HC__.mjs.map +0 -1
- package/dist/router-BTIGZR2_.mjs +0 -3
- package/dist/run-D7K5UALn.mjs.map +0 -1
- package/dist/server-D4vAieF4.mjs.map +0 -1
- package/dist/tools-LlzcV_eK.mjs.map +0 -1
- package/dist/work-queue-worker-AEmfVE0F.mjs +0 -14
- package/dist/work-queue-worker-DIT-VLSh.mjs +0 -2136
- package/dist/work-queue-worker-DIT-VLSh.mjs.map +0 -1
- /package/dist/{indexer-D7MvSQPY.mjs → indexer-C5Le7XE7.mjs} +0 -0
package/statusline-command.sh
CHANGED
|
@@ -32,11 +32,68 @@ input=$(cat)
|
|
|
32
32
|
DA_NAME="${DA:-Assistant}" # Assistant name
|
|
33
33
|
DA_COLOR="${DA_COLOR:-purple}" # Color for the assistant name
|
|
34
34
|
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
# Where the status line keeps what it may cache between renders: the usage
|
|
36
|
+
# snapshots per provider and the Claude Code version. One knob rather than a
|
|
37
|
+
# path repeated six times, so a test (or a second user on the same machine)
|
|
38
|
+
# can point the whole lot somewhere private.
|
|
39
|
+
pai_cache_dir="${PAI_CACHE_DIR:-/tmp/claude}"
|
|
40
|
+
|
|
41
|
+
# PAI's per-user namespace dir — see src/config/pai-home.ts (paiHomeDir) for
|
|
42
|
+
# the canonical (TypeScript) version of this same resolver; this script
|
|
43
|
+
# can't import that module, so the new/old fallback logic is duplicated here.
|
|
44
|
+
pai_home_dir="${PAI_HOME:-$HOME/.claude/pai}"
|
|
45
|
+
|
|
46
|
+
# Resolve a PAI per-user file: the new PAI_HOME path if it exists, else the
|
|
47
|
+
# first existing old candidate (args 2+), else the new path. Mirrors
|
|
48
|
+
# resolvePaiFile() in src/config/pai-home.ts.
|
|
49
|
+
_pai_resolve_file() {
|
|
50
|
+
_new="$1"; shift
|
|
51
|
+
[ -f "$_new" ] && { printf '%s' "$_new"; return; }
|
|
52
|
+
for _old in "$@"; do
|
|
53
|
+
if [ -f "$_old" ]; then
|
|
54
|
+
printf 'pai: %s is at an old location — run `pai config migrate` to move it to %s\n' "$_old" "$_new" >&2
|
|
55
|
+
printf '%s' "$_old"
|
|
56
|
+
return
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
printf '%s' "$_new"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Extract data from JSON input.
|
|
63
|
+
#
|
|
64
|
+
# `.workspace.current_dir` is the documented field and a full session always
|
|
65
|
+
# sends it — but `jq -r` prints the JSON null as the four characters "null"
|
|
66
|
+
# when it is absent, and `basename null` is "null", so any payload without a
|
|
67
|
+
# workspace block rendered a confident "📁 null". A folder name is never
|
|
68
|
+
# unknowable here: the payload also carries the flat `.cwd`, and failing both
|
|
69
|
+
# we are running in the directory ourselves. Fall through all three.
|
|
70
|
+
current_dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
71
|
+
[ -n "$current_dir" ] && [ "$current_dir" != "null" ] || current_dir="${PWD:-}"
|
|
72
|
+
model_name=$(echo "$input" | jq -r '.model.display_name // empty' 2>/dev/null)
|
|
73
|
+
[ -n "$model_name" ] || model_name="?"
|
|
74
|
+
model_id=$(echo "$input" | jq -r '.model.id // .model.display_name // empty' 2>/dev/null)
|
|
75
|
+
|
|
76
|
+
# Claude Code version. The payload carries `.version` as a plain string, but a
|
|
77
|
+
# caller that sends a partial payload (a test harness, an older client) left it
|
|
78
|
+
# rendering the literal word "unknown" next to a version that `claude --version`
|
|
79
|
+
# would have answered immediately. Ask the binary, and cache the answer for a
|
|
80
|
+
# day: it is a ~200MB executable and the status line runs on every keystroke.
|
|
81
|
+
cc_version=$(echo "$input" | jq -r '.version // empty' 2>/dev/null)
|
|
82
|
+
if [ -z "$cc_version" ]; then
|
|
83
|
+
_ccv_cache="${pai_cache_dir}/cc-version"
|
|
84
|
+
_ccv_age=$(( $(date +%s) - $(stat -f %m "$_ccv_cache" 2>/dev/null || echo 0) ))
|
|
85
|
+
if [ -s "$_ccv_cache" ] && [ "$_ccv_age" -lt 86400 ] 2>/dev/null; then
|
|
86
|
+
read -r cc_version < "$_ccv_cache"
|
|
87
|
+
elif command -v claude >/dev/null 2>&1; then
|
|
88
|
+
# "2.1.267 (Claude Code)" -> "2.1.267"
|
|
89
|
+
cc_version=$(command claude --version 2>/dev/null | awk 'NR==1{print $1}')
|
|
90
|
+
if [ -n "$cc_version" ]; then
|
|
91
|
+
mkdir -p "$pai_cache_dir" 2>/dev/null
|
|
92
|
+
printf '%s\n' "$cc_version" > "$_ccv_cache" 2>/dev/null || true
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
fi
|
|
96
|
+
[ -n "$cc_version" ] || cc_version="?"
|
|
40
97
|
|
|
41
98
|
# Provider detection: which worker provider is this session running on? The
|
|
42
99
|
# answer comes from the PAI config, not from model-name prefixes — a session
|
|
@@ -44,7 +101,19 @@ cc_version=$(echo "$input" | jq -r '.version // "unknown"')
|
|
|
44
101
|
# Any [...] suffix (e.g. the [1m] context marker) is stripped on both sides,
|
|
45
102
|
# so a session on "glm-5.3[1m]" matches a configured "glm-5.3" and vice versa.
|
|
46
103
|
# No config, no jq, unreadable JSON or no match => anthropic, silently.
|
|
47
|
-
|
|
104
|
+
# PAI_HOME (~/.claude/pai by default — see src/config/pai-home.ts) first;
|
|
105
|
+
# else fall back through the pre-2026-09-19 locations in the same order
|
|
106
|
+
# paiConfigFilePath() in src/daemon/config.ts does, since a shell script
|
|
107
|
+
# can't import that resolver.
|
|
108
|
+
pai_home_dir="${PAI_HOME:-$HOME/.claude/pai}"
|
|
109
|
+
pai_config="${PAI_CONFIG:-$pai_home_dir/config.json}"
|
|
110
|
+
if [ ! -f "$pai_config" ]; then
|
|
111
|
+
if [ -f "$HOME/.claude/pai.json" ]; then
|
|
112
|
+
pai_config="$HOME/.claude/pai.json"
|
|
113
|
+
elif [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/pai/config.json" ]; then
|
|
114
|
+
pai_config="${XDG_CONFIG_HOME:-$HOME/.config}/pai/config.json"
|
|
115
|
+
fi
|
|
116
|
+
fi
|
|
48
117
|
model_base="${model_id%%\[*}"
|
|
49
118
|
session_provider=anthropic
|
|
50
119
|
if [ -n "$model_base" ] && [ -f "$pai_config" ] && command -v jq >/dev/null 2>&1; then
|
|
@@ -58,7 +127,8 @@ if [ -n "$model_base" ] && [ -f "$pai_config" ] && command -v jq >/dev/null 2>&1
|
|
|
58
127
|
fi
|
|
59
128
|
|
|
60
129
|
# Get directory name
|
|
61
|
-
dir_name=$(basename "$current_dir")
|
|
130
|
+
dir_name=$(basename "$current_dir" 2>/dev/null)
|
|
131
|
+
[ -n "$dir_name" ] || dir_name="?"
|
|
62
132
|
|
|
63
133
|
# Read Whazaa session name from iTerm2 user variable
|
|
64
134
|
pai_session_name=""
|
|
@@ -372,80 +442,175 @@ fi
|
|
|
372
442
|
printf "${LINE2_PRIMARY}${EMOJI_PLUG} MCPs${RESET}${LINE2_PRIMARY}${SEPARATOR_COLOR}: ${RESET}${mcp_line1}${RESET}\n"
|
|
373
443
|
|
|
374
444
|
|
|
375
|
-
# Usage suffix: provider-aware.
|
|
376
|
-
#
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
|
|
381
|
-
|
|
445
|
+
# Usage suffix: provider-aware. Every non-anthropic provider is rendered from
|
|
446
|
+
# its own `usage` block in the PAI config (see docs/provider-abstraction.md) —
|
|
447
|
+
# endpoint, auth header and per-window jq expressions are config, not code.
|
|
448
|
+
#
|
|
449
|
+
# The anthropic numbers come from Claude Code itself. Its status line payload
|
|
450
|
+
# carries a `rate_limits` object built from the same internal reading that
|
|
451
|
+
# /usage renders:
|
|
452
|
+
#
|
|
453
|
+
# "rate_limits": {
|
|
454
|
+
# "five_hour": { "used_percentage": 9, "resets_at": 1789810200 },
|
|
455
|
+
# "seven_day": { "used_percentage": 2, "resets_at": 1790402400 }
|
|
456
|
+
# }
|
|
457
|
+
#
|
|
458
|
+
# `used_percentage` is already 0-100 (used, not remaining) and `resets_at` is
|
|
459
|
+
# Unix epoch SECONDS. It is live, free and needs no credential.
|
|
460
|
+
#
|
|
461
|
+
# The OAuth usage endpoint below stays only as a fallback for payloads that
|
|
462
|
+
# carry no rate_limits (it reports `utilization` on the same 0-100 scale but
|
|
463
|
+
# `resets_at` as an ISO-8601 UTC string, so the two are parsed differently).
|
|
464
|
+
# That endpoint needs an OAuth token out of the Keychain, and when the token
|
|
465
|
+
# goes away the fetch fails silently and leaves whatever it cached last. A
|
|
466
|
+
# cache with no expiry is not a reading, it is a photograph: this one sat at
|
|
467
|
+
# "7d: 97%" for a day and a half after the window had already reset to 2%, and
|
|
468
|
+
# that number is not decoration — it is written to advisor-mode.json and
|
|
469
|
+
# injected into every session as an instruction about how much work to do. So
|
|
470
|
+
# the fallback is refused once it is older than usage_cache_max_age, and any
|
|
471
|
+
# window whose resets_at has already passed is dropped. What neither source can
|
|
472
|
+
# answer renders "?", which is the honest reading.
|
|
473
|
+
usage_cache="${pai_cache_dir}/statusline-usage-cache.json"
|
|
474
|
+
usage_cache_ttl=60 # refetch the fallback after this many seconds
|
|
475
|
+
usage_cache_max_age=300 # refuse to render from the fallback past this age
|
|
382
476
|
usage_suffix=""
|
|
383
477
|
|
|
384
|
-
# Color based on utilization: green < 50%,
|
|
478
|
+
# Color based on utilization: green < 50%, orange 50-75%, red > 75%.
|
|
479
|
+
# An unknown percentage is neither good nor bad news — render it neutral.
|
|
385
480
|
_usage_color() {
|
|
386
481
|
local pct=$1
|
|
387
|
-
if [ "$pct"
|
|
388
|
-
elif [ "$pct" -gt
|
|
482
|
+
if [ -z "$pct" ]; then echo "$LINE3_ACCENT"
|
|
483
|
+
elif [ "$pct" -gt 75 ] 2>/dev/null; then echo "$BRIGHT_RED"
|
|
484
|
+
elif [ "$pct" -gt 50 ] 2>/dev/null; then echo "$BRIGHT_ORANGE"
|
|
389
485
|
else echo "$BRIGHT_GREEN"; fi
|
|
390
486
|
}
|
|
391
487
|
|
|
392
488
|
_fetch_usage() {
|
|
393
489
|
# Try to get OAuth token from macOS Keychain
|
|
394
490
|
local token=""
|
|
395
|
-
|
|
396
|
-
|
|
491
|
+
# More than one keychain item can carry this service name: the real one is
|
|
492
|
+
# stored under the login user account, and a stub with empty tokens has
|
|
493
|
+
# been seen under acct "unknown". Without -a the first match wins, so ask
|
|
494
|
+
# for the user item first and only then fall back to an unqualified read.
|
|
495
|
+
local raw
|
|
496
|
+
raw=$(security find-generic-password -s "Claude Code-credentials" -a "$(id -un)" -w 2>/dev/null)
|
|
497
|
+
token=$(printf '%s' "$raw" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
|
|
498
|
+
if [ -z "$token" ]; then
|
|
499
|
+
raw=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null)
|
|
500
|
+
token=$(printf '%s' "$raw" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
|
|
501
|
+
fi
|
|
397
502
|
|
|
398
|
-
mkdir -p
|
|
399
|
-
|
|
400
|
-
|
|
503
|
+
mkdir -p "$pai_cache_dir"
|
|
504
|
+
if [ -z "$token" ]; then
|
|
505
|
+
echo "no usable OAuth token in keychain item Claude Code-credentials" > "$usage_cache.error"
|
|
506
|
+
return
|
|
507
|
+
fi
|
|
508
|
+
# Per-process temp file: several renders may fetch at once.
|
|
509
|
+
local tmp="$usage_cache.tmp.$$" http
|
|
510
|
+
http=$(curl -s --max-time 3 -o "$tmp" -w '%{http_code}' \
|
|
401
511
|
-H "Authorization: Bearer $token" \
|
|
402
512
|
-H "anthropic-beta: oauth-2025-04-20" \
|
|
403
513
|
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
|
|
404
|
-
[
|
|
514
|
+
if [ "$http" = "200" ] && [ -s "$tmp" ]; then
|
|
515
|
+
mv -f "$tmp" "$usage_cache"
|
|
516
|
+
rm -f "$usage_cache.error"
|
|
517
|
+
else
|
|
518
|
+
echo "usage fetch failed: http ${http:-timeout}" > "$usage_cache.error"
|
|
519
|
+
rm -f "$tmp"
|
|
520
|
+
fi
|
|
405
521
|
}
|
|
406
522
|
|
|
407
|
-
#
|
|
523
|
+
# Resolve the anthropic windows — skipped on non-anthropic sessions so
|
|
524
|
+
# Anthropic-plan numbers (usage line AND the advisor-mode budget file)
|
|
525
|
+
# never leak into a glm or kimi statusline. A worker running on another
|
|
526
|
+
# provider spends another budget; counting it here would be the same lie in
|
|
527
|
+
# the other direction.
|
|
528
|
+
five_hour_int=""
|
|
529
|
+
seven_day_int=""
|
|
530
|
+
five_reset_epoch=0
|
|
531
|
+
seven_reset_epoch=0
|
|
532
|
+
usage_source=""
|
|
533
|
+
|
|
534
|
+
# Source 1 (authoritative): rate_limits on stdin, straight from Claude Code.
|
|
408
535
|
if [ "$session_provider" = "anthropic" ]; then
|
|
536
|
+
_rl=$(echo "$input" | jq -r '
|
|
537
|
+
[ (.rate_limits.five_hour.used_percentage // ""),
|
|
538
|
+
(.rate_limits.five_hour.resets_at // ""),
|
|
539
|
+
(.rate_limits.seven_day.used_percentage // ""),
|
|
540
|
+
(.rate_limits.seven_day.resets_at // "") ] | @tsv' 2>/dev/null)
|
|
541
|
+
_p5=$(printf '%s' "$_rl" | cut -f1)
|
|
542
|
+
_r5=$(printf '%s' "$_rl" | cut -f2)
|
|
543
|
+
_p7=$(printf '%s' "$_rl" | cut -f3)
|
|
544
|
+
_r7=$(printf '%s' "$_rl" | cut -f4)
|
|
545
|
+
if [ -n "$_p5" ] || [ -n "$_p7" ]; then
|
|
546
|
+
usage_source="payload"
|
|
547
|
+
[ -n "$_p5" ] && five_hour_int=$(printf "%.0f" "$_p5" 2>/dev/null || echo "")
|
|
548
|
+
[ -n "$_p7" ] && seven_day_int=$(printf "%.0f" "$_p7" 2>/dev/null || echo "")
|
|
549
|
+
# resets_at is epoch seconds here, not an ISO string.
|
|
550
|
+
case "$_r5" in ''|*[!0-9.]*) ;; *) five_reset_epoch="${_r5%%.*}" ;; esac
|
|
551
|
+
case "$_r7" in ''|*[!0-9.]*) ;; *) seven_reset_epoch="${_r7%%.*}" ;; esac
|
|
552
|
+
fi
|
|
553
|
+
fi
|
|
554
|
+
|
|
555
|
+
# Refresh the fallback in the background, but only when the payload did not
|
|
556
|
+
# already answer — a keychain lookup plus an HTTPS round trip on every render
|
|
557
|
+
# buys nothing when the live numbers arrived on stdin.
|
|
558
|
+
if [ "$session_provider" = "anthropic" ] && [ -z "$usage_source" ]; then
|
|
409
559
|
if [ -f "$usage_cache" ]; then
|
|
410
560
|
cache_age=$(( $(date +%s) - $(stat -f %m "$usage_cache" 2>/dev/null || echo 0) ))
|
|
411
|
-
|
|
412
|
-
_fetch_usage &
|
|
413
|
-
fi
|
|
561
|
+
[ "$cache_age" -gt "$usage_cache_ttl" ] && _fetch_usage &
|
|
414
562
|
else
|
|
415
563
|
_fetch_usage &
|
|
416
564
|
fi
|
|
417
565
|
fi
|
|
418
566
|
|
|
419
|
-
#
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if [ "$
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
# be wrong. Parse as UTC to get the epoch, then let date render it in
|
|
441
|
-
# local time, which is the only form worth showing a person.
|
|
442
|
-
five_reset_epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "$(echo "$five_reset" | cut -c1-19)" "+%s" 2>/dev/null || date -d "$five_reset" "+%s" 2>/dev/null || echo 0)
|
|
443
|
-
five_reset_fmt=$([ "$five_reset_epoch" -gt 0 ] 2>/dev/null && date -r "$five_reset_epoch" "+%H:%M" 2>/dev/null || echo "")
|
|
567
|
+
# Source 2 (fallback): the OAuth endpoint cache, and only while it is fresh.
|
|
568
|
+
if [ "$session_provider" = "anthropic" ] && [ -z "$usage_source" ] && [ -f "$usage_cache" ]; then
|
|
569
|
+
_usage_cache_age=$(( $(date +%s) - $(stat -f %m "$usage_cache" 2>/dev/null || echo 0) ))
|
|
570
|
+
if [ "$_usage_cache_age" -le "$usage_cache_max_age" ] 2>/dev/null; then
|
|
571
|
+
usage_source="oauth"
|
|
572
|
+
five_hour=$(jq -r '.five_hour.utilization // empty' "$usage_cache" 2>/dev/null)
|
|
573
|
+
seven_day=$(jq -r '.seven_day.utilization // empty' "$usage_cache" 2>/dev/null)
|
|
574
|
+
five_reset=$(jq -r '.five_hour.resets_at // empty' "$usage_cache" 2>/dev/null)
|
|
575
|
+
seven_reset=$(jq -r '.seven_day.resets_at // empty' "$usage_cache" 2>/dev/null)
|
|
576
|
+
[ -n "$five_hour" ] && five_hour_int=$(printf "%.0f" "$five_hour" 2>/dev/null || echo "")
|
|
577
|
+
[ -n "$seven_day" ] && seven_day_int=$(printf "%.0f" "$seven_day" 2>/dev/null || echo "")
|
|
578
|
+
# The endpoint states these in UTC ("...T06:00:00+00:00"). Parsing
|
|
579
|
+
# without -u reads 06:00 UTC as 06:00 local and prints a reset time out
|
|
580
|
+
# by the offset — two hours here, long enough to plan around and be
|
|
581
|
+
# wrong. Parse as UTC to get the epoch; render local further down.
|
|
582
|
+
if [ -n "$five_reset" ]; then
|
|
583
|
+
five_reset_epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "$(echo "$five_reset" | cut -c1-19)" "+%s" 2>/dev/null || date -d "$five_reset" "+%s" 2>/dev/null || echo 0)
|
|
584
|
+
fi
|
|
585
|
+
if [ -n "$seven_reset" ]; then
|
|
586
|
+
seven_reset_epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "$(echo "$seven_reset" | cut -c1-19)" "+%s" 2>/dev/null || date -d "$seven_reset" "+%s" 2>/dev/null || echo 0)
|
|
587
|
+
fi
|
|
444
588
|
fi
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
589
|
+
fi
|
|
590
|
+
|
|
591
|
+
# A window whose reset has already passed describes a window that no longer
|
|
592
|
+
# exists. Its percentage belongs to a period that has been and gone, so it is
|
|
593
|
+
# dropped rather than carried forward — a spent budget rendered as the current
|
|
594
|
+
# one is exactly the failure this whole block exists to avoid.
|
|
595
|
+
if [ "$session_provider" = "anthropic" ]; then
|
|
596
|
+
_now_epoch=$(date +%s)
|
|
597
|
+
if [ "$five_reset_epoch" -gt 0 ] 2>/dev/null && [ "$five_reset_epoch" -le "$_now_epoch" ] 2>/dev/null; then
|
|
598
|
+
five_hour_int=""; five_reset_epoch=0
|
|
599
|
+
fi
|
|
600
|
+
if [ "$seven_reset_epoch" -gt 0 ] 2>/dev/null && [ "$seven_reset_epoch" -le "$_now_epoch" ] 2>/dev/null; then
|
|
601
|
+
seven_day_int=""; seven_reset_epoch=0
|
|
448
602
|
fi
|
|
603
|
+
fi
|
|
604
|
+
|
|
605
|
+
# Rendered even when both windows are unknown: "5h: ? │ 7d: ?" says the
|
|
606
|
+
# instrument is blind, where dropping the section altogether would read as
|
|
607
|
+
# "this session is not on the anthropic plan".
|
|
608
|
+
if [ "$session_provider" = "anthropic" ]; then
|
|
609
|
+
# Format reset times in local time
|
|
610
|
+
five_reset_fmt=""
|
|
611
|
+
seven_reset_fmt=""
|
|
612
|
+
[ "$five_reset_epoch" -gt 0 ] 2>/dev/null && five_reset_fmt=$(date -r "$five_reset_epoch" "+%H:%M" 2>/dev/null || echo "")
|
|
613
|
+
[ "$seven_reset_epoch" -gt 0 ] 2>/dev/null && seven_reset_fmt=$(date -r "$seven_reset_epoch" "+%a %H:%M" 2>/dev/null || echo "")
|
|
449
614
|
|
|
450
615
|
five_color=$(_usage_color "$five_hour_int")
|
|
451
616
|
seven_color=$(_usage_color "$seven_day_int")
|
|
@@ -453,83 +618,75 @@ if [ "$session_provider" = "anthropic" ] && [ -f "$usage_cache" ]; then
|
|
|
453
618
|
# Budget pace indicator for 7-day window
|
|
454
619
|
# Compare actual usage vs linear expected usage based on elapsed time
|
|
455
620
|
pace_dot=""
|
|
456
|
-
if [ "$seven_reset_epoch" -gt 0 ] 2>/dev/null; then
|
|
621
|
+
if [ "$seven_reset_epoch" -gt 0 ] 2>/dev/null && [ -n "$seven_day_int" ]; then
|
|
457
622
|
now_epoch=$(date +%s)
|
|
458
623
|
window_secs=$((7 * 86400))
|
|
459
624
|
remaining_secs=$((seven_reset_epoch - now_epoch))
|
|
460
625
|
[ "$remaining_secs" -lt 0 ] && remaining_secs=0
|
|
461
626
|
elapsed_secs=$((window_secs - remaining_secs))
|
|
462
|
-
# Expected usage if spending linearly: elapsed/total * 100
|
|
463
|
-
expected_pct=$(( elapsed_secs * 100 / window_secs ))
|
|
464
627
|
# Daily pace: actual spend/day vs dynamic budget
|
|
465
628
|
# Budget = remaining capacity / remaining days (not static 100/7)
|
|
466
629
|
elapsed_days_x10=$((elapsed_secs * 10 / 86400))
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
630
|
+
# A per-day rate divided by a fraction of a day is not a rate, it is an
|
|
631
|
+
# extrapolation from noise: an hour into a fresh window the old clamp to
|
|
632
|
+
# 0.1 days turned 2% spent into "20% per day" and painted the pace red.
|
|
633
|
+
# Below half a day there is nothing to pace against yet — say nothing.
|
|
634
|
+
if [ "$elapsed_days_x10" -ge 5 ]; then
|
|
635
|
+
spend_per_day=$((seven_day_int * 10 / elapsed_days_x10))
|
|
636
|
+
remaining_days_x10=$((remaining_secs * 10 / 86400))
|
|
637
|
+
[ "$remaining_days_x10" -lt 1 ] && remaining_days_x10=1
|
|
638
|
+
remaining_budget=$((100 - seven_day_int))
|
|
639
|
+
budget_per_day=$((remaining_budget * 10 / remaining_days_x10))
|
|
640
|
+
# Color: green = under budget, orange = near budget, red = over budget
|
|
641
|
+
overspend=$((spend_per_day - budget_per_day))
|
|
642
|
+
if [ "$overspend" -le -3 ] 2>/dev/null; then
|
|
643
|
+
pace_color="$BRIGHT_GREEN" # well under budget
|
|
644
|
+
elif [ "$overspend" -le 2 ] 2>/dev/null; then
|
|
645
|
+
pace_color="$BRIGHT_ORANGE" # near budget
|
|
646
|
+
else
|
|
647
|
+
pace_color="$BRIGHT_RED" # over budget
|
|
648
|
+
fi
|
|
649
|
+
pace_dot="${pace_color}${spend_per_day}%% / ${budget_per_day}%%${RESET}"
|
|
481
650
|
fi
|
|
482
|
-
pace_dot="${pace_color}${spend_per_day}%% / ${budget_per_day}%%${RESET}"
|
|
483
651
|
fi
|
|
484
652
|
|
|
485
|
-
# Write weekly budget to advisor-mode.json for the whisper hook
|
|
486
|
-
# Preserve existing mode if manually set — only update weeklyBudgetPercent
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
653
|
+
# Write weekly budget to advisor-mode.json for the whisper hook.
|
|
654
|
+
# Preserve existing mode if manually set — only update weeklyBudgetPercent.
|
|
655
|
+
#
|
|
656
|
+
# `asOf` is the epoch second the percentage was read. The consumer refuses a
|
|
657
|
+
# percentage without one, or one that has gone stale: this file is the input
|
|
658
|
+
# to an instruction injected on every prompt ("weekly budget at N% — do as
|
|
659
|
+
# little as possible"), so a number that stopped being refreshed must stop
|
|
660
|
+
# being obeyed rather than quietly harden into a permanent constraint.
|
|
661
|
+
# Nothing is written at all while the percentage is unknown.
|
|
662
|
+
_advisor_file=$(_pai_resolve_file "${pai_home_dir}/advisor-mode.json" "${HOME}/.claude/advisor-mode.json")
|
|
663
|
+
mkdir -p "$(dirname "$_advisor_file")" 2>/dev/null
|
|
664
|
+
_existing_mode="auto"
|
|
665
|
+
_existing_force=""
|
|
666
|
+
if [ -f "$_advisor_file" ]; then
|
|
667
|
+
_existing_mode=$(jq -r '.mode // "auto"' "$_advisor_file" 2>/dev/null)
|
|
668
|
+
_existing_force=$(jq -r '.forceModel // empty' "$_advisor_file" 2>/dev/null)
|
|
669
|
+
fi
|
|
670
|
+
case "$_existing_mode" in
|
|
671
|
+
normal|conservative|strict|critical|auto) ;;
|
|
672
|
+
*) _existing_mode="auto" ;;
|
|
673
|
+
esac
|
|
674
|
+
if [ -n "$seven_day_int" ]; then
|
|
495
675
|
if [ -n "$_existing_force" ]; then
|
|
496
|
-
printf '{"weeklyBudgetPercent":%d,"mode":"%s","forceModel":"%s"}\n' "$seven_day_int" "$_existing_mode" "$_existing_force" > "$_advisor_file" 2>/dev/null
|
|
676
|
+
printf '{"weeklyBudgetPercent":%d,"asOf":%d,"mode":"%s","forceModel":"%s"}\n' "$seven_day_int" "$(date +%s)" "$_existing_mode" "$_existing_force" > "$_advisor_file" 2>/dev/null
|
|
497
677
|
else
|
|
498
|
-
printf '{"weeklyBudgetPercent":%d,"mode":"%s"}\n' "$seven_day_int" "$_existing_mode" > "$_advisor_file" 2>/dev/null
|
|
499
|
-
fi
|
|
500
|
-
fi
|
|
501
|
-
|
|
502
|
-
# Compute advisor mode label (mirrors thresholds in whisper-rules.ts)
|
|
503
|
-
# If mode is manually set (not "auto"), show that instead of auto-calculated
|
|
504
|
-
advisor_label=""
|
|
505
|
-
advisor_label_color=""
|
|
506
|
-
_display_mode="$_existing_mode"
|
|
507
|
-
if [ "$_display_mode" = "auto" ]; then
|
|
508
|
-
if [ "$seven_day_int" -ge 92 ] 2>/dev/null; then
|
|
509
|
-
_display_mode="critical"
|
|
510
|
-
elif [ "$seven_day_int" -ge 80 ] 2>/dev/null; then
|
|
511
|
-
_display_mode="strict"
|
|
512
|
-
elif [ "$seven_day_int" -ge 60 ] 2>/dev/null; then
|
|
513
|
-
_display_mode="conservative"
|
|
678
|
+
printf '{"weeklyBudgetPercent":%d,"asOf":%d,"mode":"%s"}\n' "$seven_day_int" "$(date +%s)" "$_existing_mode" > "$_advisor_file" 2>/dev/null
|
|
514
679
|
fi
|
|
515
680
|
fi
|
|
516
|
-
case "$_display_mode" in
|
|
517
|
-
"critical") advisor_label="critical"; advisor_label_color="$BRIGHT_RED" ;;
|
|
518
|
-
"strict") advisor_label="strict"; advisor_label_color="$BRIGHT_ORANGE" ;;
|
|
519
|
-
"conservative") advisor_label="conserve"; advisor_label_color="$BRIGHT_YELLOW" ;;
|
|
520
|
-
"normal") advisor_label="normal"; advisor_label_color="$BRIGHT_GREEN" ;;
|
|
521
|
-
esac
|
|
522
|
-
# Mark forced modes with a pin symbol so user knows it's not auto
|
|
523
|
-
if [ "$_existing_mode" != "auto" ] && [ -n "$advisor_label" ]; then
|
|
524
|
-
advisor_label="📌${advisor_label}"
|
|
525
|
-
fi
|
|
526
681
|
|
|
527
|
-
# Build usage suffix: 5h: 8% → 00:59 │ 1d: ● 29% / 36% │ 7d:
|
|
528
|
-
|
|
682
|
+
# Build usage suffix: 5h: 8% → 00:59 │ 1d: ● 29% / 36% │ 7d: 91% → Fr. 08:00
|
|
683
|
+
# A window we could not read renders "?" — a gauge that admits it cannot
|
|
684
|
+
# tell beats one reading 0% while the tank drains. The advisor mode word is
|
|
685
|
+
# deliberately not rendered here; the whisper hook is where it acts.
|
|
686
|
+
five_label="5h: ${five_hour_int:-?}%%"
|
|
529
687
|
[ -n "$five_reset_fmt" ] && five_label="${five_label} → ${five_reset_fmt}"
|
|
530
688
|
seven_label="7d: "
|
|
531
|
-
|
|
532
|
-
seven_label="${seven_label}${seven_day_int}%%"
|
|
689
|
+
seven_label="${seven_label}${seven_day_int:-?}%%"
|
|
533
690
|
[ -n "$seven_reset_fmt" ] && seven_label="${seven_label} → ${seven_reset_fmt}"
|
|
534
691
|
|
|
535
692
|
usage_suffix=" ${SEPARATOR_COLOR}│${RESET} ${five_color}${five_label}${RESET}"
|
|
@@ -562,7 +719,7 @@ _fetch_provider_usage() {
|
|
|
562
719
|
else
|
|
563
720
|
header="${auth}: ${key}"
|
|
564
721
|
fi
|
|
565
|
-
mkdir -p
|
|
722
|
+
mkdir -p "$pai_cache_dir"
|
|
566
723
|
local response
|
|
567
724
|
response=$(curl -sf --max-time 3 \
|
|
568
725
|
-H "$header" \
|
|
@@ -593,7 +750,7 @@ if [ "$session_provider" != "anthropic" ]; then
|
|
|
593
750
|
usage_auth=$(printf '%s' "$provider_usage" | jq -r '.authHeader // "Authorization: Bearer"')
|
|
594
751
|
usage_ttl=$(printf '%s' "$provider_usage" | jq -r '.ttlSeconds // empty')
|
|
595
752
|
[ "$usage_ttl" -gt 0 ] 2>/dev/null || usage_ttl="$usage_cache_ttl"
|
|
596
|
-
provider_cache="/
|
|
753
|
+
provider_cache="${pai_cache_dir}/statusline-usage-${session_provider}.json"
|
|
597
754
|
usage_probe=$(printf '%s' "$provider_usage" | jq -r '.windows[0].percent // empty')
|
|
598
755
|
|
|
599
756
|
# Use cache if fresh, otherwise refresh in the background
|
|
@@ -704,6 +861,10 @@ fi
|
|
|
704
861
|
# step, plus today's finished count). Empty when this session has none.
|
|
705
862
|
# Prefers the standalone built script (plain node, no CLI startup); falls back
|
|
706
863
|
# to the pai CLI.
|
|
864
|
+
# PAI_QUIET_NOTICES=1: this call's stderr already goes to /dev/null below, but
|
|
865
|
+
# set it anyway so a caller of worker-status-line.mjs outside this script
|
|
866
|
+
# stays quiet too.
|
|
867
|
+
export PAI_QUIET_NOTICES=1
|
|
707
868
|
worker_status_cmd=""
|
|
708
869
|
if [ -x "${claude_dir}/worker-status-line.mjs" ]; then
|
|
709
870
|
worker_status_cmd="${claude_dir}/worker-status-line.mjs"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PAI Agent Preferences (Personal Configuration)
|
|
2
2
|
|
|
3
|
-
Copy this file to `~/.
|
|
3
|
+
Copy this file to `~/.claude/pai/agent-prefs.md` and customize for your workflow. This file is **NOT** committed to any repository and contains your personal preferences.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -115,7 +115,7 @@ researcher | [researcher-voice-id] | Research summaries, findings
|
|
|
115
115
|
- No API key needed — runs entirely locally
|
|
116
116
|
- Better for privacy-sensitive workflows
|
|
117
117
|
|
|
118
|
-
**Configuration**: Store voice preferences in `~/.
|
|
118
|
+
**Configuration**: Store voice preferences in `~/.claude/pai/voices.json` (see voices.example.json). Currently unused — no code reads this file's contents yet.
|
|
119
119
|
|
|
120
120
|
---
|
|
121
121
|
|
|
@@ -306,14 +306,14 @@ Always Use: ~/dev, ~/Projects, ~/.claude
|
|
|
306
306
|
|
|
307
307
|
1. **Copy to config directory**:
|
|
308
308
|
```bash
|
|
309
|
-
cp ~/dev/ai/PAI/templates/agent-prefs.example.md ~/.
|
|
309
|
+
cp ~/dev/ai/PAI/templates/agent-prefs.example.md ~/.claude/pai/agent-prefs.md
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
-
2. **Customize for your workflow**: Edit `~/.
|
|
312
|
+
2. **Customize for your workflow**: Edit `~/.claude/pai/agent-prefs.md` with your settings.
|
|
313
313
|
|
|
314
314
|
3. **Make it executable** (optional):
|
|
315
315
|
```bash
|
|
316
|
-
chmod 600 ~/.
|
|
316
|
+
chmod 600 ~/.claude/pai/agent-prefs.md # Restrict permissions if sensitive
|
|
317
317
|
```
|
|
318
318
|
|
|
319
319
|
4. **Load in your scripts**: Your PAI daemon/CLI reads this automatically on startup.
|
|
@@ -326,13 +326,13 @@ This file contains personal preferences and may reference sensitive information:
|
|
|
326
326
|
|
|
327
327
|
```bash
|
|
328
328
|
# Recommended permissions (user read/write only)
|
|
329
|
-
chmod 600 ~/.
|
|
329
|
+
chmod 600 ~/.claude/pai/agent-prefs.md
|
|
330
330
|
```
|
|
331
331
|
|
|
332
332
|
Keep it **out of version control** — add to `.gitignore`:
|
|
333
333
|
```
|
|
334
|
-
~/.
|
|
335
|
-
.
|
|
334
|
+
~/.claude/pai/
|
|
335
|
+
.claude/pai/
|
|
336
336
|
```
|
|
337
337
|
|
|
338
338
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CLAUDE.md - PAI Global Configuration
|
|
2
2
|
<!-- Generated by PAI Setup — Do not edit directly. Run `pai setup` to regenerate. -->
|
|
3
|
-
<!-- Personal preferences and project mappings are read from ~/.
|
|
3
|
+
<!-- Personal preferences and project mappings are read from ~/.claude/pai/agent-prefs.md -->
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"comment": "PAI Voice Configuration Template. Copy to ~/.
|
|
2
|
+
"comment": "PAI Voice Configuration Template. Copy to ~/.claude/pai/voices.json and customize. Currently unused — no code reads this file's contents yet.",
|
|
3
3
|
"comment_privacy": "This file is NOT committed to any repository. Keep it out of version control.",
|
|
4
4
|
|
|
5
5
|
"voiceSystem": {
|
|
@@ -231,10 +231,10 @@
|
|
|
231
231
|
},
|
|
232
232
|
|
|
233
233
|
"notes": {
|
|
234
|
-
"setup": "Copy this file to ~/.
|
|
234
|
+
"setup": "Copy this file to ~/.claude/pai/voices.json and customize for your preferences.",
|
|
235
235
|
"kokoro_first_run": "First use downloads ~160MB model (~30 seconds). Runs entirely offline afterward.",
|
|
236
236
|
"elevenlabs_cost": "ElevenLabs has usage limits and costs. Check your account for pricing.",
|
|
237
|
-
"privacy": "This file is NOT committed to version control. Add ~/.
|
|
237
|
+
"privacy": "This file is NOT committed to version control. Add ~/.claude/pai/ to .gitignore.",
|
|
238
238
|
"reloading": "Changes take effect immediately. No daemon restart required.",
|
|
239
239
|
"fallback_behavior": "If primary system fails or voice not found, falls back to alternate system.",
|
|
240
240
|
"environment_variables": "Can also set ELEVENLABS_API_KEY and KOKORO_CACHE_DIR via environment.",
|
package/dist/config-C_ErGddD.mjs
DELETED