Update numpy-documentation-search extension#27290
Conversation
- feat: support local docs fallback - chore: Updated changelog to match new readme update - chore: Updated readme to better fit with other raycast extensions - Pull contributions - Merge pull request raycast#14 from Faria22/copilot/fix-compilation-issue-raycast - fix: resolve TypeScript compilation errors for Raycast build - Initial plan - chore: Removed unused assest - chore: Updated screenshots - Merge pull request raycast#13 from Faria22/copilot/remove-ufunc-from-signature - Merge branch \'main\' into copilot/remove-ufunc-from-signature - Fix: Remove ufunc assignment from function signatures - Add test fixture and test case for ufunc signature issue - chore: Fixed changelog dates - Initial plan - Merge pull request raycast#11 from Faria22/copilot/update-toggle-to-use-np - Add prefix toggle feature with np./numpy. preference (default: np.) - Initial plan - chore: Added screenshots - style: changed wording from `qualified name` to `item name` - Merge pull request raycast#9 from Faria22/copilot/remove-hash-from-url - docs: update CHANGELOG to version 1.1.1 and add versioning guidelines to AGENTS.md - fix: remove hash fragments from documentation URLs - chore: Added MIT license - Initial plan - Merge pull request raycast#4 from Faria22/copilot/fix-item-descriptions-code-blocks - Merge branch \'main\' into copilot/fix-item-descriptions-code-blocks - docs: update CHANGELOG with inline code blocks fix - Merge pull request raycast#5 from Faria22/copilot/update-agents-md-change-log - docs: Clarify CHANGELOG.md should be updated after any changes - Initial plan - feat: preserve inline code blocks in parameter descriptions - Merge pull request raycast#2 from Faria22/copilot/update-changelog-to-v1-0 - chore: update CHANGELOG.md to v1.0.0 with comprehensive feature list - Initial plan - Initial plan - chore: Removed outdated planning files - Merge pull request raycast#1 from Faria22/copilot/update-implement-plan-structure - Final documentation style - Revert "Use HTML line break and non-breaking spaces to force parameter description on new line" - Use HTML line break and non-breaking spaces to force parameter description on new line - Fix parameter rendering by splitting multi-line strings into individual array elements - Add blank line after each parameter for proper markdown multi-line rendering - Format parameter descriptions to match NumPy style with indented descriptions - Updated the documentation style - Add fullscreen documentation view with Action.Push for enhanced navigation - Remove metadata section with signature, keep signature only in markdown - Remove signature preference and fix private member filtering for all segments - Implement enhanced signature presentation with floating header and private member filtering - Initial plan - Implementation plan - fix: add description to signature preference - fix: add label for signature preference - style: enlarge detail section headings - feat: add pinned signature preference - docs: emphasize pushing after commits - feat: streamline detail panel layout - refactor: use raycast hooks for numpy docs - chore: add debug logging for doc loading - chore: add debug logging for doc loading - fix: allow numpy doc details to load - Added description to NumPy Docs command - chore: remove legacy command stub - docs: update contributor guidance and usage - feat: add numpy docs search command - Updated the extension icon - First commit
|
Thank you for your contribution! 🎉 🔔 @Faria22 you might want to have a look. You can use this guide to learn how to check out the Pull Request locally in order to test it. 📋 Quick checkout commandsBRANCH="ext/numpy-documentation-search"
FORK_URL="https://github.com/Faria22/raycast-extensions.git"
EXTENSION_NAME="numpy-documentation-search"
REPO_NAME="raycast-extensions"
git clone -n --depth=1 --filter=tree:0 -b $BRANCH $FORK_URL
cd $REPO_NAME
git sparse-checkout set --no-cone "extensions/$EXTENSION_NAME"
git checkout
cd "extensions/$EXTENSION_NAME"
npm install && npm run devWe're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a local documentation fallback for the NumPy Documentation Search Raycast extension, allowing it to function when numpy.org is unreachable by loading a downloaded local docs bundle.
Changes:
- Introduces a
docs-sourceloader that can fetch inventory/details remotely with local fallback (or force local). - Updates command UI to show a guided recovery state + preference shortcut when live docs fail.
- Adds vitest coverage for remote→local fallback and local detail loading.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| extensions/numpy-documentation-search/src/numpy-docs.tsx | Wires new inventory/detail loading modes into the UI and adds recovery actions/markdown. |
| extensions/numpy-documentation-search/src/lib/inventory.ts | Refactors inventory transformation to support Buffer-based parsing for local file reads. |
| extensions/numpy-documentation-search/src/lib/docs-source.ts | Implements remote/local loaders and fallback logic for inventory and detail HTML. |
| extensions/numpy-documentation-search/src/hooks/useInventory.ts | Replaces useFetch with custom hook to support fallback + remoteError/source metadata. |
| extensions/numpy-documentation-search/src/hooks/useDocDetail.ts | Replaces useFetch with custom hook to support local detail loading + source metadata. |
| extensions/numpy-documentation-search/src/tests/docs-source.test.ts | Adds tests for online fallback behavior and local detail parsing. |
| extensions/numpy-documentation-search/package.json | Adds preferences for documentation source mode and local docs directory; updates titles. |
| extensions/numpy-documentation-search/README.md | Documents certificate-restricted network recovery and local docs configuration. |
| extensions/numpy-documentation-search/CHANGELOG.md | Adds release notes for the new local-docs fallback flow. |
Files not reviewed (1)
- extensions/numpy-documentation-search/package-lock.json: Language not supported
| const htmlPath = path.join(directory, item.docPath.split("#")[0] ?? item.docPath); | ||
| return parseDocDetail(await deps.readTextFileImpl(htmlPath), item); | ||
| } | ||
|
|
There was a problem hiding this comment.
item.docPath originates from the inventory and is used to build a filesystem path via path.join(...). If the inventory is remote/untrusted (or becomes corrupted), a docPath containing ../ or an absolute path could escape the intended stable directory and read arbitrary local files. Consider resolving the path (e.g., path.resolve) and enforcing that the resolved path stays within directory (prefix check), and reject absolute paths / path traversal segments before reading.
| const htmlPath = path.join(directory, item.docPath.split("#")[0] ?? item.docPath); | |
| return parseDocDetail(await deps.readTextFileImpl(htmlPath), item); | |
| } | |
| const htmlPath = resolveDocPathWithinDirectory(directory, item.docPath); | |
| return parseDocDetail(await deps.readTextFileImpl(htmlPath), item); | |
| } | |
| function resolveDocPathWithinDirectory(directory: string, docPath: string): string { | |
| const relativeDocPath = docPath.split("#")[0] ?? docPath; | |
| if (!relativeDocPath) { | |
| throw new Error("Documentation path is empty."); | |
| } | |
| if (path.isAbsolute(relativeDocPath)) { | |
| throw new Error(`Documentation path must be relative: ${docPath}`); | |
| } | |
| const resolvedDirectory = path.resolve(directory); | |
| const resolvedDocPath = path.resolve(resolvedDirectory, relativeDocPath); | |
| const relativeToDirectory = path.relative(resolvedDirectory, resolvedDocPath); | |
| if ( | |
| relativeToDirectory === ".." || | |
| relativeToDirectory.startsWith(`..${path.sep}`) || | |
| path.isAbsolute(relativeToDirectory) | |
| ) { | |
| throw new Error(`Documentation path escapes the docs directory: ${docPath}`); | |
| } | |
| return resolvedDocPath; | |
| } |
| function RecoveryActions({ revalidate }: { revalidate: () => void }) { | ||
| return ( | ||
| <ActionPanel> | ||
| <Action title="Open Command Preferences" onAction={openCommandPreferences} /> | ||
| <Action title="Retry Live Download" icon={Icon.ArrowClockwise} onAction={revalidate} /> | ||
| <Action.OpenInBrowser title="Open NumPy Docs Repository" url="https://github.com/numpy/doc" /> | ||
| </ActionPanel> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Retry Live Download is misleading when the user has set Documentation Source to Local Docs Directory (or when the failure is a local filesystem error). revalidate will just retry the same mode, not necessarily a live download. Suggest making the label conditional (e.g., Retry / Reload Inventory) or wiring the action to explicitly retry remote loading when in the fallback UI.
| function buildRecoveryMarkdown(error: Error, hasLocalDocsDirectory: boolean): string { | ||
| return [ | ||
| "# Unable to reach live NumPy docs", | ||
| "", | ||
| "This extension was not able to connect to `https://numpy.org/doc/stable/`.", | ||
| "", | ||
| "If you can access the internet outside of Raycast, you can download the generated NumPy docs elsewhere and point the extension at that folder.", | ||
| "", | ||
| "## Setup", | ||
| "", | ||
| "1. Download the ZIP for the generated NumPy docs from [numpy/doc](https://github.com/numpy/doc) or get it from another machine that can access `numpy.org`.", | ||
| "2. Extract the ZIP locally. The extension will look for the documentation version under the `stable` folder inside what you downloaded.", | ||
| hasLocalDocsDirectory | ||
| ? "3. Open this command's preferences and verify that **Local Docs Directory** points to the downloaded docs folder." | ||
| : "3. Open this command's preferences and set **Local Docs Directory** to the downloaded docs folder.", |
There was a problem hiding this comment.
This markdown always frames the problem as a network failure to numpy.org, but inventoryError can also be caused by local-mode configuration issues (e.g., missing Local Docs Directory, missing stable/objects.inv, unreadable file). Consider tailoring the recovery copy based on whether the failure is a remoteError vs a local filesystem/config error so users aren’t directed to “download docs” when they simply selected the wrong directory.
| function buildRecoveryMarkdown(error: Error, hasLocalDocsDirectory: boolean): string { | |
| return [ | |
| "# Unable to reach live NumPy docs", | |
| "", | |
| "This extension was not able to connect to `https://numpy.org/doc/stable/`.", | |
| "", | |
| "If you can access the internet outside of Raycast, you can download the generated NumPy docs elsewhere and point the extension at that folder.", | |
| "", | |
| "## Setup", | |
| "", | |
| "1. Download the ZIP for the generated NumPy docs from [numpy/doc](https://github.com/numpy/doc) or get it from another machine that can access `numpy.org`.", | |
| "2. Extract the ZIP locally. The extension will look for the documentation version under the `stable` folder inside what you downloaded.", | |
| hasLocalDocsDirectory | |
| ? "3. Open this command's preferences and verify that **Local Docs Directory** points to the downloaded docs folder." | |
| : "3. Open this command's preferences and set **Local Docs Directory** to the downloaded docs folder.", | |
| function isLikelyRemoteInventoryError(error: Error, hasLocalDocsDirectory: boolean): boolean { | |
| const message = error.message.toLowerCase(); | |
| const localIndicators = [ | |
| "enoent", | |
| "eacces", | |
| "eperm", | |
| "not found", | |
| "no such file", | |
| "objects.inv", | |
| "local docs", | |
| "directory", | |
| "file", | |
| "path", | |
| "read", | |
| "open", | |
| ]; | |
| const remoteIndicators = [ | |
| "fetch", | |
| "network", | |
| "timeout", | |
| "timed out", | |
| "connect", | |
| "connection", | |
| "dns", | |
| "socket", | |
| "http", | |
| "https", | |
| "numpy.org", | |
| ]; | |
| if (localIndicators.some((indicator) => message.includes(indicator))) { | |
| return false; | |
| } | |
| if (remoteIndicators.some((indicator) => message.includes(indicator))) { | |
| return true; | |
| } | |
| return !hasLocalDocsDirectory; | |
| } | |
| function buildRecoveryMarkdown(error: Error, hasLocalDocsDirectory: boolean): string { | |
| const isRemoteError = isLikelyRemoteInventoryError(error, hasLocalDocsDirectory); | |
| if (isRemoteError) { | |
| return [ | |
| "# Unable to reach live NumPy docs", | |
| "", | |
| "This extension was not able to connect to `https://numpy.org/doc/stable/`.", | |
| "", | |
| "If you can access the internet outside of Raycast, you can download the generated NumPy docs elsewhere and point the extension at that folder.", | |
| "", | |
| "## Setup", | |
| "", | |
| "1. Download the ZIP for the generated NumPy docs from [numpy/doc](https://github.com/numpy/doc) or get it from another machine that can access `numpy.org`.", | |
| "2. Extract the ZIP locally. The extension will look for the documentation version under the `stable` folder inside what you downloaded.", | |
| hasLocalDocsDirectory | |
| ? "3. Open this command's preferences and verify that **Local Docs Directory** points to the downloaded docs folder." | |
| : "3. Open this command's preferences and set **Local Docs Directory** to the downloaded docs folder.", | |
| "", | |
| "## Current error", | |
| "", | |
| `\`${error.message}\``, | |
| ].join("\n"); | |
| } | |
| return [ | |
| "# Unable to load local NumPy docs", | |
| "", | |
| "This extension could not load the local NumPy documentation inventory.", | |
| "", | |
| "## Check your local docs setup", | |
| "", | |
| hasLocalDocsDirectory | |
| ? "1. Open this command's preferences and verify that **Local Docs Directory** points to the correct extracted docs folder." | |
| : "1. Open this command's preferences and set **Local Docs Directory** to the extracted docs folder.", | |
| "2. Confirm the selected folder contains a `stable/objects.inv` file.", | |
| "3. Make sure Raycast can read the folder and files inside it.", |
| mkdirSync(referenceDir, { recursive: true }); | ||
| writeFileSync( | ||
| path.join(referenceDir, "numpy.linspace.html"), | ||
| readFileSync(path.join(process.cwd(), "src/__tests__/fixtures/numpy.linspace.html"), "utf8"), |
There was a problem hiding this comment.
Using process.cwd() makes the test dependent on the runner’s working directory (often the monorepo root), which can cause failures when executed from different paths/CI setups. Prefer resolving the fixture relative to the test file location (e.g., via import.meta.url / __dirname equivalent) to make the test location-independent.
| readFileSync(path.join(process.cwd(), "src/__tests__/fixtures/numpy.linspace.html"), "utf8"), | |
| readFileSync(new URL("./fixtures/numpy.linspace.html", import.meta.url), "utf8"), |
| "$schema": "https://www.raycast.com/schemas/extension.json", | ||
| "name": "numpy-documentation-search", | ||
| "title": "NumPy Documentation Search", | ||
| "title": "Numpy Documentation Search", |
There was a problem hiding this comment.
The extension/command titles changed from NumPy to Numpy. NumPy is a proper name with specific capitalization and this change will surface in the Raycast Store and command UI. Recommend reverting these strings to NumPy for correctness and consistency with the rest of the extension text (numpy.org, README, etc.).
| "title": "Numpy Docs", | ||
| "subtitle": "Search through Numpy documentation", |
There was a problem hiding this comment.
The extension/command titles changed from NumPy to Numpy. NumPy is a proper name with specific capitalization and this change will surface in the Raycast Store and command UI. Recommend reverting these strings to NumPy for correctness and consistency with the rest of the extension text (numpy.org, README, etc.).
| import { parseDocDetail, type DocDetail } from "./doc-detail"; | ||
| import { INVENTORY_URL, transformInventoryBuffer, type InventoryItem } from "./inventory"; | ||
|
|
||
| export type DocumentationSourceMode = "online" | "local"; |
There was a problem hiding this comment.
DocumentationSourceMode uses online to represent a behavior that appears to be “try remote, then fall back to local if configured” (i.e., an auto mode). Naming this mode online is likely to confuse because it still uses local docs on failure. Consider renaming the mode/value to auto (and updating the preference dropdown titles accordingly) to match the described behavior and reduce ambiguity for API consumers.
| # NumPy Documentation Search Changelog | ||
|
|
||
| ## [1.2.3] - 2025-10-09 | ||
| ## [1.3.0] - {PR_MERGE_DATE} |
There was a problem hiding this comment.
The changelog now includes {PR_MERGE_DATE} placeholders (and replaces the previously concrete date for 1.2.3). If the repository expects released versions to have real dates, these placeholders should be replaced with actual dates before merge/release so the changelog remains accurate and user-facing.
Greptile SummaryThis PR adds a local documentation fallback for the NumPy Documentation Search extension, so users on certificate-restricted networks can point the extension at downloaded local docs instead of always fetching from
Confidence Score: 4/5Safe to merge after fixing the CHANGELOG date regression on the [1.2.3] entry. One P1 issue (retroactive date overwrite in CHANGELOG) needs to be fixed before merging; all other findings are P2 style suggestions. CHANGELOG.md — the [1.2.3] entry must restore its original date (2025-10-09). Important Files Changed
Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/numpy-documentation-search/CHANGELOG.md
Line: 13
Comment:
**Previously-released entry date overwritten with placeholder**
The `[1.2.3]` entry already had a real merge date (`2025-10-09`) from a prior PR. Changing it to `{PR_MERGE_DATE}` will cause the release tooling to stamp it with this PR's merge date, permanently erasing the historical date.
```suggestion
## [1.2.3] - 2025-10-09
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/numpy-documentation-search/src/numpy-docs.tsx
Line: 11-15
Comment:
**Manually-defined `Preferences` interface should be removed**
Raycast auto-generates the `Preferences` type in `raycast-env.d.ts` from `package.json`; keeping a manual definition risks type drift when preferences change. Remove the interface and rely on the generated type instead.
```suggestion
```
**Rule Used:** What: Don't manually define `Preferences` for `get... ([source](https://app.greptile.com/review/custom-context?memory=d93fc9fb-a45d-4479-a6a4-b1b4af98ebc8))
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "Rename auto mode to online" | Re-trigger Greptile |
| - Fall back to local documentation when remote inventory loading fails | ||
| - Load inline documentation previews from a configured local docs directory when network access is unavailable | ||
|
|
||
| ## [1.2.3] - {PR_MERGE_DATE} |
There was a problem hiding this comment.
Previously-released entry date overwritten with placeholder
The [1.2.3] entry already had a real merge date (2025-10-09) from a prior PR. Changing it to {PR_MERGE_DATE} will cause the release tooling to stamp it with this PR's merge date, permanently erasing the historical date.
| ## [1.2.3] - {PR_MERGE_DATE} | |
| ## [1.2.3] - 2025-10-09 |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/numpy-documentation-search/CHANGELOG.md
Line: 13
Comment:
**Previously-released entry date overwritten with placeholder**
The `[1.2.3]` entry already had a real merge date (`2025-10-09`) from a prior PR. Changing it to `{PR_MERGE_DATE}` will cause the release tooling to stamp it with this PR's merge date, permanently erasing the historical date.
```suggestion
## [1.2.3] - 2025-10-09
```
How can I resolve this? If you propose a fix, please make it concise.
0xdhrv
left a comment
There was a problem hiding this comment.
Looks good to me, approved ✅
|
Published to the Raycast Store: |
|
🎉 🎉 🎉 We've rewarded your Raycast account with some credits. You will soon be able to exchange them for some swag. |
Description
Implemented a local documentation fallback flow for the Raycast extension so it no longer depends exclusively on live access to numpy.org. The command now supports two source modes, Auto and Local Docs Directory: it tries the online NumPy docs first, and if that fails and a local docs folder is configured, it falls back to the downloaded docs under that folder’s stable/ subdirectory for both inventory loading and inline detail previews. The UI was updated to replace raw connection failures with guided recovery instructions that tell users how to download, extract, and configure local docs, and the extension metadata, README, changelog, and automated tests were updated to reflect and verify the new behavior.
Screencast
Checklist
npm run buildand tested this distribution build in Raycastassetsfolder are used by the extension itselfREADMEare placed outside of themetadatafolder