feat(cli): add introspect command for index facets and searchable attributes#7053
Open
sarahdayan wants to merge 23 commits into
Open
feat(cli): add introspect command for index facets and searchable attributes#7053sarahdayan wants to merge 23 commits into
sarahdayan wants to merge 23 commits into
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 33 |
TIP This summary will be updated as you push new changes.
More templates
algoliasearch-helper
instantsearch-ui-components
instantsearch.css
instantsearch.js
react-instantsearch
react-instantsearch-core
react-instantsearch-nextjs
react-instantsearch-router-nextjs
vue-instantsearch
commit: |
e2a0541 to
3f16a31
Compare
8166a20 to
75012f1
Compare
4efb18f to
537bbf3
Compare
bc4bf6b to
8d12e9e
Compare
537bbf3 to
e7a58e4
Compare
a67dcb2 to
509132f
Compare
e7a58e4 to
b13bfc9
Compare
b91ba3c to
7f5947f
Compare
185fed5 to
c6815e1
Compare
7f5947f to
8744f05
Compare
c6815e1 to
ba9898f
Compare
8744f05 to
2177c8f
Compare
ba9898f to
6c69153
Compare
2177c8f to
f3515b6
Compare
…ntsearch.json Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Manifest.framework is now optional. validateManifest no longer requires it; if present, it must be a non-empty string. Matches the detector's new contract where framework is set only when special handling is needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Premature versioning. The package is in alpha — no v2 in sight, no migration story to build for. When the manifest shape needs to change breakingly, we can introduce apiVersion (or another versioning signal) at the same time as the migrator. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6c69153 to
1d717ad
Compare
f3515b6 to
fc6525a
Compare
…quire non-empty credentials Two issues flagged by review: - writeManifest used to throw on any error other than EEXIST. Common cases (missing parent dir, permission denied, no space) crashed the CLI and bypassed --json. Now returns a write_failed refusal envelope. - checkAlgolia previously accepted empty-string appId / searchApiKey, which would fail at the first Algolia call. Now rejects empty strings the same way as other required fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1d717ad to
869f24b
Compare
fc6525a to
27b53ce
Compare
a12395d to
83299d5
Compare
The provider is meant to be index-agnostic; each feature wraps itself in <Index indexName="..."> for the specific index it targets. Setting indexName on the top-level <InstantSearch> contradicted that model. The previous YOUR_INDEX_NAME placeholder was a fix to a symptom (Copilot flagged the empty string); the root cause was the prop having no business being there. nextSteps now points the user toward <Index> instead of "set the indexName in the provider". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83299d5 to
ce830f5
Compare
21 tasks
- manifest_exists check now runs before detect(), so re-running init on a project where the detector would now refuse still gets the more actionable manifest_exists message instead of a detector failure. - defaultInstaller no longer uses stdio: 'inherit' (which writes child output directly to stdout and corrupts the JSON envelope). Both child stdout and stderr now pipe to process.stderr. - Generated algolia-client and algolia-provider files are now written with flag: 'wx', so init refuses with write_failed instead of silently overwriting an existing file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ce830f5 to
d430241
Compare
When scaffolding fails after the manifest is written (mkdir fails, client or provider write fails on EEXIST, etc.), init now undoes the files this run created so the user can retry without hitting manifest_exists on the next attempt. The rollback tracks only files this run successfully wrote — a pre-existing user file that caused the EEXIST never gets touched. Rollback is best-effort: any IO error during cleanup is swallowed so the original write_failed envelope stays the headline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
d430241 to
4c851f3
Compare
…cancel
Three fixes from the latest review pass:
- libPath is now validated to be a non-absolute, non-traversing
relative path before any filesystem writes. An absolute libPath
(e.g. /tmp/x) used to silently scaffold files outside the project
and emit an invalid import specifier in nextSteps. Refuses with the
new invalid_lib_path code.
- defaultInstaller now passes shell: process.platform === 'win32' so
the .cmd shims for npm/yarn/pnpm/bun resolve via PATHEXT on Windows.
Without it, spawn('npm', …) throws ENOENT on every Windows host,
blocking install entirely.
- The interactive cancellation check now also treats empty-string
prompt submissions as cancellation (matching the Ctrl-C path).
Previously a user who pressed Enter without typing at the Algolia
credential prompts got a misleading missing_required_flag error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4c851f3 to
2ade96e
Compare
… managers Codacy flagged shell:true as a generic shell-injection risk. Our args are controlled, but the cleaner fix removes the false positive: append the .cmd suffix explicitly on Windows for npm/yarn/pnpm (which install as .cmd shims), keep bun bare (bun.exe is a real executable). spawn now defaults to shell:false on every platform. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2ade96e to
d30a179
Compare
Two Copilot findings: - componentsPath was not validated against absolute or '..' paths, even though the PR description says both componentsPath and libPath must be relative paths inside the project. Now refuses with the new invalid_components_path code, mirroring the libPath check. - prompts was installed with a caret range while other deps in this package pin exact versions. Switched to "2.4.2" for consistency, so transitive upgrades don't land unreviewed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
d30a179 to
c572604
Compare
…lar import program.ts imported HandledFailure from run.ts; run.ts imported createProgram from program.ts. The cycle worked only because the HandledFailure usage was inside an async action callback, not at module load time. Copilot flagged it as fragile across bundlers and future refactors. Extracted HandledFailure into src/handled-failure.ts. Both run.ts and program.ts now import from there. Dependencies flow one way. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rchable attributes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same fix as the init action: throw HandledFailure when runIntrospect returns non-zero so the process exit code matches the envelope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…in introspect 401/403 from Algolia now surface as the dedicated credentials_invalid code with a message pointing at --app-id / --search-api-key. Other non-404 errors (incl. 5xx, transport failures) keep falling under algolia_error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
c572604 to
aff3e3d
Compare
The CLI's introspect command imports algoliasearch v5's named export and uses searchSingleIndex from the v5 API surface. When the legacy v4 CI job downgrades algoliasearch across the repo, the CLI's tests and typecheck fail because v4 ships a different module shape. Following the existing precedent of algolia-experiences (already excluded from both the v4 jest run and the v4 typecheck), exclude the instantsearch-cli package the same way. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new instantsearch introspect CLI subcommand that queries an Algolia index and reports discovered facet names and “searchable attributes” (inferred from _highlightResult keys). This extends the CLI beyond scaffolding by enabling automated planning before future add scaffolding steps.
Changes:
- Introduces the
introspectcommand wired into the CLI program and command registry. - Implements
runIntrospectwith manifest/flag credential resolution, Algolia querying, error classification, and human/JSON outputs. - Extends the success envelope with an optional
datapayload and adds Jest coverage (including HTTP mocking vianock).
Reviewed changes
Copilot reviewed 9 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Adds lock entries for new test dependency (nock) and its transitive deps. |
| tsconfig.v4.json | Excludes packages/instantsearch-cli from TS v4 config scope. |
| packages/instantsearch-cli/src/program.ts | Registers the new introspect subcommand and adds it to known commands. |
| packages/instantsearch-cli/src/introspect.ts | Implements introspection logic, credential resolution, Algolia query, and output formatting. |
| packages/instantsearch-cli/src/envelope.ts | Adds optional data field to success envelopes for structured outputs. |
| packages/instantsearch-cli/package.json | Adds algoliasearch runtime dependency, nock dev dependency, and a build script. |
| packages/instantsearch-cli/tests/json-envelope.test.ts | Narrows generic JSON-envelope test to add only. |
| packages/instantsearch-cli/tests/introspect.test.ts | Adds comprehensive tests for introspect outputs, errors, and credential precedence. |
| packages/instantsearch-cli/tests/human-output.test.ts | Narrows generic human-output test to add only. |
| packages/instantsearch-cli/tests/utils/helpers.ts | Adds helpers for capturing IO and parsing JSON envelopes. |
| jest.config.js | Conditionally includes instantsearch-cli tests when algoliasearch major is v5. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ospect Previously, --app-id without --search-api-key (or vice versa) silently fell back to the manifest's credentials — the user's partial intent got overridden. Now: if either credential flag is set, the other is required; the manifest is consulted only when neither is set. This matches what a user passing one flag would reasonably expect. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Haroenv
approved these changes
Jun 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the
instantsearch introspectsubcommand. Given an index name and credentials, it prints the index's facets and searchable attributes. The intent is to let an agent (or a developer) plan what to scaffold before callingadd. Builds on #7052.Examples
Credentials passed explicitly:
Credentials read from the manifest written by
init:How it works
Calls
searchSingleIndexfromalgoliasearchwithfacets: ['*']andattributesToHighlight: ['*']. Then:facetskeys of the response_highlightResultkeys across the returned hitsWhen both
--app-id/--search-api-keyflags and a manifest are present, the flags win.Failure codes
missing_required_flag—--indexmissing, or no credentials available (no manifest + no flags)index_not_found— Algolia returned 404 for the index namecredentials_invalid— Algolia returned 401/403 (app ID or search API key rejected)algolia_error— any other Algolia/transport failureinvalid_manifest— the manifest exists but is malformedEnvelope change
The success envelope grows an optional
datafield, used here to carry{ facets, searchableAttributes }without overloadingfilesCreated/nextSteps. Other commands keep working as before.Why no replicas
Listing replicas requires settings-read permission, which the search-only API key doesn't grant. Leaving them out for now.
Checklist
--index <name> --app-id X --search-api-key Y --jsonreturns facets and searchable attributes--index <name> --json(no credential flags) reads credentials from the manifestmissing_required_flag--index→missing_required_flagindex_not_foundcredentials_invalidalgolia_errorinvalid_manifestDeferred from the amendment
After review, three amendment items were intentionally not implemented:
algolia_error→network_errorrename: not done. The original name is more honest as a catch-all —network_errorreads as transport failure, but the catch also covers 5xx and other API errors. Renaming would lose information. A future split (network_errorvsapi_error) is cleaner than a flat rename.index_emptyrefusal: not done. An empty index is a state, not an error — the success envelope already represents it via emptysearchableAttributesarray. Forcing a refusal blocks consumers from acting on the (legitimately sparse) data.index_has_no_facetsrefusal: same shape as above. The emptyfacets: []is the honest representation; consumers can decide whether to surface it as guidance.