{"_id":"@drmikecrowe/omp-claude-hooks-bridge","_rev":"5-42e0bbd57a000c1a98b5a1d512c75288","name":"@drmikecrowe/omp-claude-hooks-bridge","dist-tags":{"latest":"0.5.0"},"versions":{"0.2.2":{"name":"@drmikecrowe/omp-claude-hooks-bridge","version":"0.2.2","keywords":["omp-package"],"author":{"name":"drmikecrowe"},"license":"MIT","_id":"@drmikecrowe/omp-claude-hooks-bridge@0.2.2","maintainers":[{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"}],"homepage":"https://github.com/drmikecrowe/omp-claude-hooks-bridge#readme","bugs":{"url":"https://github.com/drmikecrowe/omp-claude-hooks-bridge/issues"},"omp":{"extensions":["./index.ts"]},"dist":{"shasum":"8f0aa096a3156295acb1d97ae48c197c20c20bf1","tarball":"https://registry.npmjs.org/@drmikecrowe/omp-claude-hooks-bridge/-/omp-claude-hooks-bridge-0.2.2.tgz","fileCount":3,"integrity":"sha512-OqfMwLUEmu/cBoAHMaz8y5Du9dhzK9MUsMTo/jdMmmWiJFMOWU/ORnijVPzzb0sK6jtX5pj1yviMSGo4F0Jc1A==","signatures":[{"sig":"MEUCIGmSmIYpbtGsebTgDRKFmRowyL+z+kDAFBzHlffFej7pAiEAlueef+9+t0xBIG7Tve+8L8tmaUDONg5iVRebMZndVx8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33142},"type":"module","scripts":{"test":"vitest run","release":"bash scripts/publish.sh","release:dry":"bash scripts/publish.sh --dry-run","prepublishOnly":"npm test"},"_npmUser":{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"},"repository":{"url":"git+https://github.com/drmikecrowe/omp-claude-hooks-bridge.git","type":"git"},"_npmVersion":"11.13.0","description":"Bridge Claude Code hooks (.claude/settings.json) into omp (Oh My Pi) extension lifecycle events.","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.9"},"_npmOperationalInternal":{"tmp":"tmp/omp-claude-hooks-bridge_0.2.2_1781533551093_0.5047829149739846","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@drmikecrowe/omp-claude-hooks-bridge","version":"0.3.0","keywords":["omp-package"],"author":{"name":"drmikecrowe"},"license":"MIT","_id":"@drmikecrowe/omp-claude-hooks-bridge@0.3.0","maintainers":[{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"}],"homepage":"https://github.com/drmikecrowe/omp-claude-hooks-bridge#readme","bugs":{"url":"https://github.com/drmikecrowe/omp-claude-hooks-bridge/issues"},"omp":{"extensions":["./index.ts"]},"dist":{"shasum":"e1113817727a0d7ff5fc7eccef18a1bf34b14b32","tarball":"https://registry.npmjs.org/@drmikecrowe/omp-claude-hooks-bridge/-/omp-claude-hooks-bridge-0.3.0.tgz","fileCount":4,"integrity":"sha512-ecAY9FH7EIrjpO5wzkX3KaDBBbF40c/cN6jjKrjXUw7lMIJ4cmc4mSUfXwClP4QoAJeNX0fyKMetheOuBrGmeg==","signatures":[{"sig":"MEUCIQC5HyDITp0UKl2KVisDKa/ZwWW6Lu9ZKpGbZ6V5c9SwnwIgLIfYdFxadGO0rYMDNbAt87fwZDOg1zlq+ykrEgyYn8U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38326},"type":"module","gitHead":"3b4408b827e8ebed84831697ba896c9573d7083d","scripts":{"test":"vitest run","release":"bash scripts/publish.sh","release:dry":"bash scripts/publish.sh --dry-run","prepublishOnly":"npm test"},"_npmUser":{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"},"repository":{"url":"git+https://github.com/drmikecrowe/omp-claude-hooks-bridge.git","type":"git"},"_npmVersion":"11.16.0","description":"Bridge Claude Code hooks (.claude/settings.json) into omp (Oh My Pi) extension lifecycle events.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.9"},"_npmOperationalInternal":{"tmp":"tmp/omp-claude-hooks-bridge_0.3.0_1784117008364_0.23465297867483303","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@drmikecrowe/omp-claude-hooks-bridge","version":"0.4.0","keywords":["omp-package"],"author":{"name":"drmikecrowe"},"license":"MIT","_id":"@drmikecrowe/omp-claude-hooks-bridge@0.4.0","maintainers":[{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"}],"homepage":"https://github.com/drmikecrowe/omp-claude-hooks-bridge#readme","bugs":{"url":"https://github.com/drmikecrowe/omp-claude-hooks-bridge/issues"},"omp":{"extensions":["./index.ts"]},"dist":{"shasum":"f52233b947a2e4fd9d3f7e6d17abc146d2f90b60","tarball":"https://registry.npmjs.org/@drmikecrowe/omp-claude-hooks-bridge/-/omp-claude-hooks-bridge-0.4.0.tgz","fileCount":4,"integrity":"sha512-/vM82wXnjxRmb1841VidXZf5e+AVd4rDrZtQVayN/Vi9R/iyKHS5s7Q0/dGjXjQ8zyNQzt/lKfxmDmDJRlcA2g==","signatures":[{"sig":"MEYCIQDqclGmFlyOdmFXojYM3L9Tmm48jczd1qHnRRf/P3x2pAIhAMcqqKXb9q8+1nqwmPkCxW3Uvi50x+q2+buuLecFcPXX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41869},"type":"module","gitHead":"ff3bc69cbd6ef777b9c7d5bf237b7ec38efb3475","scripts":{"test":"vitest run","release":"varlock run -- bash scripts/publish.sh","release:dry":"varlock run -- bash scripts/publish.sh --dry-run","prepublishOnly":"npm test"},"_npmUser":{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"},"repository":{"url":"git+https://github.com/drmikecrowe/omp-claude-hooks-bridge.git","type":"git"},"_npmVersion":"11.17.0","description":"Bridge Claude Code hooks (.claude/settings.json) into omp (Oh My Pi) extension lifecycle events.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.9"},"_npmOperationalInternal":{"tmp":"tmp/omp-claude-hooks-bridge_0.4.0_1786873288627_0.3601805793687405","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@drmikecrowe/omp-claude-hooks-bridge","version":"0.4.1","keywords":["omp-package"],"author":{"name":"drmikecrowe"},"license":"MIT","_id":"@drmikecrowe/omp-claude-hooks-bridge@0.4.1","maintainers":[{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"}],"homepage":"https://github.com/drmikecrowe/omp-claude-hooks-bridge#readme","bugs":{"url":"https://github.com/drmikecrowe/omp-claude-hooks-bridge/issues"},"omp":{"extensions":["./index.ts"]},"dist":{"shasum":"d5e46bdaacd16c4dd533ae2923b6fb2471058aa5","tarball":"https://registry.npmjs.org/@drmikecrowe/omp-claude-hooks-bridge/-/omp-claude-hooks-bridge-0.4.1.tgz","fileCount":4,"integrity":"sha512-dr3P8oVthlL9t9J1Ccp+ZlSVRjhOUFH4VhjJLSIoDMmrroxovgVebdB0XnxOs02r/LLZl9zXnl8MOrgGtrQwKg==","signatures":[{"sig":"MEUCIHk6b/rgz7BjuuHpyaW0YWDr12hL12rG4g5YsxrNp9lmAiEAlSJMTVdTbQ+sWzpm+vzdg7DnUCuTYDp5DGrJZlWeMLw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":45814},"type":"module","gitHead":"c1639acbc9137a7d81dce788fc7b53fbc07b45ea","scripts":{"test":"vitest run","release":"varlock run -- bash scripts/publish.sh","release:dry":"varlock run -- bash scripts/publish.sh --dry-run","prepublishOnly":"npm test"},"_npmUser":{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"},"repository":{"url":"git+https://github.com/drmikecrowe/omp-claude-hooks-bridge.git","type":"git"},"_npmVersion":"11.17.0","description":"Bridge Claude Code hooks (.claude/settings.json) into omp (Oh My Pi) extension lifecycle events.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.9"},"_npmOperationalInternal":{"tmp":"tmp/omp-claude-hooks-bridge_0.4.1_1786886586653_0.29664829960797956","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@drmikecrowe/omp-claude-hooks-bridge","version":"0.5.0","description":"Bridge Claude Code hooks (.claude/settings.json) into omp (Oh My Pi) extension lifecycle events.","license":"MIT","scripts":{"test":"vitest run","release":"varlock run -- bash scripts/publish.sh","release:dry":"varlock run -- bash scripts/publish.sh --dry-run","prepublishOnly":"npm test"},"repository":{"type":"git","url":"git+https://github.com/drmikecrowe/omp-claude-hooks-bridge.git"},"author":{"name":"drmikecrowe"},"bugs":{"url":"https://github.com/drmikecrowe/omp-claude-hooks-bridge/issues"},"homepage":"https://github.com/drmikecrowe/omp-claude-hooks-bridge#readme","type":"module","keywords":["omp-package"],"omp":{"extensions":["./index.ts"]},"devDependencies":{"vitest":"^4.1.9"},"publishConfig":{"access":"public"},"gitHead":"b9f3ab2c71d5fedf3e943d661ccc27adbb589007","_id":"@drmikecrowe/omp-claude-hooks-bridge@0.5.0","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-07JQun6oInM3jELhu6IWU+3KUip7SkO7cNVLfH0nrtdQR9Jj7L3OAShRkKxRjjOvExbv8VR5WvT4A0iKEmGNUw==","shasum":"d1cb750a2f4eea6ae13b23046269dd0ce813f7dc","tarball":"https://registry.npmjs.org/@drmikecrowe/omp-claude-hooks-bridge/-/omp-claude-hooks-bridge-0.5.0.tgz","fileCount":5,"unpackedSize":54539,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEUK7Pbs5kQpPI+h3kybhFYFve4mGI8tOXb3MLYhkW4wAiEA/4PGvscJv/xVixR0Q0EicDNhx5QdnASvAcUekKZ2Zzc="}]},"_npmUser":{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"},"directories":{},"maintainers":[{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/omp-claude-hooks-bridge_0.5.0_1786898876659_0.5934035770678792"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-15T14:25:50.913Z","modified":"2026-08-16T16:47:56.940Z","0.2.2":"2026-06-15T14:25:51.269Z","0.3.0":"2026-07-15T12:03:28.478Z","0.4.0":"2026-08-16T09:41:28.779Z","0.4.1":"2026-08-16T13:23:06.793Z","0.5.0":"2026-08-16T16:47:56.798Z"},"bugs":{"url":"https://github.com/drmikecrowe/omp-claude-hooks-bridge/issues"},"author":{"name":"drmikecrowe"},"license":"MIT","homepage":"https://github.com/drmikecrowe/omp-claude-hooks-bridge#readme","keywords":["omp-package"],"repository":{"type":"git","url":"git+https://github.com/drmikecrowe/omp-claude-hooks-bridge.git"},"description":"Bridge Claude Code hooks (.claude/settings.json) into omp (Oh My Pi) extension lifecycle events.","maintainers":[{"name":"drmikecrowe","email":"drmikecrowe@gmail.com"}],"readme":"# omp-claude-hooks-bridge\n\n> **Built on top of upstream.** This package reuses the `claude-hooks-bridge`\n> implementation from [`Jonghakseo/pi-extension`](https://github.com/Jonghakseo/pi-extension)\n> (originally published to npm as\n> [`@ryan_nookpi/pi-extension-claude-hooks-bridge`](https://www.npmjs.com/package/@ryan_nookpi/pi-extension-claude-hooks-bridge))\n> as its foundation, ports it to the omp runtime, and enhances it further.\n> Full attribution and the list of enhancements are in [Origins](#origins)\n> below — please credit the upstream authors if you reuse this code.\n\nBridge [Claude Code hooks](https://docs.anthropic.com/en/docs/claude-code/hooks) (`.claude/settings.json`) into omp (Oh My Pi) extension lifecycle events.\n\n## What it does\n\n- Reads `.claude/settings.json` hooks configuration from the project root\n- Executes hooks at matching lifecycle events:\n  - **SessionStart** → `session_start`\n  - **UserPromptSubmit** → `before_agent_start`\n  - **PreToolUse** → `tool_call` (can block / ask for confirmation / rewrite tool input)\n  - **PostToolUse** → `tool_result`\n  - **PreCompact** → `session_before_compact` (can cancel compaction)\n  - **Stop** → `agent_end` (can queue follow-up messages)\n- Supports matcher patterns (regex or pipe-separated tool names), including\n  `PreCompact`'s `manual` / `auto` trigger matcher\n- Maps omp tool names to Claude Code equivalents (`bash` → `Bash`, etc.)\n- Handles hook JSON output with `permissionDecision` / exit code 2 for blocking\n- Provides transcript files for Stop and PreCompact hooks\n- Injects hook context into the conversation, matching Claude Code semantics:\n  `hookSpecificOutput.additionalContext` from `SessionStart` and\n  `UserPromptSubmit`, plus plain stdout from those same two events.\n  `SessionStart` context is queued for the next user prompt (omp\n  `session_start` handlers cannot return context); `UserPromptSubmit` context\n  is injected into the turn it belongs to. Context from other events is not\n  injected — see [Not bridgeable on omp](#not-bridgeable-on-omp).\n\nRelease history is in [CHANGELOG.md](CHANGELOG.md).\n\n### Not bridgeable on omp\n\nThese Claude Code context-injection paths are **not** injected today, rather\nthan faked with a mid-turn message:\n\n| Claude behavior | Status | Why |\n| --- | --- | --- |\n| `PreToolUse` `additionalContext` | Not injected (deviation required) | omp's `tool_call` result has no context field. The only same-turn landing spot is the paired `tool_result`, which arrives *after* the tool ran, so the context cannot influence whether the call happens — it can only steer later calls. See the note below. |\n| `PostToolUse` `additionalContext` | Not injected (fixable) | omp's `tool_result` result *does* accept replacement `content`, and Claude Code injects this context post-execution too, so bridging it would be faithful rather than a deviation. Nothing blocks it; it is simply not wired up yet. |\n| `SubagentStart` | Not bridgeable | omp has no `subagent_*` event, and `session_stop` never fires for subagents, so there is nothing to hook. |\n\n`PreToolUse` hooks still run, and their `allow` / `ask` / `deny` decisions and\n`hookSpecificOutput.updatedInput` rewrites are still honored — only the\n`additionalContext` field is dropped.\n\n**On attaching `PreToolUse` context to the paired `tool_result`** — this is\nmechanically possible (`ToolResultEventResult.content` replaces the content\narray, and `ToolResultEvent.content` exposes the original to append to), and\nfor advisory hooks such as a routing nudge it lands in the right turn and\nfires only on the matching tool call. It is still a real semantic deviation:\nthe context arrives after execution, so a hook written as a precondition\n(\"don't run this without X\") reads as a post-hoc note, and the model sees the\ntext as part of the tool's own output unless it is explicitly labelled. The\ndecision is therefore: **not while the same steering need is served faithfully\nby `PostToolUse` `additionalContext`** (row above), which arrives at the same\npoint in the conversation and is what Claude Code itself does. If you have a\n`PreToolUse` hook whose only job is steering, prefer configuring it as\n`PostToolUse`.\n\n### Tool-input rewriting\n\nA `PreToolUse` hook that returns `hookSpecificOutput.updatedInput` replaces the\narguments the tool runs with, matching omp's `tool_call` `input` contract:\n\n```json\n{ \"hookSpecificOutput\": { \"hookEventName\": \"PreToolUse\",\n  \"updatedInput\": { \"command\": \"rtk git status\", \"description\": \"check status\" } } }\n```\n\nSemantics follow omp: a `block` decision short-circuits ahead of any rewrite,\nthe last non-blocking rewrite wins when several hooks match, the returned\nobject *replaces* the raw arguments rather than merging into them, and hooks\ndo not see earlier hooks' revisions. omp ignores input replacement for\n`computer` calls.\n\n### Compaction hooks\n\n`PreCompact` maps to omp's `session_before_compact`. Hooks receive the common\nfields plus `trigger`, `custom_instructions`, and `transcript_path`:\n\n```json\n{ \"hook_event_name\": \"PreCompact\", \"trigger\": \"manual\",\n  \"custom_instructions\": \"keep the auth work\", \"transcript_path\": \"/tmp/...\" }\n```\n\n`trigger` is `manual` for `/compact` and `auto` for omp's automatic\ncompaction, derived from omp's `auto_compaction_start` / `auto_compaction_end`\nevents which bracket the automatic path. It doubles as the matcher value, so\n`\"matcher\": \"auto\"` runs a hook only on automatic compaction.\n`custom_instructions` carries what the user passed to `/compact`, and is empty\non the auto path — matching Claude Code.\n\nA `deny` / `block` decision or exit code 2 cancels the compaction, which is\nwhat Claude Code's exit-2 semantics do for this event. Claude Code's\n`PostCompact` has an omp analogue (`session_compact`) but is not bridged yet.\n\n## Requirements\n\n- **bash** is required — hooks are executed via `bash -lc`. Works on macOS and Linux. Not natively supported on Windows.\n\n## Security\n\nThis extension executes shell commands found in **any** `.claude/settings.json`\nit discovers — the current project's (`<cwd>/.claude/settings.json`), your\nhome config (`$CLAUDE_CONFIG_DIR/settings.json`, default `~/.claude/settings.json`),\n`~/.claude.json`, and installed plugin `hooks.json` files — with the same\nprivileges as the omp process itself (`bash -lc <command>`, full environment).\n\n**Only `PreToolUse` \"ask\"/\"block\" decisions go through a user confirmation\nprompt.** `SessionStart`, `UserPromptSubmit`, `PostToolUse`, and `Stop` hooks\nrun immediately and unconditionally the moment their lifecycle event fires —\n`SessionStart` hooks run before you've typed anything.\n\n**A `PreToolUse` hook can rewrite the arguments a tool runs with, and that\nrewrite is not confirmed.** `updatedInput` replaces the command before it\nexecutes, so an untrusted hook can turn an approved command into a different\none. Review rewriting hooks with the same care as blocking ones.\n\n**Opening or `cd`-ing into a directory whose `.claude/settings.json` you do\nnot trust is equivalent to running its shell commands.** Treat an untrusted\nrepository containing hook configuration the same way you'd treat an\nuntrusted shell script — do not open it with this extension active unless\nyou've reviewed `.claude/settings.json` first.\n\n## Install\n\n```bash\nomp plugin install @drmikecrowe/omp-claude-hooks-bridge\n```\n\n## Origins\n\n**This package is not a from-scratch implementation — it reuses and builds\non upstream work.** The entire hook-bridging design (settings discovery,\nmatcher logic, hook execution, decision extraction, transcript handling)\noriginates from the `claude-hooks-bridge` package in the\n[`Jonghakseo/pi-extension`](https://github.com/Jonghakseo/pi-extension)\nmonorepo, originally published to npm as\n[`@ryan_nookpi/pi-extension-claude-hooks-bridge`](https://www.npmjs.com/package/@ryan_nookpi/pi-extension-claude-hooks-bridge).\n**All credit for the original design and implementation belongs to that\nproject's authors.**\n\n### What was reused as-is\n\n- The core hook lifecycle model (`SessionStart` / `UserPromptSubmit` /\n  `PreToolUse` / `PostToolUse` / `Stop`) and its mapping onto extension\n  events.\n- Settings discovery and merge order across project and home\n  `.claude/settings.json`.\n- Matcher-pattern matching, tool-name aliasing, and hook decision extraction\n  (`permissionDecision`, exit-code-2 blocking).\n- Transcript-file generation for `Stop` hooks.\n\n### What this fork ports and adds on top\n\n- **Runtime port**: targets omp extension packaging (`omp.extensions`\n  manifest, `omp plugin install`) and builds against the\n  `@oh-my-pi/pi-coding-agent` extension SDK instead of `pi`'s.\n- **`CLAUDE_CONFIG_DIR` support**: home-config resolution (`settings.json`,\n  `installed_plugins.json`) now honors the `CLAUDE_CONFIG_DIR` environment\n  variable, matching Claude Code's own documented config-dir override,\n  instead of hardcoding `~/.claude`.\n- **Hook context injection**: upstream executed hooks but discarded whatever\n  context they emitted, so hooks whose only purpose is to steer the agent\n  were effectively no-ops. This fork injects it, matching Claude Code\n  semantics — `hookSpecificOutput.additionalContext` from any event, plus\n  plain stdout from `SessionStart` / `UserPromptSubmit` — routed through\n  whichever omp API each event supports (`pi.sendMessage` with\n  `deliverAs: \"nextTurn\"` for `session_start`, a returned `message` for\n  `before_agent_start`). See [Not bridgeable on omp](#not-bridgeable-on-omp)\n  for the two paths that have no omp equivalent.\n- **`PreCompact` bridging**: upstream mapped no omp event to Claude Code's\n  `PreCompact`. It now maps to `session_before_compact`, with the\n  `manual`/`auto` trigger, matcher support, and cancel-on-block.\n- **Tool-input rewriting**: upstream read only the block/ask decision from\n  `PreToolUse` results and dropped `hookSpecificOutput.updatedInput`, so\n  command-rewriting hooks silently did nothing. This fork returns the rewrite\n  as omp's `tool_call` `input`, stripping the path aliases the payload\n  normalizer adds so the replacement keeps the tool's own key shape.\n- **Security hardening**: transcript files and their directory are now\n  created with restrictive `0600`/`0700` permissions instead of umask\n  defaults, so session transcripts aren't world-readable on shared hosts;\n  the plugin project-scope check is now path-boundary-safe instead of a\n  raw prefix match, so a sibling directory can no longer inherit another\n  project's plugin hooks.\n- **Documentation**: a `Security` section spelling out exactly which hook\n  events execute unconfirmed shell commands and when, plus this expanded\n  attribution.\n\nNaming and documentation are rebranded from `pi` to `omp` throughout, and\nthe package is republished under the `@drmikecrowe` namespace as\n`@drmikecrowe/omp-claude-hooks-bridge`, **distributed under the same MIT\nlicense as upstream** (see [`LICENSE`](./LICENSE), which carries forward\nthe original copyright notice).\n\nIf you fork or reuse this code further, please preserve this attribution\nchain back to [`Jonghakseo/pi-extension`](https://github.com/Jonghakseo/pi-extension).\n","readmeFilename":"README.md"}