@herbertgao/pi-extensions 2026.9.20 → 2026.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -13
- package/THIRD_PARTY_NOTICES.md +31 -5
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/index.js +4 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +43 -3
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +142 -59
- package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +1 -1
- package/node_modules/@dietrichgebert/ponytail/README.es.md +87 -204
- package/node_modules/@dietrichgebert/ponytail/README.ja.md +212 -0
- package/node_modules/@dietrichgebert/ponytail/README.ko.md +92 -226
- package/node_modules/@dietrichgebert/ponytail/README.md +58 -244
- package/node_modules/@dietrichgebert/ponytail/README.zh-CN.md +212 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +3 -3
- package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +4 -4
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +63 -16
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +8 -7
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +46 -23
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +39 -7
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +20 -3
- package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +3 -3
- package/node_modules/@dietrichgebert/ponytail/package.json +2 -2
- package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +47 -17
- package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +21 -7
- package/node_modules/@dietrichgebert/ponytail/skills/plugin.json +5 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +7 -2
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +16 -14
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +3 -3
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +12 -7
- package/node_modules/@herbertgao/pi-bark/README.md +39 -3
- package/node_modules/@herbertgao/pi-bark/package.json +1 -1
- package/node_modules/@herbertgao/pi-bark/src/index.ts +275 -15
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +50 -50
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +7 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +25 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +24 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -4
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +47 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/mcp-chip.ts +136 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +56 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +36 -4
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +11 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +303 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +36 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +88 -34
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +6 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +31 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/message-display.ts +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +3 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +173 -36
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +1 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +6 -4
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
- package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +3 -2
- package/node_modules/@herbertgao/sol-pi/CONTRIBUTING.md +22 -0
- package/node_modules/@herbertgao/sol-pi/README.md +36 -17
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +10 -6
- package/node_modules/@herbertgao/sol-pi/agents-install.md +15 -12
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +24 -8
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +2 -2
- package/node_modules/@herbertgao/sol-pi/docs/star-history.md +18 -0
- package/node_modules/@herbertgao/sol-pi/package.json +4 -2
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +23 -4
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +32 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +3 -2
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +27 -7
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +137 -41
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +1 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +2 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/projection.ts +58 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +28 -6
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +2 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +15 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@narumitw/pi-caffeinate/package.json +4 -4
- package/node_modules/@pi-plugins/fast-mode/README.md +7 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +7 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +5 -5
- package/node_modules/pi-antigravity/README.md +3 -0
- package/node_modules/pi-antigravity/package.json +8 -8
- package/node_modules/pi-antigravity/src/auth/oauth.ts +6 -3
- package/node_modules/pi-antigravity/src/index.ts +114 -110
- package/node_modules/pi-antigravity/src/stream/stream.ts +1 -1
- package/node_modules/pi-antigravity/src/utils/util.ts +18 -1
- package/node_modules/pi-multi-account/CHANGELOG.md +20 -0
- package/node_modules/pi-multi-account/README.md +46 -8
- package/node_modules/pi-multi-account/config-file-transaction.ts +42 -0
- package/node_modules/pi-multi-account/index.ts +255 -269
- package/node_modules/pi-multi-account/model-pins.ts +36 -0
- package/node_modules/pi-multi-account/package.json +9 -7
- package/node_modules/pi-multi-account/slot-proxy-auth.ts +12 -2
- package/node_modules/pi-multi-account/slot-proxy.ts +27 -5
- package/node_modules/pi-typesafe/README.md +1 -1
- package/node_modules/pi-typesafe/dist/backends.d.ts +15 -5
- package/node_modules/pi-typesafe/dist/backends.js +18 -0
- package/node_modules/pi-typesafe/dist/client.d.ts +4 -3
- package/node_modules/pi-typesafe/dist/client.js +22 -7
- package/node_modules/pi-typesafe/dist/index.d.ts +2 -2
- package/node_modules/pi-typesafe/dist/index.js +1 -1
- package/node_modules/pi-typesafe/dist/usage.d.ts +14 -4
- package/node_modules/pi-typesafe/dist/usage.js +147 -42
- package/node_modules/pi-typesafe/package.json +1 -1
- package/node_modules/pi-web-access/CHANGELOG.md +65 -0
- package/node_modules/pi-web-access/README.md +63 -14
- package/node_modules/pi-web-access/brave-rate-limit.ts +176 -0
- package/node_modules/pi-web-access/brave.ts +28 -11
- package/node_modules/pi-web-access/curator-page.ts +5 -1
- package/node_modules/pi-web-access/curator-server.ts +2 -0
- package/node_modules/pi-web-access/declared-web-links.ts +2 -2
- package/node_modules/pi-web-access/degoog.ts +323 -0
- package/node_modules/pi-web-access/dist/index.js +3647 -2740
- package/node_modules/pi-web-access/dist/mcp-cli.js +27443 -0
- package/node_modules/pi-web-access/exa.ts +5 -1
- package/node_modules/pi-web-access/extract.ts +41 -3
- package/node_modules/pi-web-access/firecrawl.ts +35 -4
- package/node_modules/pi-web-access/gemini-search.ts +36 -16
- package/node_modules/pi-web-access/gemini-web.ts +14 -9
- package/node_modules/pi-web-access/index.ts +164 -1207
- package/node_modules/pi-web-access/keenable.ts +221 -0
- package/node_modules/pi-web-access/mcp-cli.ts +40 -0
- package/node_modules/pi-web-access/mcp-server.ts +81 -0
- package/node_modules/pi-web-access/mcp-tool-definitions.ts +117 -0
- package/node_modules/pi-web-access/openai-search.ts +58 -11
- package/node_modules/pi-web-access/package.json +23 -5
- package/node_modules/pi-web-access/perplexity.ts +64 -56
- package/node_modules/pi-web-access/summary-review.ts +8 -2
- package/node_modules/pi-web-access/tool-arguments.ts +20 -0
- package/node_modules/pi-web-access/video-extract.ts +1 -1
- package/node_modules/pi-web-access/web-tool-contract.ts +86 -0
- package/node_modules/pi-web-access/web-tool-core.ts +1502 -0
- package/node_modules/pi-web-access/youtube-extract.ts +2 -5
- package/node_modules/{@herbertgao/resume-from → resume-from}/README.md +16 -12
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.d.ts +0 -5
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.js +2 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.d.ts +3 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.js +27 -15
- package/node_modules/{@herbertgao/resume-from/dist/adapters/codex → resume-from/dist/adapters/claude-code}/redaction.js +16 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.d.ts +2 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.js +1 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.d.ts +2 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.js +1 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/read.d.ts +16 -0
- package/node_modules/resume-from/dist/adapters/codex/read.js +723 -0
- package/node_modules/{@herbertgao/resume-from/dist/adapters/pi → resume-from/dist/adapters/codex}/redaction.js +16 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.d.ts +44 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.js +88 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.d.ts +5 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.js +10 -6
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from/dist/adapters/claude-code → resume-from/dist/adapters/pi}/redaction.js +16 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.d.ts +2 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.d.ts +1 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.js +4 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.js +31 -8
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.d.ts +1 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.js +1 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.d.ts +4 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.d.ts +8 -6
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.d.ts +10 -5
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/finder.d.ts +2 -1
- package/node_modules/resume-from/dist/import/discovery/finder.js +269 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.d.ts +3 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.js +3 -3
- package/node_modules/resume-from/dist/import/pipeline.d.ts +28 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/pipeline.js +31 -11
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.js +9 -5
- package/node_modules/resume-from/dist/import/preview/warnings.d.ts +14 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/warnings.js +26 -20
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.js +12 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.d.ts +9 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.d.ts +4 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.js +7 -4
- package/node_modules/resume-from/dist/platform/repo/reader.d.ts +3 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/reader.js +60 -20
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.d.ts +8 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/package.json +19 -32
- package/node_modules/{@herbertgao/resume-from → resume-from}/shims/pi/extensions/resume-from.js +2 -2
- package/package.json +21 -21
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +0 -21
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +0 -62
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +0 -115
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +0 -27
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +0 -27
- package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/retriever-icon.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-dark.svg +0 -4
- package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-light.svg +0 -4
- package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/read.js +0 -270
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/finder.js +0 -129
- package/node_modules/@herbertgao/resume-from/dist/import/pipeline.d.ts +0 -17
- package/node_modules/@herbertgao/resume-from/dist/import/preview/warnings.d.ts +0 -11
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/reader.d.ts +0 -8
- /package/node_modules/{@herbertgao/resume-from → resume-from}/LICENSE +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/redaction.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/redaction.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/redaction.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.js +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// ponytail — removes state ponytail wrote outside the plugin's own files:
|
|
3
|
-
// the mode flag, the config file, the
|
|
4
|
-
// settings.json, and its entries in
|
|
5
|
-
// themselves are removed by each host's
|
|
6
|
-
// this only cleans up what those
|
|
3
|
+
// the mode flag, the config file, the statusline script copy, the
|
|
4
|
+
// statusLine entry it added to settings.json, and its entries in
|
|
5
|
+
// ~/.cursor/hooks.json. Plugin files themselves are removed by each host's
|
|
6
|
+
// own uninstall command (see README); this only cleans up what those
|
|
7
|
+
// commands can't see.
|
|
7
8
|
|
|
8
9
|
const fs = require('fs');
|
|
9
10
|
const os = require('os');
|
|
@@ -11,7 +12,7 @@ const path = require('path');
|
|
|
11
12
|
const { getConfigPath, getClaudeDir } = require('../hooks/ponytail-config');
|
|
12
13
|
const cursorHooks = require('./cursor-hooks');
|
|
13
14
|
|
|
14
|
-
const STATUSLINE_SCRIPT = 'ponytail-statusline'
|
|
15
|
+
const STATUSLINE_SCRIPT = /(?:^|[\s"'\\/])ponytail-statusline\.(?:sh|ps1)(?=$|[\s"'])/;
|
|
15
16
|
|
|
16
17
|
function removeIfExists(filePath, label) {
|
|
17
18
|
try {
|
|
@@ -23,8 +24,21 @@ function removeIfExists(filePath, label) {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
removeIfExists(path.join(getClaudeDir(), '.ponytail-active'), 'mode flag');
|
|
27
|
+
removeIfExists(path.join(getClaudeDir(), '.ponytail-statusline-nudged'), 'statusline nudge flag');
|
|
26
28
|
removeIfExists(path.join(os.homedir(), '.cursor', '.ponytail-active'), 'Cursor mode flag');
|
|
29
|
+
removeIfExists(path.join(os.homedir(), '.qoder', '.ponytail-active'), 'Qoder mode flag');
|
|
30
|
+
for (const dir of [path.join(getClaudeDir(), 'ponytail-modes'), path.join(os.homedir(), '.cursor', 'ponytail-modes'), path.join(process.env.CODEBUDDY_CONFIG_DIR || path.join(os.homedir(), '.codebuddy'), 'ponytail-modes')]) {
|
|
31
|
+
if (fs.existsSync(dir)) {
|
|
32
|
+
fs.rmSync(dir, { recursive: true });
|
|
33
|
+
console.log(`Removed per-project mode flags: ${dir}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
removeIfExists(path.join(process.env.CODEBUDDY_CONFIG_DIR || path.join(os.homedir(), '.codebuddy'), '.ponytail-active'), 'CodeBuddy mode flag');
|
|
27
37
|
removeIfExists(getConfigPath(), 'config file');
|
|
38
|
+
// Statusline script copies the activate hook keeps in the config dir (#1032).
|
|
39
|
+
for (const name of ['ponytail-statusline.sh', 'ponytail-statusline.ps1']) {
|
|
40
|
+
removeIfExists(path.join(getClaudeDir(), name), 'statusline script');
|
|
41
|
+
}
|
|
28
42
|
|
|
29
43
|
// Cursor hooks (#817): drop only ponytail's entries from ~/.cursor/hooks.json,
|
|
30
44
|
// keep every other hook the user configured there.
|
|
@@ -49,12 +63,12 @@ try {
|
|
|
49
63
|
// (e.g. caveman && ponytail), keep the other plugin's command intact.
|
|
50
64
|
// ponytail: splits on && / ; to detect other segments — good enough; a user
|
|
51
65
|
// piping statuslines together is on their own.
|
|
52
|
-
if (typeof cmd === 'string' &&
|
|
66
|
+
if (typeof cmd === 'string' && STATUSLINE_SCRIPT.test(cmd)) {
|
|
53
67
|
const parts = cmd
|
|
54
68
|
.split(/&&|;/)
|
|
55
69
|
.map((s) => s.trim())
|
|
56
70
|
.filter(Boolean);
|
|
57
|
-
const others = parts.filter((s) => !
|
|
71
|
+
const others = parts.filter((s) => !STATUSLINE_SCRIPT.test(s));
|
|
58
72
|
if (others.length === 0) {
|
|
59
73
|
delete settings.statusLine;
|
|
60
74
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
@@ -19,6 +19,7 @@ Same as ponytail-review:
|
|
|
19
19
|
- `delete:` dead code, unused flexibility, speculative feature. Replacement: nothing.
|
|
20
20
|
- `stdlib:` hand-rolled thing the standard library ships. Name the function.
|
|
21
21
|
- `native:` dependency or code doing what the platform already does. Name the feature.
|
|
22
|
+
- `reuse:` equivalent helper, util, or pattern already in this repo. Name the path.
|
|
22
23
|
- `yagni:` abstraction with one implementation, config nobody sets, layer with one caller.
|
|
23
24
|
- `shrink:` same logic, fewer lines. Show the shorter form.
|
|
24
25
|
|
|
@@ -26,11 +27,15 @@ Same as ponytail-review:
|
|
|
26
27
|
|
|
27
28
|
Deps the stdlib or platform already ships, single-implementation interfaces,
|
|
28
29
|
factories with one product, wrappers that only delegate, files exporting one
|
|
29
|
-
thing, dead flags and config, hand-rolled stdlib
|
|
30
|
+
thing, dead flags and config, hand-rolled stdlib, helpers duplicating an
|
|
31
|
+
equivalent that already lives in this repo.
|
|
32
|
+
Before emitting `delete:`, grep the whole tree for the symbol, including tests,
|
|
33
|
+
fixtures and string or dynamic references.
|
|
30
34
|
|
|
31
35
|
## Output
|
|
32
36
|
|
|
33
|
-
One line per finding, ranked: `<tag> <what to cut>. <replacement>. [path]
|
|
37
|
+
One line per finding, numbered and ranked: `<N>. <tag> <what to cut>. <replacement>. [path]`,
|
|
38
|
+
so the user can say "fix 2 and 5".
|
|
34
39
|
End with `net: -<N> lines, -<M> deps possible.` Nothing to cut: `Lean already. Ship.`
|
|
35
40
|
|
|
36
41
|
## Boundaries
|
|
@@ -17,7 +17,7 @@ can't quietly become permanent.
|
|
|
17
17
|
Grep the repo for comment markers, skipping `node_modules`, `.git`, and build
|
|
18
18
|
output:
|
|
19
19
|
|
|
20
|
-
`grep -rnE '(
|
|
20
|
+
`grep -rnE --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build '(#|//|/[*]) ?ponytail:' .` (add other comment prefixes if your stack uses them)
|
|
21
21
|
|
|
22
22
|
Each hit is one ledger row. The comment prefix keeps prose that merely mentions
|
|
23
23
|
the convention out of the ledger.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: ponytail-gain
|
|
3
3
|
description: >
|
|
4
4
|
Show ponytail's measured impact as a compact scoreboard: less code, less
|
|
5
|
-
cost, more speed, from the benchmark
|
|
5
|
+
cost, more speed, from the agentic benchmark averages. One-shot display, not a
|
|
6
6
|
persistent mode, and not a per-repo number. Trigger: /ponytail-gain,
|
|
7
7
|
"ponytail gain", "what does ponytail save", "show ponytail impact",
|
|
8
8
|
"ponytail scoreboard".
|
|
@@ -13,24 +13,26 @@ description: >
|
|
|
13
13
|
Display this scoreboard when invoked. One-shot: do NOT change mode, write flag
|
|
14
14
|
files, or persist anything.
|
|
15
15
|
|
|
16
|
-
The figures are the published benchmark
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
The figures are the published agentic benchmark averages: a headless Claude
|
|
17
|
+
Code session (Haiku 4.5) doing 12 feature tickets on a real FastAPI + React
|
|
18
|
+
repo, each task averaged over 4 runs, against the same agent without the
|
|
19
|
+
skill, plus 6 safety tasks. They are measured, not computed from the current
|
|
20
|
+
repo. Source: `benchmarks/results/2026-06-18-agentic.md` and the README.
|
|
20
21
|
|
|
21
22
|
## Scoreboard
|
|
22
23
|
|
|
23
|
-
Render plain ASCII bars. The bar length shows
|
|
24
|
-
carries the exact figure:
|
|
24
|
+
Render plain ASCII bars. The bar length shows ponytail as a share of the
|
|
25
|
+
no-skill baseline; the label carries the exact figure:
|
|
25
26
|
|
|
26
27
|
```
|
|
27
|
-
ponytail gain
|
|
28
|
+
ponytail gain benchmark average · 12 tasks · Haiku 4.5
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
no-skill ████████████████████ 100%
|
|
31
|
+
Lines of code █████████··········· 46% ▼ 54%
|
|
32
|
+
Tokens ████████████████···· 78% ▼ 22%
|
|
33
|
+
Cost ████████████████···· 80% ▼ 20%
|
|
34
|
+
Time ███████████████····· 73% ▼ 27%
|
|
35
|
+
Safety kept 100% (validation, error handling, security)
|
|
34
36
|
|
|
35
37
|
This repo: /ponytail-debt (shortcuts you deferred)
|
|
36
38
|
/ponytail-audit (what's still cuttable)
|
|
@@ -38,7 +40,7 @@ carries the exact figure:
|
|
|
38
40
|
|
|
39
41
|
## Honesty boundary
|
|
40
42
|
|
|
41
|
-
These are benchmark
|
|
43
|
+
These are benchmark averages, not this repo. NEVER print a per-repo savings
|
|
42
44
|
number ("you saved X lines/tokens here"): the unbuilt version was never
|
|
43
45
|
written, so there is no real baseline to subtract from in a live repo. The
|
|
44
46
|
only real per-repo figures come from `/ponytail-debt` (a counted ledger), and
|
|
@@ -32,9 +32,9 @@ Level sticks until changed or session end.
|
|
|
32
32
|
| **ponytail-gain** | `/ponytail-gain` | Measured-impact scoreboard: less code, less cost, more speed. |
|
|
33
33
|
| **ponytail-help** | `/ponytail-help` | This card. |
|
|
34
34
|
|
|
35
|
-
Codex
|
|
36
|
-
|
|
37
|
-
slash commands).
|
|
35
|
+
In Codex CLI and the IDE extension, invoke skills with `$ponytail:ponytail`,
|
|
36
|
+
`$ponytail:ponytail-review`, or `$ponytail:ponytail-help`. Claude Code and OpenCode use the
|
|
37
|
+
slash-command forms above (OpenCode ships all six as slash commands).
|
|
38
38
|
|
|
39
39
|
## Deactivate
|
|
40
40
|
|
|
@@ -15,31 +15,36 @@ to cut, what replaces it. The diff's best outcome is getting shorter.
|
|
|
15
15
|
|
|
16
16
|
## Format
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
multi-file diffs.
|
|
18
|
+
`<N>. L<line>: <tag> <what>. <replacement>.`, or `<N>. <file>:L<line>: ...` for
|
|
19
|
+
multi-file diffs. Number findings `1.`, `2.`, ... across the whole report, so the
|
|
20
|
+
user can say "fix 2 and 5".
|
|
20
21
|
|
|
21
22
|
Tags:
|
|
22
23
|
|
|
23
24
|
- `delete:` dead code, unused flexibility, speculative feature. Replacement: nothing.
|
|
24
25
|
- `stdlib:` hand-rolled thing the standard library ships. Name the function.
|
|
25
26
|
- `native:` dependency or code doing what the platform already does. Name the feature.
|
|
27
|
+
- `reuse:` equivalent helper, util, or pattern already in this repo. Name the path.
|
|
26
28
|
- `yagni:` abstraction with one implementation, config nobody sets, layer with one caller.
|
|
27
29
|
- `shrink:` same logic, fewer lines. Show the shorter form.
|
|
28
30
|
|
|
31
|
+
|
|
29
32
|
## Examples
|
|
30
33
|
|
|
31
34
|
❌ "This EmailValidator class might be more complex than necessary, have you
|
|
32
35
|
considered whether all these validation rules are needed at this stage?"
|
|
33
36
|
|
|
34
|
-
✅ `L12-38: stdlib: 27-line validator class. "@" in email, 1 line, real validation is the confirmation mail.`
|
|
37
|
+
✅ `1. L12-38: stdlib: 27-line validator class. "@" in email, 1 line, real validation is the confirmation mail.`
|
|
38
|
+
|
|
39
|
+
✅ `2. L4: native: moment.js imported for one format call. Intl.DateTimeFormat, 0 deps.`
|
|
35
40
|
|
|
36
|
-
✅ `
|
|
41
|
+
✅ `3. L18-29: reuse: slugify helper duplicates src/lib/slug.ts slugify. Delete it, import the existing one.`
|
|
37
42
|
|
|
38
|
-
✅ `repo.py:L88: yagni: AbstractRepository with one implementation. Inline it until a second one exists.`
|
|
43
|
+
✅ `4. repo.py:L88: yagni: AbstractRepository with one implementation. Inline it until a second one exists.`
|
|
39
44
|
|
|
40
|
-
✅ `L52-71: delete: retry wrapper around an idempotent local call. Nothing replaces it.`
|
|
45
|
+
✅ `5. L52-71: delete: retry wrapper around an idempotent local call. Nothing replaces it.`
|
|
41
46
|
|
|
42
|
-
✅ `L30-44: shrink: manual loop builds dict. dict(zip(keys, values)), 1 line.`
|
|
47
|
+
✅ `6. L30-44: shrink: manual loop builds dict. dict(zip(keys, values)), 1 line.`
|
|
43
48
|
|
|
44
49
|
## Scoring
|
|
45
50
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @herbertgao/pi-bark
|
|
2
2
|
|
|
3
|
-
Bark notifications for user-facing Pi sessions. It sends a notification when Pi fully settles and when [`@juicesharp/rpiv-ask-user-question`](https://github.com/juicesharp/rpiv-mono)
|
|
3
|
+
Bark notifications for user-facing Pi sessions. It sends a notification when Pi fully settles and when Pi blocks on a user-facing dialog — an approval, a select, an input prompt, a custom panel, or an [`@juicesharp/rpiv-ask-user-question`](https://github.com/juicesharp/rpiv-mono) questionnaire. Requests follow Bark's official [POST form API](https://github.com/Finb/Bark/blob/master/docs/en-us/tutorial.md#request-methods).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -21,17 +21,53 @@ Create `$PI_CODING_AGENT_DIR/bark.json` (normally `~/.pi/agent/bark.json`):
|
|
|
21
21
|
"locale": "zh-CN",
|
|
22
22
|
"events": {
|
|
23
23
|
"agentSettled": true,
|
|
24
|
-
"
|
|
24
|
+
"needsInput": true
|
|
25
25
|
},
|
|
26
26
|
"params": {
|
|
27
27
|
"group": "pi",
|
|
28
28
|
"icon": "https://raw.githubusercontent.com/HerbertGao/pi-extensions/master/packages/pi-bark/assets/pi-icon.png"
|
|
29
29
|
},
|
|
30
|
+
"title": {
|
|
31
|
+
"source": "session",
|
|
32
|
+
"maxLength": 40
|
|
33
|
+
},
|
|
34
|
+
"minDurationMs": 30000,
|
|
30
35
|
"timeoutMs": 4000
|
|
31
36
|
}
|
|
32
37
|
```
|
|
33
38
|
|
|
34
|
-
`endpoint` is required. `locale` accepts `auto` (default), `zh-CN`, `zh-TW`, or `en`; unsupported languages fall back to English. `params` accepts additional Bark POST parameters such as `group`, `sound`, `icon`, and `level`; dynamic `title` and `body` values always take precedence. Set `"enabled": false` to disable all notifications without removing the package.
|
|
39
|
+
`endpoint` is required. `locale` accepts `auto` (default), `zh-CN`, `zh-TW`, or `en`; unsupported languages fall back to English. `params` accepts additional Bark POST parameters such as `group`, `sound`, `icon`, and `level`; dynamic `title` and `body` values always take precedence. Set `"enabled": false` to disable all notifications without removing the package. `events.needsInput` covers every blocking dialog; `events.askUserQuestion` is the older name and is still honored as an alias.
|
|
40
|
+
|
|
41
|
+
### Session titles
|
|
42
|
+
|
|
43
|
+
The default `title.source` is `"fixed"`, which keeps Pi's localized copy (`✅ Pi 跑完了` / `🟡 Pi 等你回答`) as the notification title. Set it to `"session"` to title the notification with the session instead — Pi's session name when one is set, otherwise the first user message, which is the label hosts such as Paseo already show for the session:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{ "title": { "source": "session", "maxLength": 40 } }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`maxLength` defaults to `40`, counts Unicode code points without splitting emoji surrogate pairs, and includes the ellipsis. Non-finite values or values below `1` fall back to the default. With `"session"`, the event state moves to the first line of the body:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
title: Please reply with exactly the single wo…
|
|
53
|
+
body: ✅ 已完成 · 用时 2m14s
|
|
54
|
+
💻 MacBook Pro M1 Max
|
|
55
|
+
📁 /Users/herbertgao/VSCodeProject/pi
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The title is resolved when the notification is sent, so a session that is renamed or that has only just received its first message still gets the right one.
|
|
59
|
+
|
|
60
|
+
### Short runs
|
|
61
|
+
|
|
62
|
+
`minDurationMs` defaults to `0` (always notify). Raise it to skip the settle notification when the run finished faster, so one-line replies stop producing notification noise:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{ "minDurationMs": 30000 }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`minDurationMs` never suppresses needs-input notifications. Input notifications wait 400ms so an unsupported, cancelled, or quickly answered UI call does not send a stale alert. Pending alerts are cancelled when the prompt, run, or session ends. Questionnaire fallback events use a 1.5s de-duplication window because they have no shared dialog ID; separate fallback-only prompts inside that window may be merged. Native dialogs are tracked independently.
|
|
69
|
+
|
|
70
|
+
Completion notifications await the Bark request before Pi finishes settling, including during session switching or exit. This can delay those operations up to `timeoutMs` (default 4 seconds). Errors and timeouts are ignored; delivery is best-effort, with no persistent queue or retries.
|
|
35
71
|
|
|
36
72
|
The notification body uses `💻` for the configured machine name and `📁` for Pi's full working directory. Questionnaire text is intentionally not sent because it may contain sensitive context. Only sessions with a user-facing UI notify, so nested `pi-subagents` sessions do not create duplicate pushes.
|
|
37
73
|
|
|
@@ -1,39 +1,75 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionContext,
|
|
4
|
+
} from "@earendil-works/pi-coding-agent"
|
|
2
5
|
import { readFileSync } from "node:fs"
|
|
3
6
|
import { homedir, hostname } from "node:os"
|
|
4
7
|
import { join } from "node:path"
|
|
5
8
|
|
|
6
9
|
const ASK_USER_PROMPT_EVENT = "rpiv:ask-user:prompt"
|
|
10
|
+
/** Give closed/unsupported UI calls time to finish before notifying. */
|
|
11
|
+
const NEEDS_INPUT_DELAY_MS = 400
|
|
12
|
+
// ponytail: fallback events lack dialog IDs; this window can merge distinct fallback prompts.
|
|
13
|
+
// Replace it with dialog IDs if the event source provides them.
|
|
14
|
+
const NEEDS_INPUT_DEDUP_MS = 1_500
|
|
7
15
|
const DEFAULT_TIMEOUT_MS = 4_000
|
|
16
|
+
const DEFAULT_MAX_TITLE_LENGTH = 40
|
|
17
|
+
const DEFAULT_MIN_DURATION_MS = 0
|
|
8
18
|
|
|
9
19
|
export type BarkLocale = "en" | "zh-CN" | "zh-TW"
|
|
10
|
-
type NotificationEvent = "agentSettled" | "
|
|
20
|
+
type NotificationEvent = "agentSettled" | "needsInput"
|
|
21
|
+
export type BarkTitleSource = "fixed" | "session"
|
|
11
22
|
|
|
12
|
-
const COPY: Record<
|
|
23
|
+
const COPY: Record<
|
|
24
|
+
BarkLocale,
|
|
25
|
+
{
|
|
26
|
+
agentSettled: string
|
|
27
|
+
settledWithDuration: (duration: string) => string
|
|
28
|
+
needsInput: string
|
|
29
|
+
needsInputBody: string
|
|
30
|
+
}
|
|
31
|
+
> = {
|
|
13
32
|
en: {
|
|
14
33
|
agentSettled: "✅ Pi finished",
|
|
15
|
-
|
|
34
|
+
settledWithDuration: (duration) => `✅ Pi finished · ${duration}`,
|
|
35
|
+
needsInput: "🟡 Pi needs your input",
|
|
36
|
+
needsInputBody: "🟡 Needs your reply",
|
|
16
37
|
},
|
|
17
38
|
"zh-CN": {
|
|
18
39
|
agentSettled: "✅ Pi 跑完了",
|
|
19
|
-
|
|
40
|
+
settledWithDuration: (duration) => `✅ 已完成 · 用时 ${duration}`,
|
|
41
|
+
needsInput: "🟡 Pi 等你回答",
|
|
42
|
+
needsInputBody: "🟡 需要你回复",
|
|
20
43
|
},
|
|
21
44
|
"zh-TW": {
|
|
22
45
|
agentSettled: "✅ Pi 已完成",
|
|
23
|
-
|
|
46
|
+
settledWithDuration: (duration) => `✅ 已完成 · 耗時 ${duration}`,
|
|
47
|
+
needsInput: "🟡 Pi 等你回覆",
|
|
48
|
+
needsInputBody: "🟡 需要你回覆",
|
|
24
49
|
},
|
|
25
50
|
}
|
|
26
51
|
|
|
52
|
+
export interface BarkTitleOptions {
|
|
53
|
+
/** "fixed" keeps the localized Pi copy as the title (default). "session" uses the session title. */
|
|
54
|
+
source: BarkTitleSource
|
|
55
|
+
/** Maximum title length before truncation. */
|
|
56
|
+
maxLength: number
|
|
57
|
+
}
|
|
58
|
+
|
|
27
59
|
export interface BarkConfig {
|
|
28
60
|
endpoint: string
|
|
29
61
|
machine: string
|
|
30
62
|
locale: BarkLocale
|
|
31
63
|
events: {
|
|
32
64
|
agentSettled: boolean
|
|
33
|
-
|
|
65
|
+
/** Any blocking user-facing dialog: approval, select, input, custom, ask_user_question. */
|
|
66
|
+
needsInput: boolean
|
|
34
67
|
}
|
|
35
68
|
params: Record<string, string | number | boolean>
|
|
36
69
|
timeoutMs: number
|
|
70
|
+
title: BarkTitleOptions
|
|
71
|
+
/** Skip the settle notification when the run finished faster than this. 0 notifies always. */
|
|
72
|
+
minDurationMs: number
|
|
37
73
|
}
|
|
38
74
|
|
|
39
75
|
export function getConfigPath(): string {
|
|
@@ -61,6 +97,85 @@ export function notificationTitle(
|
|
|
61
97
|
return COPY[locale][event]
|
|
62
98
|
}
|
|
63
99
|
|
|
100
|
+
/** Render a bounded, human-readable duration such as `45s`, `2m14s`, or `1h3m`. */
|
|
101
|
+
export function formatDuration(ms: number): string {
|
|
102
|
+
const total = Math.max(0, Math.round(ms / 1000))
|
|
103
|
+
if (total < 60) return `${total}s`
|
|
104
|
+
const minutes = Math.floor(total / 60)
|
|
105
|
+
const seconds = total % 60
|
|
106
|
+
if (minutes < 60) return seconds ? `${minutes}m${seconds}s` : `${minutes}m`
|
|
107
|
+
const hours = Math.floor(minutes / 60)
|
|
108
|
+
const remainder = minutes % 60
|
|
109
|
+
return remainder ? `${hours}h${remainder}m` : `${hours}h`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function normalizeText(value: unknown): string {
|
|
113
|
+
if (typeof value !== "string") return ""
|
|
114
|
+
return value
|
|
115
|
+
.replace(/[\r\n\t]+/g, " ")
|
|
116
|
+
.replace(/\s{2,}/g, " ")
|
|
117
|
+
.trim()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function truncateTitle(text: string, maxLength: number): string {
|
|
121
|
+
const characters = Array.from(normalizeText(text))
|
|
122
|
+
if (!maxLength || characters.length <= maxLength) return characters.join("")
|
|
123
|
+
return `${characters
|
|
124
|
+
.slice(0, maxLength - 1)
|
|
125
|
+
.join("")
|
|
126
|
+
.trimEnd()}…`
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Read the text of a message content value (string or content-part array). */
|
|
130
|
+
export function readMessageText(content: unknown): string {
|
|
131
|
+
if (typeof content === "string") return content
|
|
132
|
+
if (!Array.isArray(content)) return ""
|
|
133
|
+
return content
|
|
134
|
+
.filter(
|
|
135
|
+
(part) =>
|
|
136
|
+
part &&
|
|
137
|
+
typeof part === "object" &&
|
|
138
|
+
(part as { type?: string }).type === "text" &&
|
|
139
|
+
typeof (part as { text?: unknown }).text === "string",
|
|
140
|
+
)
|
|
141
|
+
.map((part) => (part as { text: string }).text)
|
|
142
|
+
.join(" ")
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Pi session name if the user set one, else the first user message — the same
|
|
147
|
+
* label most hosts show for the session.
|
|
148
|
+
*/
|
|
149
|
+
export function resolveSessionTitle(
|
|
150
|
+
ctx: Pick<ExtensionContext, "sessionManager"> | undefined,
|
|
151
|
+
getSessionName?: () => string | undefined,
|
|
152
|
+
): string {
|
|
153
|
+
try {
|
|
154
|
+
const named = getSessionName?.()
|
|
155
|
+
if (typeof named === "string" && named.trim()) return named.trim()
|
|
156
|
+
} catch {
|
|
157
|
+
// fall through
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const manager = ctx?.sessionManager
|
|
161
|
+
const named = manager?.getSessionName?.()
|
|
162
|
+
if (typeof named === "string" && named.trim()) return named.trim()
|
|
163
|
+
} catch {
|
|
164
|
+
// fall through
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const entries = ctx?.sessionManager?.getEntries?.() ?? []
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
if (entry?.type !== "message" || entry.message?.role !== "user") continue
|
|
170
|
+
const text = normalizeText(readMessageText(entry.message.content))
|
|
171
|
+
if (text) return text
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
174
|
+
// fall through
|
|
175
|
+
}
|
|
176
|
+
return ""
|
|
177
|
+
}
|
|
178
|
+
|
|
64
179
|
export function normalizeConfig(input: unknown): BarkConfig | undefined {
|
|
65
180
|
if (!input || typeof input !== "object") return undefined
|
|
66
181
|
const source = input as Record<string, unknown>
|
|
@@ -92,6 +207,10 @@ export function normalizeConfig(input: unknown): BarkConfig | undefined {
|
|
|
92
207
|
source.timeoutMs > 0
|
|
93
208
|
? source.timeoutMs
|
|
94
209
|
: DEFAULT_TIMEOUT_MS
|
|
210
|
+
const titleSource =
|
|
211
|
+
source.title && typeof source.title === "object"
|
|
212
|
+
? (source.title as Record<string, unknown>)
|
|
213
|
+
: {}
|
|
95
214
|
|
|
96
215
|
return {
|
|
97
216
|
endpoint: source.endpoint,
|
|
@@ -102,10 +221,27 @@ export function normalizeConfig(input: unknown): BarkConfig | undefined {
|
|
|
102
221
|
locale: resolveLocale(source.locale),
|
|
103
222
|
events: {
|
|
104
223
|
agentSettled: eventSource.agentSettled !== false,
|
|
105
|
-
askUserQuestion
|
|
224
|
+
// `askUserQuestion` is the pre-0.2 name and is still honored.
|
|
225
|
+
needsInput:
|
|
226
|
+
(eventSource.needsInput ?? eventSource.askUserQuestion) !== false,
|
|
106
227
|
},
|
|
107
228
|
params,
|
|
108
229
|
timeoutMs,
|
|
230
|
+
title: {
|
|
231
|
+
source: titleSource.source === "session" ? "session" : "fixed",
|
|
232
|
+
maxLength:
|
|
233
|
+
typeof titleSource.maxLength === "number" &&
|
|
234
|
+
Number.isFinite(titleSource.maxLength) &&
|
|
235
|
+
titleSource.maxLength >= 1
|
|
236
|
+
? Math.floor(titleSource.maxLength)
|
|
237
|
+
: DEFAULT_MAX_TITLE_LENGTH,
|
|
238
|
+
},
|
|
239
|
+
minDurationMs:
|
|
240
|
+
typeof source.minDurationMs === "number" &&
|
|
241
|
+
Number.isFinite(source.minDurationMs) &&
|
|
242
|
+
source.minDurationMs >= 0
|
|
243
|
+
? source.minDurationMs
|
|
244
|
+
: DEFAULT_MIN_DURATION_MS,
|
|
109
245
|
}
|
|
110
246
|
}
|
|
111
247
|
|
|
@@ -145,34 +281,158 @@ export default function piBark(pi: ExtensionAPI): void {
|
|
|
145
281
|
let config: BarkConfig | undefined
|
|
146
282
|
let cwd = process.cwd()
|
|
147
283
|
let userFacingSession = false
|
|
284
|
+
let cachedTitle = ""
|
|
285
|
+
let runStartedAt: number | null = null
|
|
286
|
+
let pendingNeedsInput: ReturnType<typeof setTimeout> | undefined
|
|
287
|
+
let uiPromptActive = false
|
|
288
|
+
let lastFallbackAt = 0
|
|
289
|
+
let lastUIPromptEndAt = 0
|
|
148
290
|
|
|
149
|
-
const
|
|
291
|
+
const refreshTitle = (ctx: ExtensionContext | undefined): string => {
|
|
292
|
+
const resolved = resolveSessionTitle(ctx, () => pi.getSessionName?.())
|
|
293
|
+
if (resolved) cachedTitle = resolved
|
|
294
|
+
return cachedTitle
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const titleFor = (
|
|
298
|
+
ctx: ExtensionContext | undefined,
|
|
299
|
+
event: NotificationEvent,
|
|
300
|
+
): string => {
|
|
301
|
+
if (!config) return ""
|
|
302
|
+
if (config.title.source === "fixed")
|
|
303
|
+
return notificationTitle(config.locale, event)
|
|
304
|
+
const session = ctx ? refreshTitle(ctx) : cachedTitle
|
|
305
|
+
return truncateTitle(session || config.machine, config.title.maxLength)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const notify = async (title: string, body: string): Promise<void> => {
|
|
150
309
|
if (!config || !userFacingSession) return
|
|
151
310
|
try {
|
|
152
|
-
await sendBark(config, title,
|
|
311
|
+
await sendBark(config, title, body)
|
|
153
312
|
} catch {
|
|
154
313
|
// Notifications are best-effort and must never interrupt Pi.
|
|
155
314
|
}
|
|
156
315
|
}
|
|
157
316
|
|
|
317
|
+
const cancelNeedsInput = () => {
|
|
318
|
+
clearTimeout(pendingNeedsInput)
|
|
319
|
+
pendingNeedsInput = undefined
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const resetNeedsInput = () => {
|
|
323
|
+
cancelNeedsInput()
|
|
324
|
+
uiPromptActive = false
|
|
325
|
+
lastFallbackAt = 0
|
|
326
|
+
lastUIPromptEndAt = 0
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const scheduleNeedsInput = (ctx: ExtensionContext | undefined) => {
|
|
330
|
+
if (!config?.events.needsInput || !userFacingSession) return
|
|
331
|
+
cancelNeedsInput()
|
|
332
|
+
pendingNeedsInput = setTimeout(() => {
|
|
333
|
+
pendingNeedsInput = undefined
|
|
334
|
+
if (!config?.events.needsInput || !userFacingSession) return
|
|
335
|
+
if (!ctx) lastFallbackAt = Date.now()
|
|
336
|
+
const prefix =
|
|
337
|
+
config.title.source === "session"
|
|
338
|
+
? `${COPY[config.locale].needsInputBody}\n`
|
|
339
|
+
: ""
|
|
340
|
+
void notify(
|
|
341
|
+
titleFor(ctx, "needsInput"),
|
|
342
|
+
`${prefix}${formatBody(config, cwd)}`,
|
|
343
|
+
)
|
|
344
|
+
}, NEEDS_INPUT_DELAY_MS)
|
|
345
|
+
}
|
|
346
|
+
|
|
158
347
|
const unsubscribeAskUser = pi.events.on(ASK_USER_PROMPT_EVENT, () => {
|
|
159
|
-
|
|
160
|
-
|
|
348
|
+
const now = Date.now()
|
|
349
|
+
if (
|
|
350
|
+
uiPromptActive ||
|
|
351
|
+
now - lastUIPromptEndAt < NEEDS_INPUT_DEDUP_MS ||
|
|
352
|
+
now - lastFallbackAt < NEEDS_INPUT_DEDUP_MS
|
|
353
|
+
)
|
|
354
|
+
return
|
|
355
|
+
scheduleNeedsInput(undefined)
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
// Native prompt lifecycle cancels notifications for UI calls that finish
|
|
359
|
+
// without opening a dialog, or that the user answers before the grace period.
|
|
360
|
+
pi.on("ui_prompt_start", (_event, ctx) => {
|
|
361
|
+
cwd = ctx.cwd
|
|
362
|
+
uiPromptActive = true
|
|
363
|
+
cancelNeedsInput()
|
|
364
|
+
if (Date.now() - lastFallbackAt >= NEEDS_INPUT_DEDUP_MS)
|
|
365
|
+
scheduleNeedsInput(ctx)
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
pi.on("ui_prompt_end", () => {
|
|
369
|
+
uiPromptActive = false
|
|
370
|
+
lastFallbackAt = 0
|
|
371
|
+
lastUIPromptEndAt = Date.now()
|
|
372
|
+
cancelNeedsInput()
|
|
161
373
|
})
|
|
162
374
|
|
|
163
375
|
pi.on("session_start", (_event, ctx) => {
|
|
376
|
+
resetNeedsInput()
|
|
164
377
|
config = loadConfig()
|
|
165
378
|
cwd = ctx.cwd
|
|
166
379
|
userFacingSession = ctx.hasUI
|
|
380
|
+
runStartedAt = null
|
|
381
|
+
cachedTitle = ""
|
|
382
|
+
refreshTitle(ctx)
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
// Pi persists the user entry at message_end, not on submit, so the title cache has to be
|
|
386
|
+
// refreshed on message/turn events rather than only at agent_start.
|
|
387
|
+
pi.on("session_info_changed", (_event, ctx) => {
|
|
388
|
+
refreshTitle(ctx)
|
|
167
389
|
})
|
|
168
390
|
|
|
169
|
-
pi.on("
|
|
391
|
+
pi.on("message_end", (_event, ctx) => {
|
|
392
|
+
refreshTitle(ctx)
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
pi.on("turn_end", (_event, ctx) => {
|
|
396
|
+
refreshTitle(ctx)
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
pi.on("agent_start", (_event, ctx) => {
|
|
400
|
+
if (runStartedAt === null) {
|
|
401
|
+
resetNeedsInput()
|
|
402
|
+
runStartedAt = Date.now()
|
|
403
|
+
}
|
|
404
|
+
refreshTitle(ctx)
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
170
408
|
cwd = ctx.cwd
|
|
171
|
-
|
|
172
|
-
|
|
409
|
+
resetNeedsInput()
|
|
410
|
+
const startedAt = runStartedAt
|
|
411
|
+
runStartedAt = null
|
|
412
|
+
if (!config?.events.agentSettled) return
|
|
413
|
+
|
|
414
|
+
const elapsed = startedAt === null ? null : Date.now() - startedAt
|
|
415
|
+
if (elapsed !== null && elapsed < config.minDurationMs) return
|
|
416
|
+
|
|
417
|
+
const copy = COPY[config.locale]
|
|
418
|
+
const prefix =
|
|
419
|
+
config.title.source === "session"
|
|
420
|
+
? `${
|
|
421
|
+
elapsed === null
|
|
422
|
+
? copy.agentSettled
|
|
423
|
+
: copy.settledWithDuration(formatDuration(elapsed))
|
|
424
|
+
}\n`
|
|
425
|
+
: ""
|
|
426
|
+
// Await the request so a settle that races process shutdown still delivers.
|
|
427
|
+
await notify(
|
|
428
|
+
titleFor(ctx, "agentSettled"),
|
|
429
|
+
`${prefix}${formatBody(config, cwd)}`,
|
|
430
|
+
)
|
|
173
431
|
})
|
|
174
432
|
|
|
175
433
|
pi.on("session_shutdown", () => {
|
|
434
|
+
userFacingSession = false
|
|
435
|
+
resetNeedsInput()
|
|
176
436
|
unsubscribeAskUser()
|
|
177
437
|
})
|
|
178
438
|
}
|