@backstage/cli-module-search 0.2.0-next.0 → 0.2.1-next.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @backstage/cli-module-search
2
2
 
3
+ ## 0.2.1-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/cli-node@0.3.6-next.0
9
+
10
+ ## 0.2.0
11
+
12
+ ### Minor Changes
13
+
14
+ - 3d6721d: Add intent-based CLI modules for catalog, scaffolder, and search.
15
+
16
+ New modules provide domain-oriented subcommands that talk directly to the corresponding plugins' REST APIs:
17
+
18
+ - `@backstage/cli-module-catalog`: `catalog list`, `catalog get`, `catalog validate`, `catalog register`, `catalog unregister`
19
+ - `@backstage/cli-module-scaffolder`: `template list`, `template execute`, `template dry-run`
20
+ - `@backstage/cli-module-search`: `search`, `docs search`
21
+
22
+ The commands take their main input as a positional argument: an entity or template reference, a file path (or `-` for standard input) for `catalog validate` and `template dry-run`, a URL for `catalog register`, and the search terms for `search` and `docs search`. Repeatable `key=value` flags are used for filters, template values, and secrets, and comma-separated lists for `--fields`. Unknown flags are rejected.
23
+
24
+ The commands that list results, `catalog list`, `template list`, `search`, and `docs search`, support `--output human` (the default) or `--output json`, along with `--limit` and `--cursor` for paging. Each command prints a single page. Human output shows how many results were shown and, when more are available, prints the `--cursor` value to continue from. All other commands always print JSON. `catalog validate` checks every entity in a multi-document YAML file and prints a JSON array with one result per entity. `catalog validate` and `template dry-run` exit with a non-zero code when the input is invalid, while connection and authentication problems are reported as errors.
25
+
26
+ `@backstage/cli-node` now provides shared parsers for repeatable `key=value` inputs and comma-separated lists.
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies
31
+ - @backstage/cli-node@0.3.5
32
+ - @backstage/errors@1.3.2
33
+
3
34
  ## 0.2.0-next.0
4
35
 
5
36
  ### Minor Changes
@@ -8,73 +8,63 @@ var resolveAuth = require('../lib/resolveAuth.cjs.js');
8
8
  var intentFormat = require('../lib/intentFormat.cjs.js');
9
9
 
10
10
  var docsSearch = async ({ args, info }) => {
11
- const nonFlagArgs = [];
12
- const flagArgs = [];
13
- let skipNext = false;
14
- for (let i = 0; i < args.length; i++) {
15
- if (skipNext) {
16
- skipNext = false;
17
- continue;
18
- }
19
- if (args[i].startsWith("-")) {
20
- flagArgs.push(args[i]);
21
- if (i + 1 < args.length && !args[i + 1].startsWith("-") && !args[i].includes("=")) {
22
- flagArgs.push(args[i + 1]);
23
- skipNext = true;
24
- }
25
- } else {
26
- nonFlagArgs.push(args[i]);
27
- }
28
- }
29
- const { flags } = cleye.cli(
11
+ const parsed = cleye.cli(
30
12
  {
31
13
  name: info.usage,
14
+ strictFlags: true,
15
+ parameters: ["<term...>"],
32
16
  flags: {
33
- "page-limit": {
17
+ limit: {
34
18
  type: Number,
35
- description: "Results per page (default: 10)"
36
- },
37
- "page-cursor": {
38
- type: String,
39
- description: "Pagination cursor"
19
+ description: "Maximum number of results to return per page"
40
20
  },
41
- output: {
21
+ cursor: {
42
22
  type: String,
43
- description: "Output format: human (default), json"
23
+ description: "Continue from the cursor returned by a previous page"
44
24
  },
45
- instance: {
46
- type: String,
47
- description: "Name of the instance to use"
48
- }
25
+ ...intentFormat.outputFlag,
26
+ ...resolveAuth.instanceFlag
49
27
  }
50
28
  },
51
29
  void 0,
52
- flagArgs
30
+ args
53
31
  );
54
- const term = nonFlagArgs.join(" ");
55
- if (!term) {
56
- throw new Error("Search term is required. Usage: docs search <term>");
57
- }
32
+ const { flags } = parsed;
33
+ const term = parsed._.term.join(" ");
58
34
  const mode = intentFormat.parseOutputFlag(flags);
59
35
  const { accessToken, baseUrl } = await resolveAuth.resolveAuth(flags.instance);
60
36
  const client = new SearchClient.SearchClient(baseUrl, accessToken);
61
- const response = await client.query({
62
- term,
63
- types: ["techdocs"],
64
- pageLimit: flags["page-limit"],
65
- pageCursor: flags["page-cursor"]
66
- });
67
- const result = {
68
- results: response.results,
69
- nextPageCursor: response.nextPageCursor,
70
- totalItems: response.numberOfResults,
71
- hasMoreResults: response.nextPageCursor !== void 0
37
+ const fetchPage = async (cursor) => {
38
+ const response = await client.query({
39
+ term,
40
+ types: ["techdocs"],
41
+ pageLimit: flags.limit,
42
+ pageCursor: cursor
43
+ });
44
+ return {
45
+ results: response.results,
46
+ nextPageCursor: response.nextPageCursor,
47
+ totalItems: response.numberOfResults,
48
+ hasMoreResults: response.nextPageCursor !== void 0
49
+ };
72
50
  };
73
51
  if (mode === "json") {
74
- intentFormat.writeJson(result);
75
- } else {
76
- process.stdout.write(intentFormat.formatSearchResults(result.results));
52
+ intentFormat.writeJson(await fetchPage(flags.cursor));
53
+ return;
77
54
  }
55
+ await intentFormat.printPage(
56
+ async (cursor) => {
57
+ const page = await fetchPage(cursor);
58
+ return {
59
+ ...page,
60
+ count: page.results.length,
61
+ total: page.totalItems,
62
+ nextCursor: page.nextPageCursor
63
+ };
64
+ },
65
+ (page) => process.stdout.write(intentFormat.formatSearchResults(page.results)),
66
+ flags.cursor
67
+ );
78
68
  };
79
69
 
80
70
  exports.default = docsSearch;
@@ -1 +1 @@
1
- {"version":3,"file":"docsSearch.cjs.js","sources":["../../src/commands/docsSearch.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { SearchClient } from '../lib/SearchClient';\nimport { resolveAuth } from '../lib/resolveAuth';\nimport {\n parseOutputFlag,\n writeJson,\n formatSearchResults,\n} from '../lib/intentFormat';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const nonFlagArgs: string[] = [];\n const flagArgs: string[] = [];\n let skipNext = false;\n\n for (let i = 0; i < args.length; i++) {\n if (skipNext) {\n skipNext = false;\n continue;\n }\n if (args[i].startsWith('-')) {\n flagArgs.push(args[i]);\n if (\n i + 1 < args.length &&\n !args[i + 1].startsWith('-') &&\n !args[i].includes('=')\n ) {\n flagArgs.push(args[i + 1]);\n skipNext = true;\n }\n } else {\n nonFlagArgs.push(args[i]);\n }\n }\n\n const { flags } = cli(\n {\n name: info.usage,\n flags: {\n 'page-limit': {\n type: Number,\n description: 'Results per page (default: 10)',\n },\n 'page-cursor': {\n type: String,\n description: 'Pagination cursor',\n },\n output: {\n type: String,\n description: 'Output format: human (default), json',\n },\n instance: {\n type: String,\n description: 'Name of the instance to use',\n },\n },\n },\n undefined,\n flagArgs,\n );\n\n const term = nonFlagArgs.join(' ');\n if (!term) {\n throw new Error('Search term is required. Usage: docs search <term>');\n }\n\n const mode = parseOutputFlag(flags as Record<string, unknown>);\n const { accessToken, baseUrl } = await resolveAuth(flags.instance);\n const client = new SearchClient(baseUrl, accessToken);\n\n const response = await client.query({\n term,\n types: ['techdocs'],\n pageLimit: flags['page-limit'],\n pageCursor: flags['page-cursor'],\n });\n const result = {\n results: response.results,\n nextPageCursor: response.nextPageCursor,\n totalItems: response.numberOfResults,\n hasMoreResults: response.nextPageCursor !== undefined,\n };\n\n if (mode === 'json') {\n writeJson(result);\n } else {\n process.stdout.write(formatSearchResults(result.results));\n }\n};\n"],"names":["cli","parseOutputFlag","resolveAuth","SearchClient","writeJson","formatSearchResults"],"mappings":"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"}
1
+ {"version":3,"file":"docsSearch.cjs.js","sources":["../../src/commands/docsSearch.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport type { CliCommandContext } from '@backstage/cli-node';\nimport { SearchClient } from '../lib/SearchClient';\nimport { instanceFlag, resolveAuth } from '../lib/resolveAuth';\nimport {\n outputFlag,\n printPage,\n parseOutputFlag,\n writeJson,\n formatSearchResults,\n} from '../lib/intentFormat';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const parsed = cli(\n {\n name: info.usage,\n strictFlags: true,\n parameters: ['<term...>'],\n flags: {\n limit: {\n type: Number,\n description: 'Maximum number of results to return per page',\n },\n cursor: {\n type: String,\n description: 'Continue from the cursor returned by a previous page',\n },\n ...outputFlag,\n ...instanceFlag,\n },\n },\n undefined,\n args,\n );\n const { flags } = parsed;\n\n const term = parsed._.term.join(' ');\n const mode = parseOutputFlag(flags as Record<string, unknown>);\n\n const { accessToken, baseUrl } = await resolveAuth(flags.instance);\n const client = new SearchClient(baseUrl, accessToken);\n\n const fetchPage = async (cursor?: string) => {\n const response = await client.query({\n term,\n types: ['techdocs'],\n pageLimit: flags.limit,\n pageCursor: cursor,\n });\n return {\n results: response.results,\n nextPageCursor: response.nextPageCursor,\n totalItems: response.numberOfResults,\n hasMoreResults: response.nextPageCursor !== undefined,\n };\n };\n\n if (mode === 'json') {\n writeJson(await fetchPage(flags.cursor));\n return;\n }\n\n await printPage(\n async cursor => {\n const page = await fetchPage(cursor);\n return {\n ...page,\n count: page.results.length,\n total: page.totalItems,\n nextCursor: page.nextPageCursor,\n };\n },\n page => process.stdout.write(formatSearchResults(page.results)),\n flags.cursor,\n );\n};\n"],"names":["cli","outputFlag","instanceFlag","parseOutputFlag","resolveAuth","SearchClient","writeJson","printPage","formatSearchResults"],"mappings":";;;;;;;;;AA4BA,iBAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM,MAAA,GAASA,SAAA;AAAA,IACb;AAAA,MACE,MAAM,IAAA,CAAK,KAAA;AAAA,MACX,WAAA,EAAa,IAAA;AAAA,MACb,UAAA,EAAY,CAAC,WAAW,CAAA;AAAA,MACxB,KAAA,EAAO;AAAA,QACL,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA,SACf;AAAA,QACA,MAAA,EAAQ;AAAA,UACN,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA,SACf;AAAA,QACA,GAAGC,uBAAA;AAAA,QACH,GAAGC;AAAA;AACL,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,EAAE,OAAM,GAAI,MAAA;AAElB,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,CAAA,CAAE,IAAA,CAAK,KAAK,GAAG,CAAA;AACnC,EAAA,MAAM,IAAA,GAAOC,6BAAgB,KAAgC,CAAA;AAE7D,EAAA,MAAM,EAAE,WAAA,EAAa,OAAA,KAAY,MAAMC,uBAAA,CAAY,MAAM,QAAQ,CAAA;AACjE,EAAA,MAAM,MAAA,GAAS,IAAIC,yBAAA,CAAa,OAAA,EAAS,WAAW,CAAA;AAEpD,EAAA,MAAM,SAAA,GAAY,OAAO,MAAA,KAAoB;AAC3C,IAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,KAAA,CAAM;AAAA,MAClC,IAAA;AAAA,MACA,KAAA,EAAO,CAAC,UAAU,CAAA;AAAA,MAClB,WAAW,KAAA,CAAM,KAAA;AAAA,MACjB,UAAA,EAAY;AAAA,KACb,CAAA;AACD,IAAA,OAAO;AAAA,MACL,SAAS,QAAA,CAAS,OAAA;AAAA,MAClB,gBAAgB,QAAA,CAAS,cAAA;AAAA,MACzB,YAAY,QAAA,CAAS,eAAA;AAAA,MACrB,cAAA,EAAgB,SAAS,cAAA,KAAmB;AAAA,KAC9C;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAAC,sBAAA,CAAU,MAAM,SAAA,CAAU,KAAA,CAAM,MAAM,CAAC,CAAA;AACvC,IAAA;AAAA,EACF;AAEA,EAAA,MAAMC,sBAAA;AAAA,IACJ,OAAM,MAAA,KAAU;AACd,MAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,MAAM,CAAA;AACnC,MAAA,OAAO;AAAA,QACL,GAAG,IAAA;AAAA,QACH,KAAA,EAAO,KAAK,OAAA,CAAQ,MAAA;AAAA,QACpB,OAAO,IAAA,CAAK,UAAA;AAAA,QACZ,YAAY,IAAA,CAAK;AAAA,OACnB;AAAA,IACF,CAAA;AAAA,IACA,UAAQ,OAAA,CAAQ,MAAA,CAAO,MAAMC,gCAAA,CAAoB,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA,IAC9D,KAAA,CAAM;AAAA,GACR;AACF,CAAA;;"}
@@ -9,86 +9,76 @@ var resolveAuth = require('../lib/resolveAuth.cjs.js');
9
9
  var intentFormat = require('../lib/intentFormat.cjs.js');
10
10
 
11
11
  var search = async ({ args, info }) => {
12
- const nonFlagArgs = [];
13
- let skipNext = false;
14
- for (let i = 0; i < args.length; i++) {
15
- if (skipNext) {
16
- skipNext = false;
17
- continue;
18
- }
19
- if (args[i].startsWith("-")) {
20
- if (i + 1 < args.length && !args[i + 1].startsWith("-") && !args[i].includes("=")) {
21
- skipNext = true;
22
- }
23
- } else {
24
- nonFlagArgs.push(args[i]);
25
- }
26
- }
27
12
  const parsed = cleye.cli(
28
13
  {
29
14
  name: info.usage,
30
15
  strictFlags: true,
31
16
  parameters: ["<term...>"],
32
17
  flags: {
33
- types: {
34
- type: String,
35
- description: "Comma-separated document types"
18
+ type: {
19
+ type: [String],
20
+ description: "Only search documents of this type, for example techdocs (repeatable)",
21
+ default: []
36
22
  },
37
23
  filter: {
38
24
  type: [String],
39
- description: "Query filter as repeatable key=value input",
25
+ description: "Filter results by a field, as key=value (repeatable)",
40
26
  default: []
41
27
  },
42
- "page-limit": {
28
+ limit: {
43
29
  type: Number,
44
- description: "Results per page (default: 10)"
30
+ description: "Maximum number of results to return per page"
45
31
  },
46
- "page-cursor": {
32
+ cursor: {
47
33
  type: String,
48
- description: "Pagination cursor"
34
+ description: "Continue from the cursor returned by a previous page"
49
35
  },
50
- output: {
51
- type: String,
52
- description: "Output format: human (default), json"
53
- },
54
- instance: {
55
- type: String,
56
- description: "Name of the instance to use"
57
- }
36
+ ...intentFormat.outputFlag,
37
+ ...resolveAuth.instanceFlag
58
38
  }
59
39
  },
60
40
  void 0,
61
41
  args
62
42
  );
63
43
  const { flags } = parsed;
64
- const termParts = parsed._?.term ?? nonFlagArgs;
65
- const term = termParts.join(" ");
66
- if (!term) {
67
- throw new Error(
68
- "Search term is required. Usage: search <term> [--types techdocs]"
69
- );
70
- }
44
+ const term = parsed._.term.join(" ");
71
45
  const mode = intentFormat.parseOutputFlag(flags);
46
+ const types = flags.type.length > 0 ? flags.type : void 0;
47
+ const filters = cliNode.parseKeyValuePairs(flags.filter);
72
48
  const { accessToken, baseUrl } = await resolveAuth.resolveAuth(flags.instance);
73
49
  const client = new SearchClient.SearchClient(baseUrl, accessToken);
74
- const response = await client.query({
75
- term,
76
- types: cliNode.parseCommaSeparatedList(flags.types),
77
- filters: cliNode.parseKeyValuePairs(flags.filter),
78
- pageLimit: flags["page-limit"],
79
- pageCursor: flags["page-cursor"]
80
- });
81
- const result = {
82
- results: response.results,
83
- nextPageCursor: response.nextPageCursor,
84
- totalItems: response.numberOfResults,
85
- hasMoreResults: response.nextPageCursor !== void 0
50
+ const fetchPage = async (cursor) => {
51
+ const response = await client.query({
52
+ term,
53
+ types,
54
+ filters,
55
+ pageLimit: flags.limit,
56
+ pageCursor: cursor
57
+ });
58
+ return {
59
+ results: response.results,
60
+ nextPageCursor: response.nextPageCursor,
61
+ totalItems: response.numberOfResults,
62
+ hasMoreResults: response.nextPageCursor !== void 0
63
+ };
86
64
  };
87
65
  if (mode === "json") {
88
- intentFormat.writeJson(result);
89
- } else {
90
- process.stdout.write(intentFormat.formatSearchResults(result.results));
66
+ intentFormat.writeJson(await fetchPage(flags.cursor));
67
+ return;
91
68
  }
69
+ await intentFormat.printPage(
70
+ async (cursor) => {
71
+ const page = await fetchPage(cursor);
72
+ return {
73
+ ...page,
74
+ count: page.results.length,
75
+ total: page.totalItems,
76
+ nextCursor: page.nextPageCursor
77
+ };
78
+ },
79
+ (page) => process.stdout.write(intentFormat.formatSearchResults(page.results)),
80
+ flags.cursor
81
+ );
92
82
  };
93
83
 
94
84
  exports.default = search;
@@ -1 +1 @@
1
- {"version":3,"file":"search.cjs.js","sources":["../../src/commands/search.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport {\n parseCommaSeparatedList,\n parseKeyValuePairs,\n type CliCommandContext,\n} from '@backstage/cli-node';\nimport { SearchClient } from '../lib/SearchClient';\nimport { resolveAuth } from '../lib/resolveAuth';\nimport {\n parseOutputFlag,\n writeJson,\n formatSearchResults,\n} from '../lib/intentFormat';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const nonFlagArgs: string[] = [];\n let skipNext = false;\n\n for (let i = 0; i < args.length; i++) {\n if (skipNext) {\n skipNext = false;\n continue;\n }\n if (args[i].startsWith('-')) {\n if (\n i + 1 < args.length &&\n !args[i + 1].startsWith('-') &&\n !args[i].includes('=')\n ) {\n skipNext = true;\n }\n } else {\n nonFlagArgs.push(args[i]);\n }\n }\n\n const parsed = cli(\n {\n name: info.usage,\n strictFlags: true,\n parameters: ['<term...>'],\n flags: {\n types: {\n type: String,\n description: 'Comma-separated document types',\n },\n filter: {\n type: [String] as const,\n description: 'Query filter as repeatable key=value input',\n default: [] as string[],\n },\n 'page-limit': {\n type: Number,\n description: 'Results per page (default: 10)',\n },\n 'page-cursor': {\n type: String,\n description: 'Pagination cursor',\n },\n output: {\n type: String,\n description: 'Output format: human (default), json',\n },\n instance: {\n type: String,\n description: 'Name of the instance to use',\n },\n },\n },\n undefined,\n args,\n );\n const { flags } = parsed;\n\n const termParts = parsed._?.term ?? nonFlagArgs;\n const term = termParts.join(' ');\n if (!term) {\n throw new Error(\n 'Search term is required. Usage: search <term> [--types techdocs]',\n );\n }\n\n const mode = parseOutputFlag(flags as Record<string, unknown>);\n const { accessToken, baseUrl } = await resolveAuth(flags.instance);\n const client = new SearchClient(baseUrl, accessToken);\n\n const response = await client.query({\n term,\n types: parseCommaSeparatedList(flags.types),\n filters: parseKeyValuePairs(flags.filter),\n pageLimit: flags['page-limit'],\n pageCursor: flags['page-cursor'],\n });\n const result = {\n results: response.results,\n nextPageCursor: response.nextPageCursor,\n totalItems: response.numberOfResults,\n hasMoreResults: response.nextPageCursor !== undefined,\n };\n\n if (mode === 'json') {\n writeJson(result);\n } else {\n process.stdout.write(formatSearchResults(result.results));\n }\n};\n"],"names":["cli","parseOutputFlag","resolveAuth","SearchClient","parseCommaSeparatedList","parseKeyValuePairs","writeJson","formatSearchResults"],"mappings":"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"}
1
+ {"version":3,"file":"search.cjs.js","sources":["../../src/commands/search.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cli } from 'cleye';\nimport {\n parseKeyValuePairs,\n type CliCommandContext,\n} from '@backstage/cli-node';\nimport { SearchClient } from '../lib/SearchClient';\nimport { instanceFlag, resolveAuth } from '../lib/resolveAuth';\nimport {\n outputFlag,\n printPage,\n parseOutputFlag,\n writeJson,\n formatSearchResults,\n} from '../lib/intentFormat';\n\nexport default async ({ args, info }: CliCommandContext) => {\n const parsed = cli(\n {\n name: info.usage,\n strictFlags: true,\n parameters: ['<term...>'],\n flags: {\n type: {\n type: [String] as const,\n description:\n 'Only search documents of this type, for example techdocs (repeatable)',\n default: [] as string[],\n },\n filter: {\n type: [String] as const,\n description: 'Filter results by a field, as key=value (repeatable)',\n default: [] as string[],\n },\n limit: {\n type: Number,\n description: 'Maximum number of results to return per page',\n },\n cursor: {\n type: String,\n description: 'Continue from the cursor returned by a previous page',\n },\n ...outputFlag,\n ...instanceFlag,\n },\n },\n undefined,\n args,\n );\n const { flags } = parsed;\n\n const term = parsed._.term.join(' ');\n const mode = parseOutputFlag(flags as Record<string, unknown>);\n const types = flags.type.length > 0 ? flags.type : undefined;\n const filters = parseKeyValuePairs(flags.filter);\n\n const { accessToken, baseUrl } = await resolveAuth(flags.instance);\n const client = new SearchClient(baseUrl, accessToken);\n\n const fetchPage = async (cursor?: string) => {\n const response = await client.query({\n term,\n types,\n filters,\n pageLimit: flags.limit,\n pageCursor: cursor,\n });\n return {\n results: response.results,\n nextPageCursor: response.nextPageCursor,\n totalItems: response.numberOfResults,\n hasMoreResults: response.nextPageCursor !== undefined,\n };\n };\n\n if (mode === 'json') {\n writeJson(await fetchPage(flags.cursor));\n return;\n }\n\n await printPage(\n async cursor => {\n const page = await fetchPage(cursor);\n return {\n ...page,\n count: page.results.length,\n total: page.totalItems,\n nextCursor: page.nextPageCursor,\n };\n },\n page => process.stdout.write(formatSearchResults(page.results)),\n flags.cursor,\n );\n};\n"],"names":["cli","outputFlag","instanceFlag","parseOutputFlag","parseKeyValuePairs","resolveAuth","SearchClient","writeJson","printPage","formatSearchResults"],"mappings":";;;;;;;;;;AA+BA,aAAe,OAAO,EAAE,IAAA,EAAM,IAAA,EAAK,KAAyB;AAC1D,EAAA,MAAM,MAAA,GAASA,SAAA;AAAA,IACb;AAAA,MACE,MAAM,IAAA,CAAK,KAAA;AAAA,MACX,WAAA,EAAa,IAAA;AAAA,MACb,UAAA,EAAY,CAAC,WAAW,CAAA;AAAA,MACxB,KAAA,EAAO;AAAA,QACL,IAAA,EAAM;AAAA,UACJ,IAAA,EAAM,CAAC,MAAM,CAAA;AAAA,UACb,WAAA,EACE,uEAAA;AAAA,UACF,SAAS;AAAC,SACZ;AAAA,QACA,MAAA,EAAQ;AAAA,UACN,IAAA,EAAM,CAAC,MAAM,CAAA;AAAA,UACb,WAAA,EAAa,sDAAA;AAAA,UACb,SAAS;AAAC,SACZ;AAAA,QACA,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA,SACf;AAAA,QACA,MAAA,EAAQ;AAAA,UACN,IAAA,EAAM,MAAA;AAAA,UACN,WAAA,EAAa;AAAA,SACf;AAAA,QACA,GAAGC,uBAAA;AAAA,QACH,GAAGC;AAAA;AACL,KACF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,EAAE,OAAM,GAAI,MAAA;AAElB,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,CAAA,CAAE,IAAA,CAAK,KAAK,GAAG,CAAA;AACnC,EAAA,MAAM,IAAA,GAAOC,6BAAgB,KAAgC,CAAA;AAC7D,EAAA,MAAM,QAAQ,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,MAAM,IAAA,GAAO,MAAA;AACnD,EAAA,MAAM,OAAA,GAAUC,0BAAA,CAAmB,KAAA,CAAM,MAAM,CAAA;AAE/C,EAAA,MAAM,EAAE,WAAA,EAAa,OAAA,KAAY,MAAMC,uBAAA,CAAY,MAAM,QAAQ,CAAA;AACjE,EAAA,MAAM,MAAA,GAAS,IAAIC,yBAAA,CAAa,OAAA,EAAS,WAAW,CAAA;AAEpD,EAAA,MAAM,SAAA,GAAY,OAAO,MAAA,KAAoB;AAC3C,IAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,KAAA,CAAM;AAAA,MAClC,IAAA;AAAA,MACA,KAAA;AAAA,MACA,OAAA;AAAA,MACA,WAAW,KAAA,CAAM,KAAA;AAAA,MACjB,UAAA,EAAY;AAAA,KACb,CAAA;AACD,IAAA,OAAO;AAAA,MACL,SAAS,QAAA,CAAS,OAAA;AAAA,MAClB,gBAAgB,QAAA,CAAS,cAAA;AAAA,MACzB,YAAY,QAAA,CAAS,eAAA;AAAA,MACrB,cAAA,EAAgB,SAAS,cAAA,KAAmB;AAAA,KAC9C;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAAC,sBAAA,CAAU,MAAM,SAAA,CAAU,KAAA,CAAM,MAAM,CAAC,CAAA;AACvC,IAAA;AAAA,EACF;AAEA,EAAA,MAAMC,sBAAA;AAAA,IACJ,OAAM,MAAA,KAAU;AACd,MAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,MAAM,CAAA;AACnC,MAAA,OAAO;AAAA,QACL,GAAG,IAAA;AAAA,QACH,KAAA,EAAO,KAAK,OAAA,CAAQ,MAAA;AAAA,QACpB,OAAO,IAAA,CAAK,UAAA;AAAA,QACZ,YAAY,IAAA,CAAK;AAAA,OACnB;AAAA,IACF,CAAA;AAAA,IACA,UAAQ,OAAA,CAAQ,MAAA,CAAO,MAAMC,gCAAA,CAAoB,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA,IAC9D,KAAA,CAAM;AAAA,GACR;AACF,CAAA;;"}
@@ -6,8 +6,36 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
6
6
 
7
7
  var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
8
8
 
9
+ const outputFlag = {
10
+ output: {
11
+ type: String,
12
+ description: 'Output format: "human" (default) or "json"'
13
+ }
14
+ };
9
15
  function parseOutputFlag(flags) {
10
- return flags.output === "json" ? "json" : "human";
16
+ const output = flags.output;
17
+ if (output === void 0 || output === "human") return "human";
18
+ if (output === "json") return "json";
19
+ throw new Error(
20
+ `Invalid --output value "${String(output)}", expected "human" or "json"`
21
+ );
22
+ }
23
+ async function printPage(fetchPage, render, cursor) {
24
+ const page = await fetchPage(cursor);
25
+ render(page);
26
+ if (page.count > 0) {
27
+ const total = page.total === void 0 ? "" : ` of ${page.total}`;
28
+ process.stdout.write(`${chalk__default.default.dim(`Showing ${page.count}${total}`)}
29
+ `);
30
+ }
31
+ if (page.nextCursor) {
32
+ process.stdout.write(
33
+ `${chalk__default.default.dim(
34
+ `More results available, use --cursor ${page.nextCursor} to show them`
35
+ )}
36
+ `
37
+ );
38
+ }
11
39
  }
12
40
  function writeJson(data) {
13
41
  process.stdout.write(`${JSON.stringify(data, null, 2)}
@@ -34,6 +62,8 @@ function formatSearchResults(results) {
34
62
  }
35
63
 
36
64
  exports.formatSearchResults = formatSearchResults;
65
+ exports.outputFlag = outputFlag;
37
66
  exports.parseOutputFlag = parseOutputFlag;
67
+ exports.printPage = printPage;
38
68
  exports.writeJson = writeJson;
39
69
  //# sourceMappingURL=intentFormat.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"intentFormat.cjs.js","sources":["../../src/lib/intentFormat.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport chalk from 'chalk';\n\nexport type OutputMode = 'human' | 'json';\n\nexport function parseOutputFlag(flags: Record<string, unknown>): OutputMode {\n return flags.output === 'json' ? 'json' : 'human';\n}\n\nexport function writeJson(data: unknown): void {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`);\n}\n\nexport function formatSearchResults(\n results: Array<Record<string, unknown>>,\n): string {\n if (results.length === 0) {\n return `${chalk.yellow('No results found.')}\\n`;\n }\n\n const lines: string[] = [];\n for (const result of results) {\n const doc = result.document as Record<string, unknown> | undefined;\n const title = String(doc?.title ?? result.title ?? '');\n const location = String(doc?.location ?? result.location ?? '');\n const text = String(doc?.text ?? result.text ?? '');\n const snippet = text.length > 120 ? `${text.slice(0, 120)}...` : text;\n\n lines.push(chalk.bold(title));\n if (location) lines.push(` ${chalk.dim(location)}`);\n if (snippet) lines.push(` ${snippet}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n"],"names":["chalk"],"mappings":";;;;;;;;AAoBO,SAAS,gBAAgB,KAAA,EAA4C;AAC1E,EAAA,OAAO,KAAA,CAAM,MAAA,KAAW,MAAA,GAAS,MAAA,GAAS,OAAA;AAC5C;AAEO,SAAS,UAAU,IAAA,EAAqB;AAC7C,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,EAAG,IAAA,CAAK,UAAU,IAAA,EAAM,IAAA,EAAM,CAAC,CAAC;AAAA,CAAI,CAAA;AAC3D;AAEO,SAAS,oBACd,OAAA,EACQ;AACR,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,OAAO,CAAA,EAAGA,sBAAA,CAAM,MAAA,CAAO,mBAAmB,CAAC;AAAA,CAAA;AAAA,EAC7C;AAEA,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,MAAM,MAAM,MAAA,CAAO,QAAA;AACnB,IAAA,MAAM,QAAQ,MAAA,CAAO,GAAA,EAAK,KAAA,IAAS,MAAA,CAAO,SAAS,EAAE,CAAA;AACrD,IAAA,MAAM,WAAW,MAAA,CAAO,GAAA,EAAK,QAAA,IAAY,MAAA,CAAO,YAAY,EAAE,CAAA;AAC9D,IAAA,MAAM,OAAO,MAAA,CAAO,GAAA,EAAK,IAAA,IAAQ,MAAA,CAAO,QAAQ,EAAE,CAAA;AAClD,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,MAAA,GAAS,GAAA,GAAM,CAAA,EAAG,KAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,GAAA,CAAA,GAAQ,IAAA;AAEjE,IAAA,KAAA,CAAM,IAAA,CAAKA,sBAAA,CAAM,IAAA,CAAK,KAAK,CAAC,CAAA;AAC5B,IAAA,IAAI,QAAA,QAAgB,IAAA,CAAK,CAAA,EAAA,EAAKA,uBAAM,GAAA,CAAI,QAAQ,CAAC,CAAA,CAAE,CAAA;AACnD,IAAA,IAAI,OAAA,EAAS,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,CAAA;AACtC,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAEA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;;;;"}
1
+ {"version":3,"file":"intentFormat.cjs.js","sources":["../../src/lib/intentFormat.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport chalk from 'chalk';\n\nexport type OutputMode = 'human' | 'json';\n\n/**\n * Shared `--output` flag definition for commands that support both formats.\n */\nexport const outputFlag = {\n output: {\n type: String,\n description: 'Output format: \"human\" (default) or \"json\"',\n },\n};\n\nexport function parseOutputFlag(flags: Record<string, unknown>): OutputMode {\n const output = flags.output;\n if (output === undefined || output === 'human') return 'human';\n if (output === 'json') return 'json';\n throw new Error(\n `Invalid --output value \"${String(output)}\", expected \"human\" or \"json\"`,\n );\n}\n\n/**\n * Describes one fetched page of a paginated list.\n */\nexport type PageResult = {\n /** Number of items in this page */\n count: number;\n /** Total number of items across all pages, if known */\n total?: number;\n /** Cursor for the next page, if there is one */\n nextCursor?: string;\n};\n\n/**\n * Prints a single page of results followed by a footer with the number of\n * results shown, unless the page is empty. When more results exist, a hint with the `--cursor` value to\n * continue from is printed.\n */\nexport async function printPage<T extends PageResult>(\n fetchPage: (cursor?: string) => Promise<T>,\n render: (page: T) => void,\n cursor?: string,\n): Promise<void> {\n const page = await fetchPage(cursor);\n render(page);\n\n if (page.count > 0) {\n const total = page.total === undefined ? '' : ` of ${page.total}`;\n process.stdout.write(`${chalk.dim(`Showing ${page.count}${total}`)}\\n`);\n }\n if (page.nextCursor) {\n process.stdout.write(\n `${chalk.dim(\n `More results available, use --cursor ${page.nextCursor} to show them`,\n )}\\n`,\n );\n }\n}\n\nexport function writeJson(data: unknown): void {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`);\n}\n\nexport function formatSearchResults(\n results: Array<Record<string, unknown>>,\n): string {\n if (results.length === 0) {\n return `${chalk.yellow('No results found.')}\\n`;\n }\n\n const lines: string[] = [];\n for (const result of results) {\n const doc = result.document as Record<string, unknown> | undefined;\n const title = String(doc?.title ?? result.title ?? '');\n const location = String(doc?.location ?? result.location ?? '');\n const text = String(doc?.text ?? result.text ?? '');\n const snippet = text.length > 120 ? `${text.slice(0, 120)}...` : text;\n\n lines.push(chalk.bold(title));\n if (location) lines.push(` ${chalk.dim(location)}`);\n if (snippet) lines.push(` ${snippet}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n"],"names":["chalk"],"mappings":"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"}
@@ -2,11 +2,18 @@
2
2
 
3
3
  var cliNode = require('@backstage/cli-node');
4
4
 
5
- async function resolveAuth(instanceFlag) {
6
- const auth = await cliNode.CliAuth.create({ instanceName: instanceFlag });
5
+ async function resolveAuth(instanceFlag2) {
6
+ const auth = await cliNode.CliAuth.create({ instanceName: instanceFlag2 });
7
7
  const accessToken = await auth.getAccessToken();
8
8
  return { baseUrl: auth.getBaseUrl(), accessToken };
9
9
  }
10
+ const instanceFlag = {
11
+ instance: {
12
+ type: String,
13
+ description: 'Name of the Backstage instance to use (defaults to the one chosen with "auth select")'
14
+ }
15
+ };
10
16
 
17
+ exports.instanceFlag = instanceFlag;
11
18
  exports.resolveAuth = resolveAuth;
12
19
  //# sourceMappingURL=resolveAuth.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveAuth.cjs.js","sources":["../../src/lib/resolveAuth.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CliAuth } from '@backstage/cli-node';\n\nexport async function resolveAuth(instanceFlag?: string): Promise<{\n baseUrl: string;\n accessToken: string;\n}> {\n const auth = await CliAuth.create({ instanceName: instanceFlag });\n const accessToken = await auth.getAccessToken();\n return { baseUrl: auth.getBaseUrl(), accessToken };\n}\n"],"names":["CliAuth"],"mappings":";;;;AAkBA,eAAsB,YAAY,YAAA,EAG/B;AACD,EAAA,MAAM,OAAO,MAAMA,eAAA,CAAQ,OAAO,EAAE,YAAA,EAAc,cAAc,CAAA;AAChE,EAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,cAAA,EAAe;AAC9C,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,UAAA,IAAc,WAAA,EAAY;AACnD;;"}
1
+ {"version":3,"file":"resolveAuth.cjs.js","sources":["../../src/lib/resolveAuth.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CliAuth } from '@backstage/cli-node';\n\nexport async function resolveAuth(instanceFlag?: string): Promise<{\n baseUrl: string;\n accessToken: string;\n}> {\n const auth = await CliAuth.create({ instanceName: instanceFlag });\n const accessToken = await auth.getAccessToken();\n return { baseUrl: auth.getBaseUrl(), accessToken };\n}\n\n/**\n * Shared `--instance` flag definition, to be spread into each command's flags.\n */\nexport const instanceFlag = {\n instance: {\n type: String,\n description:\n 'Name of the Backstage instance to use (defaults to the one chosen with \"auth select\")',\n },\n};\n"],"names":["instanceFlag","CliAuth"],"mappings":";;;;AAkBA,eAAsB,YAAYA,aAAAA,EAG/B;AACD,EAAA,MAAM,OAAO,MAAMC,eAAA,CAAQ,OAAO,EAAE,YAAA,EAAcD,eAAc,CAAA;AAChE,EAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,cAAA,EAAe;AAC9C,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,UAAA,IAAc,WAAA,EAAY;AACnD;AAKO,MAAM,YAAA,GAAe;AAAA,EAC1B,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,MAAA;AAAA,IACN,WAAA,EACE;AAAA;AAEN;;;"}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var name = "@backstage/cli-module-search";
6
- var version = "0.2.0-next.0";
6
+ var version = "0.2.1-next.0";
7
7
  var description = "CLI module for searching Backstage content";
8
8
  var backstage = {
9
9
  role: "cli-module"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/cli-module-search",
3
- "version": "0.2.0-next.0",
3
+ "version": "0.2.1-next.0",
4
4
  "description": "CLI module for searching Backstage content",
5
5
  "backstage": {
6
6
  "role": "cli-module"
@@ -33,13 +33,13 @@
33
33
  "test": "backstage-cli package test"
34
34
  },
35
35
  "dependencies": {
36
- "@backstage/cli-node": "0.3.5-next.0",
37
- "@backstage/errors": "1.3.2-next.0",
36
+ "@backstage/cli-node": "0.3.6-next.0",
37
+ "@backstage/errors": "1.3.2",
38
38
  "chalk": "^4.0.0",
39
39
  "cleye": "^2.6.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@backstage/cli": "0.36.7-next.0"
42
+ "@backstage/cli": "0.36.8-next.0"
43
43
  },
44
44
  "typesVersions": {
45
45
  "*": {