@equinor/fusion-framework-cli-plugin-ai-index 1.0.6 → 2.0.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +74 -2
  2. package/README.md +105 -69
  3. package/dist/esm/bin/embed.js +28 -13
  4. package/dist/esm/bin/embed.js.map +1 -1
  5. package/dist/esm/delete-command.js +100 -0
  6. package/dist/esm/delete-command.js.map +1 -0
  7. package/dist/esm/delete-command.options.js +43 -0
  8. package/dist/esm/delete-command.options.js.map +1 -0
  9. package/dist/esm/{command.js → embeddings-command.js} +42 -28
  10. package/dist/esm/embeddings-command.js.map +1 -0
  11. package/dist/esm/{command.options.js → embeddings-command.options.js} +14 -7
  12. package/dist/esm/embeddings-command.options.js.map +1 -0
  13. package/dist/esm/index.js +37 -4
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/search-command.js +198 -0
  16. package/dist/esm/search-command.js.map +1 -0
  17. package/dist/esm/utils/generate-chunk-id.js +17 -5
  18. package/dist/esm/utils/generate-chunk-id.js.map +1 -1
  19. package/dist/esm/utils/git/file-changes.js +26 -11
  20. package/dist/esm/utils/git/file-changes.js.map +1 -1
  21. package/dist/esm/utils/git/git-client.js +16 -7
  22. package/dist/esm/utils/git/git-client.js.map +1 -1
  23. package/dist/esm/utils/git/metadata.js +7 -3
  24. package/dist/esm/utils/git/metadata.js.map +1 -1
  25. package/dist/esm/utils/git/status.js +9 -3
  26. package/dist/esm/utils/git/status.js.map +1 -1
  27. package/dist/esm/utils/markdown/parser.js +53 -13
  28. package/dist/esm/utils/markdown/parser.js.map +1 -1
  29. package/dist/esm/utils/package-resolver.js +10 -6
  30. package/dist/esm/utils/package-resolver.js.map +1 -1
  31. package/dist/esm/utils/ts-doc/constants.js +4 -1
  32. package/dist/esm/utils/ts-doc/constants.js.map +1 -1
  33. package/dist/esm/utils/ts-doc/extractors.js +27 -13
  34. package/dist/esm/utils/ts-doc/extractors.js.map +1 -1
  35. package/dist/esm/utils/ts-doc/parser.js +19 -10
  36. package/dist/esm/utils/ts-doc/parser.js.map +1 -1
  37. package/dist/esm/version.js +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/dist/types/config.d.ts +51 -10
  40. package/dist/types/delete-command.d.ts +9 -0
  41. package/dist/types/delete-command.options.d.ts +32 -0
  42. package/dist/types/embeddings-command.d.ts +11 -0
  43. package/dist/types/embeddings-command.options.d.ts +40 -0
  44. package/dist/types/index.d.ts +19 -2
  45. package/dist/types/search-command.d.ts +8 -0
  46. package/dist/types/utils/generate-chunk-id.d.ts +17 -5
  47. package/dist/types/utils/git/file-changes.d.ts +26 -11
  48. package/dist/types/utils/git/git-client.d.ts +16 -7
  49. package/dist/types/utils/git/metadata.d.ts +7 -3
  50. package/dist/types/utils/git/status.d.ts +9 -3
  51. package/dist/types/utils/git/types.d.ts +15 -9
  52. package/dist/types/utils/markdown/parser.d.ts +23 -10
  53. package/dist/types/utils/markdown/types.d.ts +13 -2
  54. package/dist/types/utils/package-resolver.d.ts +8 -5
  55. package/dist/types/utils/ts-doc/constants.d.ts +4 -1
  56. package/dist/types/utils/ts-doc/extractors.d.ts +27 -13
  57. package/dist/types/utils/ts-doc/parser.d.ts +19 -10
  58. package/dist/types/utils/ts-doc/types.d.ts +12 -4
  59. package/dist/types/utils/types.d.ts +10 -6
  60. package/dist/types/version.d.ts +1 -1
  61. package/package.json +12 -10
  62. package/src/bin/delete-removed-files.ts +1 -1
  63. package/src/bin/embed.ts +47 -18
  64. package/src/bin/file-stream.ts +1 -1
  65. package/src/bin/get-diff.ts +1 -1
  66. package/src/bin/types.ts +1 -1
  67. package/src/config.ts +52 -10
  68. package/src/delete-command.options.ts +51 -0
  69. package/src/delete-command.ts +117 -0
  70. package/src/{command.options.ts → embeddings-command.options.ts} +16 -9
  71. package/src/{command.ts → embeddings-command.ts} +46 -28
  72. package/src/index.ts +38 -4
  73. package/src/search-command.ts +259 -0
  74. package/src/utils/generate-chunk-id.ts +17 -5
  75. package/src/utils/git/file-changes.ts +26 -11
  76. package/src/utils/git/git-client.ts +16 -7
  77. package/src/utils/git/metadata.ts +7 -3
  78. package/src/utils/git/status.ts +9 -3
  79. package/src/utils/git/types.ts +15 -9
  80. package/src/utils/markdown/parser.ts +54 -13
  81. package/src/utils/markdown/types.ts +13 -2
  82. package/src/utils/package-resolver.ts +10 -6
  83. package/src/utils/ts-doc/constants.ts +4 -1
  84. package/src/utils/ts-doc/extractors.ts +27 -13
  85. package/src/utils/ts-doc/parser.ts +19 -10
  86. package/src/utils/ts-doc/types.ts +12 -4
  87. package/src/utils/types.ts +10 -6
  88. package/src/version.ts +1 -1
  89. package/dist/esm/command.js.map +0 -1
  90. package/dist/esm/command.options.js.map +0 -1
  91. package/dist/types/command.d.ts +0 -2
  92. package/dist/types/command.options.d.ts +0 -33
@@ -2,11 +2,11 @@ import { createCommand, createOption } from 'commander';
2
2
  import { loadFusionAIConfig, setupFramework } from '@equinor/fusion-framework-cli-plugin-ai-base';
3
3
  import { withOptions as withAiOptions } from '@equinor/fusion-framework-cli-plugin-ai-base/command-options';
4
4
  import { embed } from './bin/embed.js';
5
- import { CommandOptionsSchema } from './command.options.js';
5
+ import { CommandOptionsSchema } from './embeddings-command.options.js';
6
6
  /**
7
- * CLI command: `ai embeddings`
7
+ * CLI command: `ai index add`
8
8
  *
9
- * Document embedding utilities for Large Language Model processing.
9
+ * Add documents to the AI search index via embedding generation.
10
10
  *
11
11
  * Features:
12
12
  * - Markdown/MDX document chunking with frontmatter extraction
@@ -17,7 +17,7 @@ import { CommandOptionsSchema } from './command.options.js';
17
17
  * - Configurable file patterns via fusion-ai.config.ts
18
18
  *
19
19
  * Usage:
20
- * $ ffc ai embeddings [options] [glob-patterns...]
20
+ * $ ffc ai index add [options] [glob-patterns...]
21
21
  *
22
22
  * Arguments:
23
23
  * glob-patterns Glob patterns to match files (optional when using --diff)
@@ -30,38 +30,44 @@ import { CommandOptionsSchema } from './command.options.js';
30
30
  * --base-ref <ref> Git reference to compare against (default: HEAD~1)
31
31
  * --clean Delete all existing documents from the vector store before processing
32
32
  *
33
- * AI Options (required):
34
- * --openai-api-key <key> Azure OpenAI API key (or AZURE_OPENAI_API_KEY env var)
35
- * --openai-api-version <version> Azure OpenAI API version (default: 2024-02-15-preview)
36
- * --openai-instance <name> Azure OpenAI instance name (or AZURE_OPENAI_INSTANCE_NAME env var)
37
- * --openai-embedding-deployment <name> Azure OpenAI embedding deployment name (or AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME env var)
38
- * --azure-search-endpoint <url> Azure Search endpoint URL (or AZURE_SEARCH_ENDPOINT env var)
39
- * --azure-search-api-key <key> Azure Search API key (or AZURE_SEARCH_API_KEY env var)
40
- * --azure-search-index-name <name> Azure Search index name (or AZURE_SEARCH_INDEX_NAME env var)
41
- *
42
33
  * Examples:
43
- * $ ffc ai embeddings --dry-run ./src
44
- * $ ffc ai embeddings "*.ts" "*.md" "*.mdx"
45
- * $ ffc ai embeddings --diff
46
- * $ ffc ai embeddings --diff --base-ref origin/main
47
- * $ ffc ai embeddings --clean "*.ts"
34
+ * $ ffc ai index add --dry-run ./src
35
+ * $ ffc ai index add "*.ts" "*.md" "*.mdx"
36
+ * $ ffc ai index add --diff
37
+ * $ ffc ai index add --diff --base-ref origin/main
38
+ * $ ffc ai index add --clean "*.ts"
48
39
  */
49
- const _command = createCommand('embeddings')
50
- .description('Document embedding utilities for Large Language Model processing')
40
+ const _command = createCommand('add')
41
+ .description('Add documents to the AI search index via embedding generation')
51
42
  .addOption(createOption('--dry-run', 'Show what would be processed without actually doing it').default(false))
52
43
  .addOption(createOption('--config <config>', 'Path to a config file').default('fusion-ai.config'))
53
44
  .addOption(createOption('--diff', 'Process only changed files (workflow mode)').default(false))
54
45
  .addOption(createOption('--base-ref <ref>', 'Git reference to compare against').default('HEAD~1'))
55
46
  .addOption(createOption('--clean', 'Delete all existing documents from the vector store before processing').default(false))
56
47
  .argument('[glob-patterns...]', 'Glob patterns to match files (optional when using --diff)')
57
- .action(async (patterns, commandOptions) => {
58
- const options = await CommandOptionsSchema.parseAsync(commandOptions);
59
- // Load configuration
60
- const config = await loadFusionAIConfig(options.config, {
61
- baseDir: process.cwd(),
62
- });
63
- // CLI args take precedence over config patterns
48
+ .action(async function (patterns, commandOptions) {
49
+ // Load configuration before validation so config values can fill gaps
50
+ const preOptions = commandOptions;
51
+ const config = await loadFusionAIConfig(preOptions.config ?? 'fusion-ai.config', { baseDir: process.cwd() });
64
52
  const indexConfig = config.index ?? {};
53
+ // Config file values override env-var defaults but not explicit CLI flags.
54
+ // Commander merges env vars before the action runs, so we use
55
+ // getOptionValueSource to distinguish "user passed --flag" from "came from env".
56
+ const parentCommand = this.parent ?? this;
57
+ if (indexConfig.name) {
58
+ const source = parentCommand.getOptionValueSource('azureSearchIndexName');
59
+ if (source !== 'cli') {
60
+ preOptions.azureSearchIndexName = indexConfig.name;
61
+ }
62
+ }
63
+ if (indexConfig.model) {
64
+ const source = parentCommand.getOptionValueSource('openaiEmbeddingDeployment');
65
+ if (source !== 'cli') {
66
+ preOptions.openaiEmbeddingDeployment = indexConfig.model;
67
+ }
68
+ }
69
+ const options = await CommandOptionsSchema.parseAsync(preOptions);
70
+ // CLI args take precedence over config patterns
65
71
  const allowedFilePatterns = indexConfig.patterns ?? ['**/*.ts', '**/*.md', '**/*.mdx'];
66
72
  const filePatterns = patterns.length ? patterns : allowedFilePatterns;
67
73
  // Initialize framework
@@ -74,9 +80,17 @@ const _command = createCommand('embeddings')
74
80
  filePatterns,
75
81
  });
76
82
  });
83
+ /**
84
+ * Configured Commander command for the `ai index add` subcommand.
85
+ *
86
+ * This constant is the fully-configured {@link Command} instance with all
87
+ * AI-specific options (embedding deployment, Azure Search credentials) applied
88
+ * via `withAiOptions`. It is registered with the CLI automatically by
89
+ * {@link registerAiPlugin}.
90
+ */
77
91
  export const command = withAiOptions(_command, {
78
92
  includeEmbedding: true,
79
93
  includeSearch: true,
80
94
  });
81
95
  export default command;
82
- //# sourceMappingURL=command.js.map
96
+ //# sourceMappingURL=embeddings-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings-command.js","sourceRoot":"","sources":["../../src/embeddings-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AAClG,OAAO,EAAE,WAAW,IAAI,aAAa,EAAE,MAAM,8DAA8D,CAAC;AAE5G,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAuB,MAAM,iCAAiC,CAAC;AAG5F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC;KAClC,WAAW,CAAC,+DAA+D,CAAC;KAC5E,SAAS,CACR,YAAY,CAAC,WAAW,EAAE,wDAAwD,CAAC,CAAC,OAAO,CACzF,KAAK,CACN,CACF;KACA,SAAS,CAAC,YAAY,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;KACjG,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,4CAA4C,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;KAC9F,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,kCAAkC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;KACjG,SAAS,CACR,YAAY,CACV,SAAS,EACT,uEAAuE,CACxE,CAAC,OAAO,CAAC,KAAK,CAAC,CACjB;KACA,QAAQ,CAAC,oBAAoB,EAAE,2DAA2D,CAAC;KAC3F,MAAM,CAAC,KAAK,WAA0B,QAAkB,EAAE,cAA8B;IACvF,sEAAsE;IACtE,MAAM,UAAU,GAAG,cAAyC,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACpC,UAAU,CAAC,MAAiB,IAAI,kBAAkB,EACnD,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAC3B,CAAC;IACF,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IAEvC,2EAA2E;IAC3E,8DAA8D;IAC9D,iFAAiF;IACjF,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IAC1C,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,aAAa,CAAC,oBAAoB,CAAC,sBAAsB,CAAC,CAAC;QAC1E,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,UAAU,CAAC,oBAAoB,GAAG,WAAW,CAAC,IAAI,CAAC;QACrD,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,aAAa,CAAC,oBAAoB,CAAC,2BAA2B,CAAC,CAAC;QAC/E,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,UAAU,CAAC,yBAAyB,GAAG,WAAW,CAAC,KAAK,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAElE,gDAAgD;IAChD,MAAM,mBAAmB,GAAG,WAAW,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACvF,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAEtE,uBAAuB;IACvB,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAEhD,oDAAoD;IACpD,MAAM,KAAK,CAAC;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,YAAY;KACb,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE;IAC7C,gBAAgB,EAAE,IAAI;IACtB,aAAa,EAAE,IAAI;CACpB,CAAC,CAAC;AAEH,eAAe,OAAO,CAAC"}
@@ -1,14 +1,21 @@
1
1
  import { z } from 'zod';
2
2
  import { AiOptionsSchema } from '@equinor/fusion-framework-cli-plugin-ai-base/command-options';
3
3
  /**
4
- * Zod schema for validating command options for the embeddings command.
4
+ * Zod schema for validating command options for the `ai index add` command.
5
5
  *
6
- * This schema extends the base AI options schema with embeddings-specific options,
7
- * ensuring type safety and runtime validation of command arguments.
6
+ * Extends the base AI options schema ({@link AiOptionsSchema}) with
7
+ * add-specific options such as `--dry-run`, `--diff`, `--config`,
8
+ * `--base-ref`, and `--clean`.
8
9
  *
9
- * Note: Some optional AI options become required for the embeddings command
10
- * (openaiEmbeddingDeployment, azureSearchEndpoint, azureSearchApiKey, azureSearchIndexName)
11
- * because the command uses withAiOptions with includeEmbedding and includeSearch set to true.
10
+ * Azure Search and embedding options that are optional in the base schema
11
+ * become **required** because the add command always writes to a
12
+ * vector store.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const validated = await CommandOptionsSchema.parseAsync(rawOptions);
17
+ * // validated.dryRun, validated.azureSearchEndpoint, etc.
18
+ * ```
12
19
  */
13
20
  export const CommandOptionsSchema = AiOptionsSchema.extend({
14
21
  // Override optional AI options to make them required for embeddings command
@@ -45,4 +52,4 @@ export const CommandOptionsSchema = AiOptionsSchema.extend({
45
52
  .boolean({ message: 'clean must be a boolean value.' })
46
53
  .describe('Delete all existing documents from the vector store before processing'),
47
54
  }).describe('Command options for the embeddings command');
48
- //# sourceMappingURL=command.options.js.map
55
+ //# sourceMappingURL=embeddings-command.options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings-command.options.js","sourceRoot":"","sources":["../../src/embeddings-command.options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAC;AAE/F;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC,MAAM,CAAC;IACzD,4EAA4E;IAC5E,yBAAyB,EAAE,CAAC;SACzB,MAAM,CAAC,EAAE,OAAO,EAAE,+DAA+D,EAAE,CAAC;SACpF,GAAG,CAAC,CAAC,EAAE,uDAAuD,CAAC;SAC/D,QAAQ,CAAC,wCAAwC,CAAC;IACrD,mBAAmB,EAAE,CAAC;SACnB,MAAM,CAAC,EAAE,OAAO,EAAE,2DAA2D,EAAE,CAAC;SAChF,GAAG,CAAC,4CAA4C,CAAC;SACjD,GAAG,CAAC,CAAC,EAAE,mDAAmD,CAAC;SAC3D,QAAQ,CAAC,2BAA2B,CAAC;IACxC,iBAAiB,EAAE,CAAC;SACjB,MAAM,CAAC,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC;SAC/E,GAAG,CAAC,CAAC,EAAE,kDAAkD,CAAC;SAC1D,QAAQ,CAAC,sBAAsB,CAAC;IACnC,oBAAoB,EAAE,CAAC;SACpB,MAAM,CAAC,EAAE,OAAO,EAAE,6DAA6D,EAAE,CAAC;SAClF,GAAG,CAAC,CAAC,EAAE,qDAAqD,CAAC;SAC7D,QAAQ,CAAC,yBAAyB,CAAC;IAEtC,8BAA8B;IAC9B,MAAM,EAAE,CAAC;SACN,OAAO,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC;SACvD,QAAQ,CAAC,wDAAwD,CAAC;IACrE,MAAM,EAAE,CAAC;SACN,MAAM,CAAC,EAAE,OAAO,EAAE,8DAA8D,EAAE,CAAC;SACnF,GAAG,CAAC,CAAC,EAAE,8CAA8C,CAAC;SACtD,QAAQ,CAAC,uBAAuB,CAAC;IACpC,IAAI,EAAE,CAAC;SACJ,OAAO,CAAC,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;SACrD,QAAQ,CAAC,4CAA4C,CAAC;IACzD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAClF,KAAK,EAAE,CAAC;SACL,OAAO,CAAC,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC;SACtD,QAAQ,CAAC,uEAAuE,CAAC;CACrF,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC"}
package/dist/esm/index.js CHANGED
@@ -1,11 +1,44 @@
1
+ import { createCommand } from 'commander';
1
2
  import { registerAiPlugin as registerAiPluginBase } from '@equinor/fusion-framework-cli-plugin-ai-base';
2
- import { command as embeddingsCommand } from './command.js';
3
+ import { command as addCommand } from './embeddings-command.js';
4
+ import { deleteCommand as removeCommand } from './delete-command.js';
5
+ import { searchCommand } from './search-command.js';
3
6
  /**
4
- * Registers the AI index plugin command with the CLI program
5
- * @param program - The Commander program instance to register commands with
7
+ * Parent command for the `ai index` group.
8
+ *
9
+ * Owns three subcommands:
10
+ * - `add` — index documents into the Azure AI Search vector store.
11
+ * - `remove` — remove documents from the vector store.
12
+ * - `search` — query the vector store for indexed documents.
13
+ */
14
+ const indexCommand = createCommand('index')
15
+ .description('Manage the AI search index (add, search, remove)')
16
+ .addCommand(addCommand)
17
+ .addCommand(removeCommand)
18
+ .addCommand(searchCommand);
19
+ /**
20
+ * Registers the `ai index` command with the Fusion Framework CLI.
21
+ *
22
+ * Adds a single `index` command under `ai` with subcommands for indexing,
23
+ * searching, and removing documents in the Azure AI Search vector store.
24
+ *
25
+ * @param program - The root Commander {@link Command} instance to attach to.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { Command } from 'commander';
30
+ * import { registerAiPlugin } from '@equinor/fusion-framework-cli-plugin-ai-index';
31
+ *
32
+ * const program = new Command();
33
+ * registerAiPlugin(program);
34
+ * program.parse();
35
+ * // ffc ai index add [glob-patterns...]
36
+ * // ffc ai index search <query>
37
+ * // ffc ai index remove [source-paths...]
38
+ * ```
6
39
  */
7
40
  export function registerAiPlugin(program) {
8
- registerAiPluginBase(program, embeddingsCommand);
41
+ registerAiPluginBase(program, indexCommand);
9
42
  }
10
43
  export default registerAiPlugin;
11
44
  // Re-export config utilities for convenience
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACxG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAI5D;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;AACnD,CAAC;AAED,eAAe,gBAAgB,CAAC;AAEhC,6CAA6C;AAC7C,OAAO,EACL,iBAAiB,GAElB,MAAM,8CAA8C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACxG,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,aAAa,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIpD;;;;;;;GAOG;AACH,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC;KACxC,WAAW,CAAC,kDAAkD,CAAC;KAC/D,UAAU,CAAC,UAAU,CAAC;KACtB,UAAU,CAAC,aAAa,CAAC;KACzB,UAAU,CAAC,aAAa,CAAC,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,oBAAoB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AAC9C,CAAC;AAED,eAAe,gBAAgB,CAAC;AAEhC,6CAA6C;AAC7C,OAAO,EACL,iBAAiB,GAElB,MAAM,8CAA8C,CAAC"}
@@ -0,0 +1,198 @@
1
+ import { createCommand, createOption } from 'commander';
2
+ import { inspect } from 'node:util';
3
+ import { setupFramework } from '@equinor/fusion-framework-cli-plugin-ai-base';
4
+ import { withOptions as withAiOptions, } from '@equinor/fusion-framework-cli-plugin-ai-base/command-options';
5
+ /**
6
+ * Flatten Azure Cognitive Search metadata attributes into a plain object.
7
+ *
8
+ * Azure Search stores custom metadata as an array of `{ key, value }` pairs
9
+ * under an `attributes` property. This helper converts that array into a flat
10
+ * key-value map so consumers can access attributes directly
11
+ * (e.g. `metadata.source` instead of iterating the attributes array).
12
+ *
13
+ * JSON-encoded attribute values are transparently parsed; plain strings are
14
+ * kept as-is.
15
+ *
16
+ * @param metadata - Raw metadata record from an Azure Search document.
17
+ * @returns A shallow copy of `metadata` with the `attributes` array replaced by
18
+ * its flattened key-value entries.
19
+ */
20
+ const normalizeMetadata = (metadata) => {
21
+ const normalized = { ...metadata };
22
+ if (Array.isArray(normalized.attributes)) {
23
+ const attributesObj = {};
24
+ for (const attr of normalized.attributes) {
25
+ if (typeof attr === 'object' &&
26
+ attr !== null &&
27
+ 'key' in attr &&
28
+ 'value' in attr &&
29
+ typeof attr.key === 'string') {
30
+ try {
31
+ attributesObj[attr.key] = JSON.parse(attr.value);
32
+ }
33
+ catch {
34
+ attributesObj[attr.key] = attr.value;
35
+ }
36
+ }
37
+ }
38
+ Object.assign(normalized, attributesObj);
39
+ delete normalized.attributes;
40
+ }
41
+ return normalized;
42
+ };
43
+ /**
44
+ * Commander subcommand: **`ai index search`**
45
+ *
46
+ * Performs semantic vector-store search against an Azure Cognitive Search index
47
+ * and displays the matching documents. Use this command to validate that
48
+ * embeddings are indexed correctly, to explore the retrieval corpus, or to
49
+ * test OData filter expressions.
50
+ *
51
+ * Supports two search algorithms:
52
+ * - **`similarity`** (default) — pure cosine-similarity ranking.
53
+ * - **`mmr`** — Maximum Marginal Relevance, which re-ranks results to increase
54
+ * diversity while staying relevant.
55
+ *
56
+ * Results can be output as human-readable text (default) or as JSON objects
57
+ * (`--json`). The `--raw` flag preserves Azure Search's native metadata
58
+ * structure; without it, metadata attributes are flattened by
59
+ * {@link normalizeMetadata}.
60
+ *
61
+ * @example
62
+ * ```sh
63
+ * # Basic similarity search
64
+ * ffc ai index search "how to configure modules"
65
+ *
66
+ * # Limit results and use MMR for diversity
67
+ * ffc ai index search "authentication" --limit 5 --search-type mmr
68
+ *
69
+ * # Filter by package name
70
+ * ffc ai index search "hooks" --filter "metadata/attributes/any(a: a/key eq 'pkg_name' and a/value eq '@equinor/fusion-framework-react')" --json
71
+ *
72
+ * # Verbose output with raw Azure metadata
73
+ * ffc ai index search "API reference" --verbose --raw
74
+ * ```
75
+ */
76
+ const _command = createCommand('search')
77
+ .description('Search the vector store to validate embeddings and retrieve relevant documents')
78
+ .addOption(createOption('--limit <number>', 'Maximum number of results to return')
79
+ .default(10)
80
+ .argParser(parseInt))
81
+ .addOption(createOption('--search-type <type>', 'Search type: mmr or similarity')
82
+ .choices(['mmr', 'similarity'])
83
+ .default('similarity'))
84
+ .addOption(createOption('--filter <expression>', 'OData filter expression for metadata filtering'))
85
+ .addOption(createOption('--json', 'Output results as JSON').default(false))
86
+ .addOption(createOption('--raw', 'Output raw metadata without normalization').default(false))
87
+ .addOption(createOption('--verbose', 'Enable verbose output').default(false))
88
+ .argument('<query>', 'Search query string')
89
+ .action(async (query, options) => {
90
+ if (options.verbose) {
91
+ console.log('🔍 Initializing framework...');
92
+ }
93
+ const framework = await setupFramework(options);
94
+ if (!options.azureSearchIndexName) {
95
+ throw new Error('Azure Search index name is required');
96
+ }
97
+ if (options.verbose) {
98
+ console.log('✅ Framework initialized successfully');
99
+ console.log(`📇 Index: ${options.azureSearchIndexName}`);
100
+ console.log(`🔎 Searching for: "${query}"`);
101
+ console.log(`📊 Limit: ${options.limit}`);
102
+ console.log(`🔍 Search type: ${options.searchType}`);
103
+ if (options.filter) {
104
+ console.log(`🔧 Filter: ${options.filter}`);
105
+ }
106
+ console.log('');
107
+ }
108
+ const vectorStoreService = framework.ai.getService('search', options.azureSearchIndexName);
109
+ try {
110
+ const filter = options.filter ? { filterExpression: options.filter } : undefined;
111
+ const retrieverOptions = options.searchType === 'mmr'
112
+ ? {
113
+ k: options.limit,
114
+ searchType: 'mmr',
115
+ ...(filter && { filter: filter }),
116
+ }
117
+ : {
118
+ k: options.limit,
119
+ searchType: 'similarity',
120
+ ...(filter && { filter: filter }),
121
+ };
122
+ const retriever = vectorStoreService.asRetriever(retrieverOptions);
123
+ const results = await retriever.invoke(query);
124
+ if (!results || !Array.isArray(results)) {
125
+ throw new Error(`Invalid search results: expected array but got ${results === null ? 'null' : typeof results}`);
126
+ }
127
+ if (options.json) {
128
+ for (const doc of results) {
129
+ if (options.raw) {
130
+ console.log(inspect(doc, { depth: null, colors: true }));
131
+ }
132
+ else {
133
+ const metadata = normalizeMetadata(doc.metadata);
134
+ console.log({
135
+ content: doc.pageContent,
136
+ metadata,
137
+ score: metadata?.score,
138
+ });
139
+ }
140
+ }
141
+ }
142
+ else {
143
+ if (results.length === 0) {
144
+ console.log('❌ No results found');
145
+ return;
146
+ }
147
+ console.log(`✅ Found ${results.length} result${results.length !== 1 ? 's' : ''}:\n`);
148
+ results.forEach((doc, index) => {
149
+ const processedMetadata = options.raw
150
+ ? doc.metadata
151
+ : normalizeMetadata(doc.metadata);
152
+ const metadata = processedMetadata;
153
+ const score = metadata.score;
154
+ const source = metadata.source || 'Unknown source';
155
+ console.log(`${'─'.repeat(80)}`);
156
+ console.log(`Result ${index + 1}${score !== undefined ? ` (Score: ${score.toFixed(4)})` : ''}`);
157
+ console.log(`Source: ${source}`);
158
+ if (options.verbose) {
159
+ const { source: _, score: __, ...otherMetadata } = metadata;
160
+ if (Object.keys(otherMetadata).length > 0) {
161
+ console.log(`Metadata:`, JSON.stringify(otherMetadata, null, 2));
162
+ }
163
+ }
164
+ console.log('');
165
+ const content = doc.pageContent;
166
+ const maxLength = 500;
167
+ if (content.length > maxLength) {
168
+ console.log(`${content.substring(0, maxLength)}...`);
169
+ console.log(`\n[Content truncated - ${content.length} characters total]`);
170
+ }
171
+ else {
172
+ console.log(content);
173
+ }
174
+ console.log('');
175
+ });
176
+ console.log(`${'─'.repeat(80)}`);
177
+ }
178
+ }
179
+ catch (error) {
180
+ console.error(`❌ Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
181
+ if (options.verbose && error instanceof Error && error.stack) {
182
+ console.error(error.stack);
183
+ }
184
+ process.exit(1);
185
+ }
186
+ });
187
+ /**
188
+ * Configured Commander command for the `ai index search` subcommand.
189
+ *
190
+ * Fully-configured {@link Command} instance with all AI-specific options
191
+ * (embedding deployment, Azure Search credentials) applied via `withAiOptions`.
192
+ */
193
+ export const searchCommand = withAiOptions(_command, {
194
+ includeEmbedding: true,
195
+ includeSearch: true,
196
+ });
197
+ export default searchCommand;
198
+ //# sourceMappingURL=search-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-command.js","sourceRoot":"","sources":["../../src/search-command.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,21 @@
1
1
  /**
2
- * Generates a unique identifier for a document chunk based on file path
3
- * Creates a deterministic, URL-safe hash from the file path for validation and checks
4
- * @param filePath - The file path to generate an ID from
5
- * @param chunkIndex - Optional chunk index to append for multi-chunk documents
6
- * @returns A base64-encoded hash of the file path, optionally suffixed with chunk index
2
+ * Generates a deterministic, URL-safe identifier for a document chunk.
3
+ *
4
+ * The identifier is a Base64-encoded hash of the file path with all
5
+ * non-alphanumeric characters stripped, making it safe for use as an
6
+ * Azure AI Search document key.
7
+ *
8
+ * @param filePath - The relative file path to hash.
9
+ * @param chunkIndex - Optional zero-based chunk index appended to distinguish
10
+ * multiple chunks originating from the same file.
11
+ * @returns A stable, alphanumeric document ID string.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * generateChunkId('packages/cli/src/index.ts'); // 'cGFja2FnZXMvY2xpL3NyYy9pbmRleC50cw'
16
+ * generateChunkId('packages/cli/src/index.ts', 0); // 'cGFja2FnZXMvY2xpL3NyYy9pbmRleC50cw-0'
17
+ * generateChunkId('packages/cli/src/index.ts', 3); // 'cGFja2FnZXMvY2xpL3NyYy9pbmRleC50cw-3'
18
+ * ```
7
19
  */
8
20
  export const generateChunkId = (filePath, chunkIndex) => {
9
21
  // Convert file path to base64 and remove non-alphanumeric characters
@@ -1 +1 @@
1
- {"version":3,"file":"generate-chunk-id.js","sourceRoot":"","sources":["../../../src/utils/generate-chunk-id.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAE,UAAmB,EAAU,EAAE;IAC/E,qEAAqE;IACrE,gEAAgE;IAChE,yEAAyE;IACzE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;SACnC,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IAChC,mFAAmF;IACnF,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7D,CAAC,CAAC"}
1
+ {"version":3,"file":"generate-chunk-id.js","sourceRoot":"","sources":["../../../src/utils/generate-chunk-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAE,UAAmB,EAAU,EAAE;IAC/E,qEAAqE;IACrE,gEAAgE;IAChE,yEAAyE;IACzE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;SACnC,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IAChC,mFAAmF;IACnF,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7D,CAAC,CAAC"}
@@ -1,9 +1,15 @@
1
1
  import { join, relative } from 'node:path';
2
2
  import { resolveProjectRoot, getGit } from './git-client.js';
3
3
  /**
4
- * Get list of changed files using git diff with status
5
- * @param options - Git diff configuration options
6
- * @returns Array of changed files with their status
4
+ * Returns a list of files changed between `baseRef` and HEAD.
5
+ *
6
+ * Parses the output of `git diff --name-status` to classify each file as
7
+ * `'new'`, `'modified'`, or `'removed'`. Renames are expanded into a
8
+ * `'removed'` entry for the old path and a `'new'` entry for the new path.
9
+ *
10
+ * @param options - Configuration controlling the diff reference and working directory.
11
+ * @returns Array of changed files with their status.
12
+ * @throws {Error} If the working directory is not inside a git repository.
7
13
  */
8
14
  export const getChangedFiles = async (options) => {
9
15
  const { diff, baseRef = 'HEAD~1', cwd = process.cwd() } = options;
@@ -70,10 +76,15 @@ export const getChangedFiles = async (options) => {
70
76
  }
71
77
  };
72
78
  /**
73
- * Determine the git status of a file, including handling renames
74
- * Returns an array of ChangedFile objects - if the file was renamed, returns both old and new paths
75
- * @param filePath - Absolute file path to check
76
- * @returns Promise resolving to array of changed files (1 or 2 items if renamed)
79
+ * Determines the git change status of a single file.
80
+ *
81
+ * Checks tracked status, porcelain output, and rename/copy detection to
82
+ * produce one or two {@link ChangedFile} entries (two when a rename is
83
+ * detected — one `'removed'` for the old path and one `'new'` for the
84
+ * current path).
85
+ *
86
+ * @param filePath - Absolute path to the file to inspect.
87
+ * @returns Array with one or two changed-file entries.
77
88
  */
78
89
  export const getFileStatus = async (filePath) => {
79
90
  const { git, gitRepoPath } = getGit(filePath) ?? {};
@@ -182,10 +193,14 @@ export const getFileStatus = async (filePath) => {
182
193
  }
183
194
  };
184
195
  /**
185
- * Check if a file path matches any of the changed files
186
- * @param filePath - File path to check
187
- * @param changedFiles - Array of changed file objects
188
- * @returns True if file has changed
196
+ * Checks whether a file path appears in a list of changed files.
197
+ *
198
+ * When the changed-files list is empty (no diff filtering active), every
199
+ * file is considered changed so that all files are processed.
200
+ *
201
+ * @param filePath - Absolute file path to look up.
202
+ * @param changedFiles - Array of {@link ChangedFile} entries to search.
203
+ * @returns `true` if the file has changed or if diff filtering is disabled.
189
204
  */
190
205
  export const isFileChanged = (filePath, changedFiles) => {
191
206
  if (changedFiles.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"file-changes.js","sourceRoot":"","sources":["../../../../src/utils/git/file-changes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-changes.js","sourceRoot":"","sources":["../../../../src/utils/git/file-changes.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,13 @@ import { dirname, join } from 'node:path';
4
4
  import { existsSync } from 'node:fs';
5
5
  const gitCache = new Map();
6
6
  /**
7
- * Resolve the project root (git repository root) for a given file path
8
- * @param filePath - File path to resolve from
9
- * @returns Project root path or undefined if not in a git repository
7
+ * Resolves the git repository root for a given file path.
8
+ *
9
+ * Walks up the directory tree looking for a `.git` directory or file
10
+ * (to support worktrees) and returns the enclosing directory.
11
+ *
12
+ * @param filePath - Absolute file or directory path to resolve from.
13
+ * @returns Absolute path to the repository root, or `undefined` if not inside a git repo.
10
14
  */
11
15
  export const resolveProjectRoot = (filePath) => {
12
16
  // if we are in the root of the git repository, return the root
@@ -18,10 +22,15 @@ export const resolveProjectRoot = (filePath) => {
18
22
  return projectRoot;
19
23
  };
20
24
  /**
21
- * Get or create a SimpleGit instance for a given file path
22
- * Uses caching to avoid creating multiple instances for the same repository
23
- * @param filePath - File path to get git instance for
24
- * @returns Git instance and repository path, or undefined if not in a git repository
25
+ * Returns a cached `SimpleGit` instance scoped to the repository that
26
+ * contains `filePath`.
27
+ *
28
+ * Instances are cached by repository root to avoid repeatedly spawning
29
+ * new git processes for the same repo.
30
+ *
31
+ * @param filePath - Absolute file path to locate the repository for.
32
+ * @returns An object containing the git client and the repository root path,
33
+ * or `undefined` when `filePath` is not inside a git repository.
25
34
  */
26
35
  export const getGit = (filePath) => {
27
36
  const gitRepoPath = resolveProjectRoot(filePath);
@@ -1 +1 @@
1
- {"version":3,"file":"git-client.js","sourceRoot":"","sources":["../../../../src/utils/git/git-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAsB,EAAE;IACzE,+DAA+D;IAC/D,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACjF,MAAM,WAAW,GAAG,WAAW,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACvD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,QAAgB,EACiD,EAAE;IACnE,MAAM,WAAW,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,OAAO;YACL,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;YAC9B,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
1
+ {"version":3,"file":"git-client.js","sourceRoot":"","sources":["../../../../src/utils/git/git-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAsB,EAAE;IACzE,+DAA+D;IAC/D,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACjF,MAAM,WAAW,GAAG,WAAW,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACvD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,QAAgB,EACiD,EAAE;IACnE,MAAM,WAAW,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,OAAO;YACL,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;YAC9B,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
@@ -17,9 +17,13 @@ const generateGithubPermalink = (gitRemoteUrl, filePath, slug) => {
17
17
  return undefined;
18
18
  };
19
19
  /**
20
- * Extract git metadata for a file
21
- * @param filePath - Absolute file path
22
- * @returns Git metadata or undefined if not in a git repository
20
+ * Extracts git metadata for a single source file.
21
+ *
22
+ * Resolves the latest commit hash, commit date, and a GitHub permalink
23
+ * (when the remote is a GitHub URL) by inspecting `git log` output.
24
+ *
25
+ * @param filePath - Absolute path to the file.
26
+ * @returns Git metadata, or `undefined` if the file is not inside a git repository.
23
27
  */
24
28
  export const extractGitMetadata = async (filePath) => {
25
29
  const { git, gitRepoPath: gitRepoRoot } = getGit(filePath) ?? {};
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../src/utils/git/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,uBAAuB,GAAG,CAC9B,YAAoB,EACpB,QAAgB,EAChB,IAAa,EACO,EAAE;IACtB,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACtF,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,WAAW,CAAC;QACpC,OAAO,sBAAsB,KAAK,IAAI,IAAI,SAAS,IAAI,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;IAClF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EAAE,QAAgB,EAAoC,EAAE;IAC7F,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjE,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,WAAW,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACpD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IACrE,MAAM,YAAY,GAAG,MAAM,GAAG;SAC3B,SAAS,CAAC,mBAAmB,CAAC;SAC9B,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,uBAAuB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/F,OAAO;QACL,QAAQ;QACR,eAAe,EAAE,MAAM,EAAE,IAAI;QAC7B,eAAe,EAAE,MAAM,EAAE,IAAI;KAC9B,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../src/utils/git/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,uBAAuB,GAAG,CAC9B,YAAoB,EACpB,QAAgB,EAChB,IAAa,EACO,EAAE;IACtB,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACtF,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,WAAW,CAAC;QACpC,OAAO,sBAAsB,KAAK,IAAI,IAAI,SAAS,IAAI,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;IAClF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EAAE,QAAgB,EAAoC,EAAE;IAC7F,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjE,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,WAAW,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACpD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IACrE,MAAM,YAAY,GAAG,MAAM,GAAG;SAC3B,SAAS,CAAC,mBAAmB,CAAC;SAC9B,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,uBAAuB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/F,OAAO;QACL,QAAQ;QACR,eAAe,EAAE,MAAM,EAAE,IAAI;QAC7B,eAAe,EAAE,MAAM,EAAE,IAAI;KAC9B,CAAC;AACJ,CAAC,CAAC"}