Skip to content

feat(cli): add introspect command for index facets and searchable attributes#7053

Open
sarahdayan wants to merge 23 commits into
masterfrom
feat/introspect
Open

feat(cli): add introspect command for index facets and searchable attributes#7053
sarahdayan wants to merge 23 commits into
masterfrom
feat/introspect

Conversation

@sarahdayan

@sarahdayan sarahdayan commented May 22, 2026

Copy link
Copy Markdown
Member

Summary

Adds the instantsearch introspect subcommand. 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 calling add. Builds on #7052.

Examples

Credentials passed explicitly:

instantsearch introspect --index products --app-id XYZ --search-api-key abc --json

Credentials read from the manifest written by init:

instantsearch introspect --index products --json

How it works

Calls searchSingleIndex from algoliasearch with facets: ['*'] and attributesToHighlight: ['*']. Then:

  • Facets are the top-level facets keys of the response
  • Searchable attributes are the union of _highlightResult keys across the returned hits

When both --app-id/--search-api-key flags and a manifest are present, the flags win.

Failure codes

  • missing_required_flag--index missing, or no credentials available (no manifest + no flags)
  • index_not_found — Algolia returned 404 for the index name
  • credentials_invalid — Algolia returned 401/403 (app ID or search API key rejected)
  • algolia_error — any other Algolia/transport failure
  • invalid_manifest — the manifest exists but is malformed

Envelope change

The success envelope grows an optional data field, used here to carry { facets, searchableAttributes } without overloading filesCreated / 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 --json returns facets and searchable attributes
  • --index <name> --json (no credential flags) reads credentials from the manifest
  • Flag credentials take precedence over the manifest when both are present
  • No manifest and no flags → missing_required_flag
  • Missing --indexmissing_required_flag
  • Invalid index name → index_not_found
  • Algolia returns 401/403 → credentials_invalid
  • Network or other API errors → algolia_error
  • Malformed manifest → invalid_manifest

Deferred from the amendment

After review, three amendment items were intentionally not implemented:

  • algolia_errornetwork_error rename: not done. The original name is more honest as a catch-all — network_error reads as transport failure, but the catch also covers 5xx and other API errors. Renaming would lose information. A future split (network_error vs api_error) is cleaner than a flat rename.
  • index_empty refusal: not done. An empty index is a state, not an error — the success envelope already represents it via empty searchableAttributes array. Forcing a refusal blocks consumers from acting on the (legitimately sparse) data.
  • index_has_no_facets refusal: same shape as above. The empty facets: [] is the honest representation; consumers can decide whether to surface it as guidance.

@codacy-production

codacy-production Bot commented May 22, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 33 complexity

Metric Results
Complexity 33

View in Codacy

TIP This summary will be updated as you push new changes.

@pkg-pr-new

pkg-pr-new Bot commented May 22, 2026

Copy link
Copy Markdown
More templates

algoliasearch-helper

npm i https://pkg.pr.new/algolia/instantsearch/algoliasearch-helper@7053

instantsearch-ui-components

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch-ui-components@7053

instantsearch.css

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch.css@7053

instantsearch.js

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch.js@7053

react-instantsearch

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch@7053

react-instantsearch-core

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-core@7053

react-instantsearch-nextjs

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-nextjs@7053

react-instantsearch-router-nextjs

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-router-nextjs@7053

vue-instantsearch

npm i https://pkg.pr.new/algolia/instantsearch/vue-instantsearch@7053

commit: 708510b

@sarahdayan sarahdayan force-pushed the feat/init-command branch from e2a0541 to 3f16a31 Compare May 26, 2026 12:30
@sarahdayan sarahdayan force-pushed the feat/introspect branch 3 times, most recently from 8166a20 to 75012f1 Compare May 26, 2026 13:18
@sarahdayan sarahdayan force-pushed the feat/init-command branch 2 times, most recently from 4efb18f to 537bbf3 Compare May 26, 2026 13:29
@sarahdayan sarahdayan force-pushed the feat/init-command branch from 537bbf3 to e7a58e4 Compare May 26, 2026 13:49
@sarahdayan sarahdayan force-pushed the feat/init-command branch from e7a58e4 to b13bfc9 Compare May 26, 2026 13:55
@sarahdayan sarahdayan force-pushed the feat/introspect branch 2 times, most recently from b91ba3c to 7f5947f Compare May 26, 2026 14:07
@sarahdayan sarahdayan force-pushed the feat/init-command branch from 185fed5 to c6815e1 Compare May 26, 2026 14:18
@sarahdayan sarahdayan force-pushed the feat/init-command branch from c6815e1 to ba9898f Compare May 26, 2026 14:41
@sarahdayan sarahdayan force-pushed the feat/init-command branch from ba9898f to 6c69153 Compare May 26, 2026 14:51
sarahdayan and others added 5 commits May 28, 2026 13:07
…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>
…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>
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>
- 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>
sarahdayan and others added 2 commits June 1, 2026 09:51
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>
…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>
… 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>
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>
sarahdayan and others added 6 commits June 1, 2026 10:55
…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>
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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 introspect command wired into the CLI program and command registry.
  • Implements runIntrospect with manifest/flag credential resolution, Algolia querying, error classification, and human/JSON outputs.
  • Extends the success envelope with an optional data payload and adds Jest coverage (including HTTP mocking via nock).

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.

Comment thread packages/instantsearch-cli/src/introspect.ts
…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>
@sarahdayan sarahdayan requested a review from Haroenv June 1, 2026 09:28
Base automatically changed from feat/init-command to master June 2, 2026 11:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants