@redaksjon/protokoll 0.4.3 → 1.0.1
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/.kronologi/config.yaml +10 -0
- package/.kronologi/jobs/monthly-summary/config.yaml +40 -0
- package/.kronologi/jobs/monthly-summary/instructions.md +23 -0
- package/.kronologi/jobs/monthly-summary/persona.md +11 -0
- package/.kronologi/jobs/weekly-summary/config.yaml +42 -0
- package/.kronologi/jobs/weekly-summary/instructions.md +21 -0
- package/.kronologi/jobs/weekly-summary/persona.md +10 -0
- package/README.md +41 -0
- package/activity/2026/4/test-activity.md +10 -0
- package/dist/main.js +5 -4
- package/dist/main.js.map +1 -1
- package/dist/mcp/prompts/batch_transcription.md +50 -1
- package/dist/mcp/prompts/edit_entity.md +50 -1
- package/dist/mcp/prompts/enrich_entity.md +95 -2
- package/dist/mcp/prompts/find_and_analyze.md +127 -0
- package/dist/mcp/prompts/review_transcript.md +39 -1
- package/dist/mcp/server.js +45 -12
- package/dist/mcp/server.js.map +1 -1
- package/dist/term-assist.js +15 -5
- package/dist/term-assist.js.map +1 -1
- package/dist/term-context.js +14 -4
- package/dist/term-context.js.map +1 -1
- package/dist/transcript.js +495 -404
- package/dist/transcript.js.map +1 -1
- package/docs/mcp-tools/get-version.md +57 -0
- package/guide/index.md +6 -0
- package/guide/quickstart.md +26 -1
- package/package.json +4 -2
- package/summary/2026/4/completion.json +16 -0
- package/summary/2026/4/inputs.json +60 -0
- package/summary/2026/4/summary.md +26 -0
package/dist/term-assist.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { L as createCompletion, g as getLogger } from './transcript.js';
|
|
2
2
|
import 'readline';
|
|
3
3
|
import 'child_process';
|
|
4
4
|
import 'node:path';
|
|
5
5
|
import 'fs/promises';
|
|
6
6
|
import 'openai';
|
|
7
7
|
import 'fluent-ffmpeg';
|
|
8
|
+
import 'node:os';
|
|
9
|
+
import '@riotprompt/riotprompt';
|
|
10
|
+
import 'zod';
|
|
8
11
|
import 'node:fs';
|
|
9
12
|
import 'glob';
|
|
10
13
|
import 'node:crypto';
|
|
11
14
|
import 'node:fs/promises';
|
|
12
15
|
import 'html-to-text';
|
|
13
16
|
import 'commander';
|
|
17
|
+
import '@theunwalked/overcontext';
|
|
18
|
+
import '@redaksjon/context';
|
|
14
19
|
import 'js-yaml';
|
|
15
|
-
import 'fs';
|
|
16
|
-
import 'node:os';
|
|
17
20
|
import 'winston';
|
|
18
|
-
import '@riotprompt/riotprompt';
|
|
19
21
|
|
|
20
22
|
const create = (config) => {
|
|
21
23
|
const logger = getLogger();
|
|
@@ -269,6 +271,14 @@ Example for "PostgreSQL": database`;
|
|
|
269
271
|
isAvailable
|
|
270
272
|
};
|
|
271
273
|
};
|
|
274
|
+
const withProgress = async (message, operation, print) => {
|
|
275
|
+
print(`[${message}...]`);
|
|
276
|
+
try {
|
|
277
|
+
const result = await operation();
|
|
278
|
+
return result;
|
|
279
|
+
} finally {
|
|
280
|
+
}
|
|
281
|
+
};
|
|
272
282
|
|
|
273
|
-
export { create };
|
|
283
|
+
export { create, withProgress };
|
|
274
284
|
//# sourceMappingURL=term-assist.js.map
|
package/dist/term-assist.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"term-assist.js","sources":["../src/cli/term-assist.ts"],"sourcesContent":["/**\n * Term Assist\n * \n * LLM-assisted term metadata generation for smart term creation.\n */\n\nimport { getLogger } from '../logging';\nimport * as OpenAI from '../util/openai';\nimport { SmartAssistanceConfig } from '../context/types';\nimport { TermAnalysisContext } from './term-context';\n\nexport interface TermSuggestions {\n soundsLike: string[];\n description?: string;\n topics: string[];\n domain?: string;\n}\n\nexport interface TermAssistInstance {\n generateSoundsLike(term: string): Promise<string[]>;\n generateDescription(term: string, context: TermAnalysisContext): Promise<string>;\n generateTopics(term: string, context: TermAnalysisContext): Promise<string[]>;\n suggestDomain(term: string, context: TermAnalysisContext): Promise<string | undefined>;\n generateAll(term: string, context: TermAnalysisContext): Promise<TermSuggestions>;\n isAvailable(): boolean;\n}\n\nexport const create = (config: SmartAssistanceConfig): TermAssistInstance => {\n const logger = getLogger();\n \n const isAvailable = (): boolean => {\n return !!process.env.OPENAI_API_KEY && config.enabled && config.termsEnabled !== false;\n };\n\n const generateSoundsLike = async (term: string): Promise<string[]> => {\n if (!isAvailable() || !config.termSoundsLikeOnAdd) {\n logger.debug('Term sounds_like generation not enabled');\n return [];\n }\n\n logger.debug('Generating phonetic variants for term: %s', term);\n\n const prompt = `The term \"${term}\" will be spoken in audio recordings and transcribed by Whisper speech-to-text.\n\nGenerate phonetic variations that Whisper might produce when mishearing this term. Include:\n- Common phonetic mishearings\n- How the term sounds in different accents\n- Alternate spellings a speech-to-text system might produce\n- Common transcription errors\n- Phonetically similar words or phrases\n\nThis is for correcting the TERM when it's misheard in transcription.\n\nOutput ONLY a comma-separated list with no explanation, no quotes, no extra text.\nDo NOT include the original term in the list.\n\nExample for \"Kubernetes\": cube a netes,coobernettys,cube er netes,k8s,coobernetties\nExample for \"PostgreSQL\": post gres,postgres,post gray sequel,postgre\nExample for \"OAuth\": oh auth,o auth,open auth,o off`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.phoneticModel,\n reasoningLevel: 'low',\n }\n );\n\n const variants: string[] = response\n .split(',')\n .map((p: string) => p.trim().toLowerCase())\n .filter((p: string) => p.length > 0 && p.toLowerCase() !== term.toLowerCase());\n\n const uniqueVariants = [...new Set(variants)];\n\n logger.debug('Generated %d phonetic variants', uniqueVariants.length);\n return uniqueVariants;\n\n } catch (error: any) {\n logger.error('Failed to generate phonetic variants: %s', error.message);\n return [];\n }\n };\n\n const generateDescription = async (term: string, context: TermAnalysisContext): Promise<string> => {\n if (!isAvailable() || !config.termDescriptionOnAdd) {\n logger.debug('Term description generation not enabled');\n return '';\n }\n\n logger.debug('Generating description for term: %s', term);\n\n // Build rich prompt with source content if available\n let sourceContext = '';\n if (context.sourceContent) {\n sourceContext = `\\n\\nSource documentation:\\n---\\n${context.sourceContent}\\n---\\n`;\n }\n\n const prompt = `Generate a clear, concise description for the term \"${term}\".\n\n${context.expansion ? `This term is an abbreviation/acronym for: ${context.expansion}` : ''}\n\n${sourceContext}\n\n${context.contextText}\n\nWrite a description that:\n- Explains what the term means in 1-3 sentences\n- Is clear and accessible to someone unfamiliar with the term\n- Focuses on practical understanding over formal definitions\n- Relates to how this term is used in the user's work context\n\nOutput ONLY the description text with no preamble, quotes, or extra formatting.\n\nExample for \"Kubernetes\": \"Kubernetes is an open-source container orchestration platform that automates deployment, scaling, and management of containerized applications. It provides a framework for running distributed systems resiliently.\"\n\nExample for \"CICD\": \"CICD (Continuous Integration/Continuous Deployment) is a software development practice that automates the building, testing, and deployment of applications. It enables teams to deliver code changes more frequently and reliably.\"`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.analysisModel,\n reasoningLevel: 'low',\n }\n );\n\n const description = response.trim();\n logger.debug('Generated description (%d chars)', description.length);\n return description;\n\n } catch (error: any) {\n logger.error('Failed to generate description: %s', error.message);\n return '';\n }\n };\n\n const generateTopics = async (term: string, context: TermAnalysisContext): Promise<string[]> => {\n if (!isAvailable() || !config.termTopicsOnAdd) {\n logger.debug('Term topics generation not enabled');\n return [];\n }\n\n logger.debug('Generating topics for term: %s', term);\n\n // Build rich prompt with source content if available\n let sourceContext = '';\n if (context.sourceContent) {\n sourceContext = `\\n\\nSource documentation:\\n---\\n${context.sourceContent}\\n---\\n`;\n }\n\n const prompt = `Generate related topic keywords for the term \"${term}\".\n\n${context.expansion ? `This term is an abbreviation/acronym for: ${context.expansion}` : ''}\n\n${sourceContext}\n\n${context.contextText}\n\nGenerate keywords that:\n- Describe technologies, concepts, or domains related to this term\n- Are single words or hyphenated phrases\n- Would help identify when this term is relevant to a conversation\n- Include both specific and broader related concepts\n- Aim for 8-15 keywords\n\nOutput ONLY a comma-separated list with no explanation, no quotes, no extra text.\n\nExample for \"Kubernetes\": containers,orchestration,cloud-native,devops,docker,microservices,deployment,scaling,infrastructure,automation\nExample for \"OAuth\": authentication,authorization,security,api,tokens,identity,access-control,sso`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.analysisModel,\n reasoningLevel: 'low',\n }\n );\n\n const topics: string[] = response\n .split(',')\n .map((t: string) => t.trim().toLowerCase())\n .filter((t: string) => t.length > 0);\n\n const uniqueTopics = [...new Set(topics)];\n\n logger.debug('Generated %d topics', uniqueTopics.length);\n return uniqueTopics;\n\n } catch (error: any) {\n logger.error('Failed to generate topics: %s', error.message);\n return [];\n }\n };\n\n const suggestDomain = async (term: string, context: TermAnalysisContext): Promise<string | undefined> => {\n if (!isAvailable()) {\n logger.debug('Term domain suggestion not enabled');\n return context.suggestedDomain;\n }\n\n // If context already has a strong domain suggestion, use it\n if (context.suggestedDomain) {\n logger.debug('Using inferred domain: %s', context.suggestedDomain);\n return context.suggestedDomain;\n }\n\n logger.debug('Suggesting domain for term: %s', term);\n\n // Build rich prompt with source content if available\n let sourceContext = '';\n if (context.sourceContent) {\n sourceContext = `\\n\\nSource documentation:\\n---\\n${context.sourceContent}\\n---\\n`;\n }\n\n const prompt = `Suggest an appropriate domain/category for the term \"${term}\".\n\n${context.expansion ? `This term is an abbreviation/acronym for: ${context.expansion}` : ''}\n\n${sourceContext}\n\n${context.contextText}\n\nChoose ONE domain that best fits this term. Common domains include:\n- devops\n- engineering\n- cloud\n- database\n- security\n- business\n- product\n- finance\n- testing\n- infrastructure\n- automation\n- data-science\n- frontend\n- backend\n\nOutput ONLY the domain name (lowercase, hyphenated if needed) with no explanation or extra text.\n\nExample for \"Kubernetes\": devops\nExample for \"React\": frontend\nExample for \"PostgreSQL\": database`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.analysisModel,\n reasoningLevel: 'low',\n }\n );\n\n const domain = response.trim().toLowerCase();\n logger.debug('Suggested domain: %s', domain);\n return domain || undefined;\n\n } catch (error: any) {\n logger.error('Failed to suggest domain: %s', error.message);\n return undefined;\n }\n };\n\n const generateAll = async (term: string, context: TermAnalysisContext): Promise<TermSuggestions> => {\n if (!isAvailable()) {\n logger.debug('Smart assistance not available');\n return {\n soundsLike: [],\n topics: [],\n };\n }\n\n logger.debug('Generating all suggestions for term: %s', term);\n\n try {\n // Generate in parallel for efficiency\n const [soundsLike, description, topics, domain] = await Promise.all([\n config.termSoundsLikeOnAdd ? generateSoundsLike(term) : Promise.resolve([]),\n config.termDescriptionOnAdd ? generateDescription(term, context) : Promise.resolve(''),\n config.termTopicsOnAdd ? generateTopics(term, context) : Promise.resolve([]),\n suggestDomain(term, context),\n ]);\n\n return {\n soundsLike,\n description: description || undefined,\n topics,\n domain,\n };\n\n } catch (error: any) {\n logger.error('Failed to generate suggestions: %s', error.message);\n return {\n soundsLike: [],\n topics: [],\n };\n }\n };\n\n return {\n generateSoundsLike,\n generateDescription,\n generateTopics,\n suggestDomain,\n generateAll,\n isAvailable,\n };\n};\n\n/**\n * Helper for showing progress during async operations\n */\nexport const withProgress = async <T>(\n message: string,\n operation: () => Promise<T>,\n print: (text: string) => void\n): Promise<T> => {\n print(`[${message}...]`);\n try {\n const result = await operation();\n return result;\n } finally {\n // Progress complete\n }\n};\n"],"names":["OpenAI.createCompletion"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"term-assist.js","sources":["../src/cli/term-assist.ts"],"sourcesContent":["/**\n * Term Assist\n * \n * LLM-assisted term metadata generation for smart term creation.\n */\n\nimport { getLogger } from '../logging';\nimport * as OpenAI from '../util/openai';\nimport { SmartAssistanceConfig } from '../context/types';\nimport { TermAnalysisContext } from './term-context';\n\nexport interface TermSuggestions {\n soundsLike: string[];\n description?: string;\n topics: string[];\n domain?: string;\n}\n\nexport interface TermAssistInstance {\n generateSoundsLike(term: string): Promise<string[]>;\n generateDescription(term: string, context: TermAnalysisContext): Promise<string>;\n generateTopics(term: string, context: TermAnalysisContext): Promise<string[]>;\n suggestDomain(term: string, context: TermAnalysisContext): Promise<string | undefined>;\n generateAll(term: string, context: TermAnalysisContext): Promise<TermSuggestions>;\n isAvailable(): boolean;\n}\n\nexport const create = (config: SmartAssistanceConfig): TermAssistInstance => {\n const logger = getLogger();\n \n const isAvailable = (): boolean => {\n return !!process.env.OPENAI_API_KEY && config.enabled && config.termsEnabled !== false;\n };\n\n const generateSoundsLike = async (term: string): Promise<string[]> => {\n if (!isAvailable() || !config.termSoundsLikeOnAdd) {\n logger.debug('Term sounds_like generation not enabled');\n return [];\n }\n\n logger.debug('Generating phonetic variants for term: %s', term);\n\n const prompt = `The term \"${term}\" will be spoken in audio recordings and transcribed by Whisper speech-to-text.\n\nGenerate phonetic variations that Whisper might produce when mishearing this term. Include:\n- Common phonetic mishearings\n- How the term sounds in different accents\n- Alternate spellings a speech-to-text system might produce\n- Common transcription errors\n- Phonetically similar words or phrases\n\nThis is for correcting the TERM when it's misheard in transcription.\n\nOutput ONLY a comma-separated list with no explanation, no quotes, no extra text.\nDo NOT include the original term in the list.\n\nExample for \"Kubernetes\": cube a netes,coobernettys,cube er netes,k8s,coobernetties\nExample for \"PostgreSQL\": post gres,postgres,post gray sequel,postgre\nExample for \"OAuth\": oh auth,o auth,open auth,o off`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.phoneticModel,\n reasoningLevel: 'low',\n }\n );\n\n const variants: string[] = response\n .split(',')\n .map((p: string) => p.trim().toLowerCase())\n .filter((p: string) => p.length > 0 && p.toLowerCase() !== term.toLowerCase());\n\n const uniqueVariants = [...new Set(variants)];\n\n logger.debug('Generated %d phonetic variants', uniqueVariants.length);\n return uniqueVariants;\n\n } catch (error: any) {\n logger.error('Failed to generate phonetic variants: %s', error.message);\n return [];\n }\n };\n\n const generateDescription = async (term: string, context: TermAnalysisContext): Promise<string> => {\n if (!isAvailable() || !config.termDescriptionOnAdd) {\n logger.debug('Term description generation not enabled');\n return '';\n }\n\n logger.debug('Generating description for term: %s', term);\n\n // Build rich prompt with source content if available\n let sourceContext = '';\n if (context.sourceContent) {\n sourceContext = `\\n\\nSource documentation:\\n---\\n${context.sourceContent}\\n---\\n`;\n }\n\n const prompt = `Generate a clear, concise description for the term \"${term}\".\n\n${context.expansion ? `This term is an abbreviation/acronym for: ${context.expansion}` : ''}\n\n${sourceContext}\n\n${context.contextText}\n\nWrite a description that:\n- Explains what the term means in 1-3 sentences\n- Is clear and accessible to someone unfamiliar with the term\n- Focuses on practical understanding over formal definitions\n- Relates to how this term is used in the user's work context\n\nOutput ONLY the description text with no preamble, quotes, or extra formatting.\n\nExample for \"Kubernetes\": \"Kubernetes is an open-source container orchestration platform that automates deployment, scaling, and management of containerized applications. It provides a framework for running distributed systems resiliently.\"\n\nExample for \"CICD\": \"CICD (Continuous Integration/Continuous Deployment) is a software development practice that automates the building, testing, and deployment of applications. It enables teams to deliver code changes more frequently and reliably.\"`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.analysisModel,\n reasoningLevel: 'low',\n }\n );\n\n const description = response.trim();\n logger.debug('Generated description (%d chars)', description.length);\n return description;\n\n } catch (error: any) {\n logger.error('Failed to generate description: %s', error.message);\n return '';\n }\n };\n\n const generateTopics = async (term: string, context: TermAnalysisContext): Promise<string[]> => {\n if (!isAvailable() || !config.termTopicsOnAdd) {\n logger.debug('Term topics generation not enabled');\n return [];\n }\n\n logger.debug('Generating topics for term: %s', term);\n\n // Build rich prompt with source content if available\n let sourceContext = '';\n if (context.sourceContent) {\n sourceContext = `\\n\\nSource documentation:\\n---\\n${context.sourceContent}\\n---\\n`;\n }\n\n const prompt = `Generate related topic keywords for the term \"${term}\".\n\n${context.expansion ? `This term is an abbreviation/acronym for: ${context.expansion}` : ''}\n\n${sourceContext}\n\n${context.contextText}\n\nGenerate keywords that:\n- Describe technologies, concepts, or domains related to this term\n- Are single words or hyphenated phrases\n- Would help identify when this term is relevant to a conversation\n- Include both specific and broader related concepts\n- Aim for 8-15 keywords\n\nOutput ONLY a comma-separated list with no explanation, no quotes, no extra text.\n\nExample for \"Kubernetes\": containers,orchestration,cloud-native,devops,docker,microservices,deployment,scaling,infrastructure,automation\nExample for \"OAuth\": authentication,authorization,security,api,tokens,identity,access-control,sso`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.analysisModel,\n reasoningLevel: 'low',\n }\n );\n\n const topics: string[] = response\n .split(',')\n .map((t: string) => t.trim().toLowerCase())\n .filter((t: string) => t.length > 0);\n\n const uniqueTopics = [...new Set(topics)];\n\n logger.debug('Generated %d topics', uniqueTopics.length);\n return uniqueTopics;\n\n } catch (error: any) {\n logger.error('Failed to generate topics: %s', error.message);\n return [];\n }\n };\n\n const suggestDomain = async (term: string, context: TermAnalysisContext): Promise<string | undefined> => {\n if (!isAvailable()) {\n logger.debug('Term domain suggestion not enabled');\n return context.suggestedDomain;\n }\n\n // If context already has a strong domain suggestion, use it\n if (context.suggestedDomain) {\n logger.debug('Using inferred domain: %s', context.suggestedDomain);\n return context.suggestedDomain;\n }\n\n logger.debug('Suggesting domain for term: %s', term);\n\n // Build rich prompt with source content if available\n let sourceContext = '';\n if (context.sourceContent) {\n sourceContext = `\\n\\nSource documentation:\\n---\\n${context.sourceContent}\\n---\\n`;\n }\n\n const prompt = `Suggest an appropriate domain/category for the term \"${term}\".\n\n${context.expansion ? `This term is an abbreviation/acronym for: ${context.expansion}` : ''}\n\n${sourceContext}\n\n${context.contextText}\n\nChoose ONE domain that best fits this term. Common domains include:\n- devops\n- engineering\n- cloud\n- database\n- security\n- business\n- product\n- finance\n- testing\n- infrastructure\n- automation\n- data-science\n- frontend\n- backend\n\nOutput ONLY the domain name (lowercase, hyphenated if needed) with no explanation or extra text.\n\nExample for \"Kubernetes\": devops\nExample for \"React\": frontend\nExample for \"PostgreSQL\": database`;\n\n try {\n const response = await OpenAI.createCompletion(\n [{ role: 'user', content: prompt }],\n { \n model: config.analysisModel,\n reasoningLevel: 'low',\n }\n );\n\n const domain = response.trim().toLowerCase();\n logger.debug('Suggested domain: %s', domain);\n return domain || undefined;\n\n } catch (error: any) {\n logger.error('Failed to suggest domain: %s', error.message);\n return undefined;\n }\n };\n\n const generateAll = async (term: string, context: TermAnalysisContext): Promise<TermSuggestions> => {\n if (!isAvailable()) {\n logger.debug('Smart assistance not available');\n return {\n soundsLike: [],\n topics: [],\n };\n }\n\n logger.debug('Generating all suggestions for term: %s', term);\n\n try {\n // Generate in parallel for efficiency\n const [soundsLike, description, topics, domain] = await Promise.all([\n config.termSoundsLikeOnAdd ? generateSoundsLike(term) : Promise.resolve([]),\n config.termDescriptionOnAdd ? generateDescription(term, context) : Promise.resolve(''),\n config.termTopicsOnAdd ? generateTopics(term, context) : Promise.resolve([]),\n suggestDomain(term, context),\n ]);\n\n return {\n soundsLike,\n description: description || undefined,\n topics,\n domain,\n };\n\n } catch (error: any) {\n logger.error('Failed to generate suggestions: %s', error.message);\n return {\n soundsLike: [],\n topics: [],\n };\n }\n };\n\n return {\n generateSoundsLike,\n generateDescription,\n generateTopics,\n suggestDomain,\n generateAll,\n isAvailable,\n };\n};\n\n/**\n * Helper for showing progress during async operations\n */\nexport const withProgress = async <T>(\n message: string,\n operation: () => Promise<T>,\n print: (text: string) => void\n): Promise<T> => {\n print(`[${message}...]`);\n try {\n const result = await operation();\n return result;\n } finally {\n // Progress complete\n }\n};\n"],"names":["OpenAI.createCompletion"],"mappings":"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"}
|
package/dist/term-context.js
CHANGED
|
@@ -5,17 +5,19 @@ import 'node:path';
|
|
|
5
5
|
import 'fs/promises';
|
|
6
6
|
import 'openai';
|
|
7
7
|
import 'fluent-ffmpeg';
|
|
8
|
+
import 'node:os';
|
|
9
|
+
import '@riotprompt/riotprompt';
|
|
10
|
+
import 'zod';
|
|
8
11
|
import 'node:fs';
|
|
9
12
|
import 'glob';
|
|
10
13
|
import 'node:crypto';
|
|
11
14
|
import 'node:fs/promises';
|
|
12
15
|
import 'html-to-text';
|
|
13
16
|
import 'commander';
|
|
17
|
+
import '@theunwalked/overcontext';
|
|
18
|
+
import '@redaksjon/context';
|
|
14
19
|
import 'js-yaml';
|
|
15
|
-
import 'fs';
|
|
16
|
-
import 'node:os';
|
|
17
20
|
import 'winston';
|
|
18
|
-
import '@riotprompt/riotprompt';
|
|
19
21
|
|
|
20
22
|
const create = (contextInstance) => {
|
|
21
23
|
const logger = getLogger();
|
|
@@ -141,6 +143,14 @@ const buildAnalysisContext = (term, expansion, fetchResult, internalContext) =>
|
|
|
141
143
|
contextText: parts.join("\n")
|
|
142
144
|
};
|
|
143
145
|
};
|
|
146
|
+
const enrichWithProjects = (context, topics, termContext) => {
|
|
147
|
+
const relatedProjects = termContext.findProjectsByTopic(topics);
|
|
148
|
+
return {
|
|
149
|
+
...context,
|
|
150
|
+
topics,
|
|
151
|
+
relatedProjects
|
|
152
|
+
};
|
|
153
|
+
};
|
|
144
154
|
|
|
145
|
-
export { buildAnalysisContext, create };
|
|
155
|
+
export { buildAnalysisContext, create, enrichWithProjects };
|
|
146
156
|
//# sourceMappingURL=term-context.js.map
|
package/dist/term-context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"term-context.js","sources":["../src/cli/term-context.ts"],"sourcesContent":["/**\n * Term Context\n * \n * Gathers internal contextual information for term analysis:\n * - Similar existing terms\n * - Related projects (based on topics)\n * - Domain inference\n */\n\nimport { getLogger } from '../logging';\nimport { Project, Term } from '../context/types';\nimport { ContextInstance } from '../context';\nimport * as ContentFetcher from './content-fetcher';\n\nexport interface InternalTermContext {\n similarTerms: Term[];\n relatedProjects: Project[];\n suggestedDomain?: string;\n}\n\nexport interface TermAnalysisContext {\n term: string;\n expansion?: string;\n \n // External content\n sourceContent?: string;\n sourceType?: 'url' | 'file' | 'directory' | 'github';\n sourceName?: string;\n \n // Internal context\n similarTerms: Term[];\n suggestedDomain?: string;\n \n // For project suggestions (populated after topic generation)\n topics?: string[];\n relatedProjects: Project[];\n \n // Formatted for LLM\n contextText: string;\n}\n\nexport interface TermContextInstance {\n gatherInternalContext(term: string, expansion?: string): InternalTermContext;\n findSimilarTerms(term: string): Term[];\n findProjectsByTopic(topics: string[]): Project[];\n inferDomain(term: string, expansion?: string): string | undefined;\n}\n\nexport const create = (contextInstance: ContextInstance): TermContextInstance => {\n const logger = getLogger();\n \n const findSimilarTerms = (term: string): Term[] => {\n const allTerms = contextInstance.getAllTerms();\n const termLower = term.toLowerCase();\n \n const similar = allTerms.filter((t: Term) => {\n const nameLower = t.name.toLowerCase();\n \n // Exact match (excluding self)\n if (nameLower === termLower) {\n return false;\n }\n \n // One contains the other\n if (nameLower.includes(termLower) || termLower.includes(nameLower)) {\n return true;\n }\n \n // Similar expansion\n if (t.expansion && termLower === t.expansion.toLowerCase()) {\n return true;\n }\n \n // Check sounds_like matches\n if (t.sounds_like?.some((s: string) => s.toLowerCase() === termLower)) {\n return true;\n }\n \n return false;\n });\n \n logger.debug('Found %d similar terms', similar.length);\n return similar.slice(0, 5); // Limit to top 5\n };\n \n const findProjectsByTopic = (topics: string[]): Project[] => {\n if (topics.length === 0) {\n return [];\n }\n \n const allProjects = contextInstance.getAllProjects();\n const topicsLower = topics.map(t => t.toLowerCase());\n \n // Score each project by topic overlap\n const scoredProjects = allProjects\n .map((project: Project) => {\n const projectTopics = project.classification.topics || [];\n const projectTopicsLower = projectTopics.map((t: string) => t.toLowerCase());\n \n // Count matching topics\n const matches = topicsLower.filter((topic: string) => \n projectTopicsLower.some((pt: string) => \n pt.includes(topic) || topic.includes(pt)\n )\n );\n \n return {\n project,\n score: matches.length,\n };\n })\n .filter((item: { project: Project; score: number }) => item.score > 0)\n .sort((a: { project: Project; score: number }, b: { project: Project; score: number }) => b.score - a.score);\n \n logger.debug('Found %d projects matching topics', scoredProjects.length);\n return scoredProjects.slice(0, 5).map((item: { project: Project; score: number }) => item.project);\n };\n \n const inferDomain = (term: string, expansion?: string): string | undefined => {\n const textToAnalyze = `${term} ${expansion || ''}`.toLowerCase();\n \n // Simple keyword-based domain inference\n const domainKeywords: Record<string, string[]> = {\n 'devops': ['docker', 'kubernetes', 'k8s', 'ci', 'cd', 'deployment', 'container', 'orchestration', 'jenkins', 'gitlab', 'github-actions'],\n 'engineering': ['algorithm', 'data structure', 'api', 'framework', 'library', 'code', 'programming', 'software'],\n 'cloud': ['aws', 'azure', 'gcp', 'cloud', 's3', 'lambda', 'ec2', 'cloudformation', 'terraform'],\n 'database': ['sql', 'nosql', 'database', 'postgres', 'mongo', 'redis', 'query', 'orm', 'schema'],\n 'security': ['auth', 'encryption', 'certificate', 'ssl', 'tls', 'security', 'vault', 'oauth', 'jwt'],\n 'business': ['roi', 'kpi', 'okr', 'revenue', 'cost', 'budget', 'stakeholder', 'metrics'],\n 'product': ['user', 'feature', 'roadmap', 'requirement', 'specification', 'ux', 'ui', 'design'],\n 'finance': ['accounting', 'invoice', 'payment', 'transaction', 'ledger', 'revenue', 'billing'],\n 'testing': ['test', 'qa', 'quality', 'coverage', 'mock', 'integration', 'unit', 'e2e'],\n 'frontend': ['react', 'vue', 'angular', 'javascript', 'typescript', 'css', 'html', 'component'],\n 'backend': ['api', 'server', 'microservice', 'endpoint', 'rest', 'graphql', 'grpc'],\n 'infrastructure': ['server', 'network', 'load-balancer', 'dns', 'proxy', 'infrastructure', 'platform'],\n };\n \n for (const [domain, keywords] of Object.entries(domainKeywords)) {\n if (keywords.some(keyword => textToAnalyze.includes(keyword))) {\n logger.debug('Inferred domain: %s', domain);\n return domain;\n }\n }\n \n return undefined;\n };\n \n const gatherInternalContext = (term: string, expansion?: string): InternalTermContext => {\n logger.debug('Gathering internal context for term: %s', term);\n \n return {\n similarTerms: findSimilarTerms(term),\n relatedProjects: [], // Populated after topic generation\n suggestedDomain: inferDomain(term, expansion),\n };\n };\n \n return {\n gatherInternalContext,\n findSimilarTerms,\n findProjectsByTopic,\n inferDomain,\n };\n};\n\n/**\n * Build complete context for LLM analysis\n * Combines external content (from URL/file) with internal context (similar terms, projects)\n */\nexport const buildAnalysisContext = (\n term: string,\n expansion: string | undefined,\n fetchResult: ContentFetcher.FetchResult | undefined,\n internalContext: InternalTermContext\n): TermAnalysisContext => {\n const parts: string[] = [];\n \n parts.push(`Term: ${term}`);\n \n if (expansion) {\n parts.push(`Expansion: ${expansion}`);\n }\n \n // Add source content if available\n if (fetchResult?.success && fetchResult.content) {\n parts.push('\\n--- Source Content ---');\n parts.push(fetchResult.content.substring(0, 5000)); // Limit for context\n parts.push('--- End Source Content ---\\n');\n }\n \n // Add suggested domain\n if (internalContext.suggestedDomain) {\n parts.push(`Suggested Domain: ${internalContext.suggestedDomain}`);\n }\n \n // Add similar terms\n if (internalContext.similarTerms.length > 0) {\n parts.push('\\nSimilar existing terms:');\n internalContext.similarTerms.forEach(t => {\n parts.push(`- ${t.name}${t.expansion ? ` (${t.expansion})` : ''}: ${t.description || 'No description'}`);\n if (t.domain) {\n parts.push(` Domain: ${t.domain}`);\n }\n if (t.topics && t.topics.length > 0) {\n parts.push(` Topics: ${t.topics.join(', ')}`);\n }\n });\n }\n \n return {\n term,\n expansion,\n sourceContent: fetchResult?.content,\n sourceType: fetchResult?.sourceType,\n sourceName: fetchResult?.sourceName,\n similarTerms: internalContext.similarTerms,\n suggestedDomain: internalContext.suggestedDomain,\n relatedProjects: [],\n contextText: parts.join('\\n'),\n };\n};\n\n/**\n * Enrich context with project suggestions after topic generation\n */\nexport const enrichWithProjects = (\n context: TermAnalysisContext,\n topics: string[],\n termContext: TermContextInstance\n): TermAnalysisContext => {\n const relatedProjects = termContext.findProjectsByTopic(topics);\n \n return {\n ...context,\n topics,\n relatedProjects,\n };\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAgDO,MAAM,MAAA,GAAS,CAAC,eAAA,KAA0D;AAC7E,EAAA,MAAM,SAAS,SAAA,EAAU;AAEzB,EAAA,MAAM,gBAAA,GAAmB,CAAC,IAAA,KAAyB;AAC/C,IAAA,MAAM,QAAA,GAAW,gBAAgB,WAAA,EAAY;AAC7C,IAAA,MAAM,SAAA,GAAY,KAAK,WAAA,EAAY;AAEnC,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAY;AACzC,MAAA,MAAM,SAAA,GAAY,CAAA,CAAE,IAAA,CAAK,WAAA,EAAY;AAGrC,MAAA,IAAI,cAAc,SAAA,EAAW;AACzB,QAAA,OAAO,KAAA;AAAA,MACX;AAGA,MAAA,IAAI,UAAU,QAAA,CAAS,SAAS,KAAK,SAAA,CAAU,QAAA,CAAS,SAAS,CAAA,EAAG;AAChE,QAAA,OAAO,IAAA;AAAA,MACX;AAGA,MAAA,IAAI,EAAE,SAAA,IAAa,SAAA,KAAc,CAAA,CAAE,SAAA,CAAU,aAAY,EAAG;AACxD,QAAA,OAAO,IAAA;AAAA,MACX;AAGA,MAAA,IAAI,CAAA,CAAE,aAAa,IAAA,CAAK,CAAC,MAAc,CAAA,CAAE,WAAA,EAAY,KAAM,SAAS,CAAA,EAAG;AACnE,QAAA,OAAO,IAAA;AAAA,MACX;AAEA,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,KAAA,CAAM,wBAAA,EAA0B,OAAA,CAAQ,MAAM,CAAA;AACrD,IAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AAAA,EAC7B,CAAA;AAEA,EAAA,MAAM,mBAAA,GAAsB,CAAC,MAAA,KAAgC;AACzD,IAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACrB,MAAA,OAAO,EAAC;AAAA,IACZ;AAEA,IAAA,MAAM,WAAA,GAAc,gBAAgB,cAAA,EAAe;AACnD,IAAA,MAAM,cAAc,MAAA,CAAO,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,aAAa,CAAA;AAGnD,IAAA,MAAM,cAAA,GAAiB,WAAA,CAClB,GAAA,CAAI,CAAC,OAAA,KAAqB;AACvB,MAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,cAAA,CAAe,MAAA,IAAU,EAAC;AACxD,MAAA,MAAM,qBAAqB,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,KAAc,CAAA,CAAE,aAAa,CAAA;AAG3E,MAAA,MAAM,UAAU,WAAA,CAAY,MAAA;AAAA,QAAO,CAAC,UAChC,kBAAA,CAAmB,IAAA;AAAA,UAAK,CAAC,OACrB,EAAA,CAAG,QAAA,CAAS,KAAK,CAAA,IAAK,KAAA,CAAM,SAAS,EAAE;AAAA;AAC3C,OACJ;AAEA,MAAA,OAAO;AAAA,QACH,OAAA;AAAA,QACA,OAAO,OAAA,CAAQ;AAAA,OACnB;AAAA,IACJ,CAAC,CAAA,CACA,MAAA,CAAO,CAAC,IAAA,KAA8C,KAAK,KAAA,GAAQ,CAAC,CAAA,CACpE,IAAA,CAAK,CAAC,CAAA,EAAwC,CAAA,KAA2C,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AAE/G,IAAA,MAAA,CAAO,KAAA,CAAM,mCAAA,EAAqC,cAAA,CAAe,MAAM,CAAA;AACvE,IAAA,OAAO,cAAA,CAAe,MAAM,CAAA,EAAG,CAAC,EAAE,GAAA,CAAI,CAAC,IAAA,KAA8C,IAAA,CAAK,OAAO,CAAA;AAAA,EACrG,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,IAAA,EAAc,SAAA,KAA2C;AAC1E,IAAA,MAAM,gBAAgB,CAAA,EAAG,IAAI,IAAI,SAAA,IAAa,EAAE,GAAG,WAAA,EAAY;AAG/D,IAAA,MAAM,cAAA,GAA2C;AAAA,MAC7C,QAAA,EAAU,CAAC,QAAA,EAAU,YAAA,EAAc,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,YAAA,EAAc,WAAA,EAAa,eAAA,EAAiB,SAAA,EAAW,QAAA,EAAU,gBAAgB,CAAA;AAAA,MACvI,aAAA,EAAe,CAAC,WAAA,EAAa,gBAAA,EAAkB,OAAO,WAAA,EAAa,SAAA,EAAW,MAAA,EAAQ,aAAA,EAAe,UAAU,CAAA;AAAA,MAC/G,OAAA,EAAS,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,SAAS,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,gBAAA,EAAkB,WAAW,CAAA;AAAA,MAC9F,UAAA,EAAY,CAAC,KAAA,EAAO,OAAA,EAAS,UAAA,EAAY,YAAY,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO,QAAQ,CAAA;AAAA,MAC/F,UAAA,EAAY,CAAC,MAAA,EAAQ,YAAA,EAAc,aAAA,EAAe,OAAO,KAAA,EAAO,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,KAAK,CAAA;AAAA,MACnG,UAAA,EAAY,CAAC,KAAA,EAAO,KAAA,EAAO,OAAO,SAAA,EAAW,MAAA,EAAQ,QAAA,EAAU,aAAA,EAAe,SAAS,CAAA;AAAA,MACvF,SAAA,EAAW,CAAC,MAAA,EAAQ,SAAA,EAAW,WAAW,aAAA,EAAe,eAAA,EAAiB,IAAA,EAAM,IAAA,EAAM,QAAQ,CAAA;AAAA,MAC9F,SAAA,EAAW,CAAC,YAAA,EAAc,SAAA,EAAW,WAAW,aAAA,EAAe,QAAA,EAAU,WAAW,SAAS,CAAA;AAAA,MAC7F,SAAA,EAAW,CAAC,MAAA,EAAQ,IAAA,EAAM,WAAW,UAAA,EAAY,MAAA,EAAQ,aAAA,EAAe,MAAA,EAAQ,KAAK,CAAA;AAAA,MACrF,UAAA,EAAY,CAAC,OAAA,EAAS,KAAA,EAAO,WAAW,YAAA,EAAc,YAAA,EAAc,KAAA,EAAO,MAAA,EAAQ,WAAW,CAAA;AAAA,MAC9F,SAAA,EAAW,CAAC,KAAA,EAAO,QAAA,EAAU,gBAAgB,UAAA,EAAY,MAAA,EAAQ,WAAW,MAAM,CAAA;AAAA,MAClF,gBAAA,EAAkB,CAAC,QAAA,EAAU,SAAA,EAAW,iBAAiB,KAAA,EAAO,OAAA,EAAS,kBAAkB,UAAU;AAAA,KACzG;AAEA,IAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,QAAQ,KAAK,MAAA,CAAO,OAAA,CAAQ,cAAc,CAAA,EAAG;AAC7D,MAAA,IAAI,SAAS,IAAA,CAAK,CAAA,OAAA,KAAW,cAAc,QAAA,CAAS,OAAO,CAAC,CAAA,EAAG;AAC3D,QAAA,MAAA,CAAO,KAAA,CAAM,uBAAuB,MAAM,CAAA;AAC1C,QAAA,OAAO,MAAA;AAAA,MACX;AAAA,IACJ;AAEA,IAAA,OAAO,MAAA;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,qBAAA,GAAwB,CAAC,IAAA,EAAc,SAAA,KAA4C;AACrF,IAAA,MAAA,CAAO,KAAA,CAAM,2CAA2C,IAAI,CAAA;AAE5D,IAAA,OAAO;AAAA,MACH,YAAA,EAAc,iBAAiB,IAAI,CAAA;AAAA,MACnC,iBAAiB,EAAC;AAAA;AAAA,MAClB,eAAA,EAAiB,WAAA,CAAY,IAAA,EAAM,SAAS;AAAA,KAChD;AAAA,EACJ,CAAA;AAEA,EAAA,OAAO;AAAA,IACH,qBAAA;AAAA,IACA,gBAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACJ;AACJ;AAMO,MAAM,oBAAA,GAAuB,CAChC,IAAA,EACA,SAAA,EACA,aACA,eAAA,KACsB;AACtB,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,MAAA,EAAS,IAAI,CAAA,CAAE,CAAA;AAE1B,EAAA,IAAI,SAAA,EAAW;AACX,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,WAAA,EAAc,SAAS,CAAA,CAAE,CAAA;AAAA,EACxC;AAGA,EAAA,IAAI,WAAA,EAAa,OAAA,IAAW,WAAA,CAAY,OAAA,EAAS;AAC7C,IAAA,KAAA,CAAM,KAAK,0BAA0B,CAAA;AACrC,IAAA,KAAA,CAAM,KAAK,WAAA,CAAY,OAAA,CAAQ,SAAA,CAAU,CAAA,EAAG,GAAI,CAAC,CAAA;AACjD,IAAA,KAAA,CAAM,KAAK,8BAA8B,CAAA;AAAA,EAC7C;AAGA,EAAA,IAAI,gBAAgB,eAAA,EAAiB;AACjC,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,kBAAA,EAAqB,eAAA,CAAgB,eAAe,CAAA,CAAE,CAAA;AAAA,EACrE;AAGA,EAAA,IAAI,eAAA,CAAgB,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AACzC,IAAA,KAAA,CAAM,KAAK,2BAA2B,CAAA;AACtC,IAAA,eAAA,CAAgB,YAAA,CAAa,QAAQ,CAAA,CAAA,KAAK;AACtC,MAAA,KAAA,CAAM,KAAK,CAAA,EAAA,EAAK,CAAA,CAAE,IAAI,CAAA,EAAG,EAAE,SAAA,GAAY,CAAA,EAAA,EAAK,CAAA,CAAE,SAAS,MAAM,EAAE,CAAA,EAAA,EAAK,CAAA,CAAE,WAAA,IAAe,gBAAgB,CAAA,CAAE,CAAA;AACvG,MAAA,IAAI,EAAE,MAAA,EAAQ;AACV,QAAA,KAAA,CAAM,IAAA,CAAK,CAAA,UAAA,EAAa,CAAA,CAAE,MAAM,CAAA,CAAE,CAAA;AAAA,MACtC;AACA,MAAA,IAAI,CAAA,CAAE,MAAA,IAAU,CAAA,CAAE,MAAA,CAAO,SAAS,CAAA,EAAG;AACjC,QAAA,KAAA,CAAM,KAAK,CAAA,UAAA,EAAa,CAAA,CAAE,OAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,MACjD;AAAA,IACJ,CAAC,CAAA;AAAA,EACL;AAEA,EAAA,OAAO;AAAA,IACH,IAAA;AAAA,IACA,SAAA;AAAA,IACA,eAAe,WAAA,EAAa,OAAA;AAAA,IAC5B,YAAY,WAAA,EAAa,UAAA;AAAA,IACzB,YAAY,WAAA,EAAa,UAAA;AAAA,IACzB,cAAc,eAAA,CAAgB,YAAA;AAAA,IAC9B,iBAAiB,eAAA,CAAgB,eAAA;AAAA,IACjC,iBAAiB,EAAC;AAAA,IAClB,WAAA,EAAa,KAAA,CAAM,IAAA,CAAK,IAAI;AAAA,GAChC;AACJ;;;;"}
|
|
1
|
+
{"version":3,"file":"term-context.js","sources":["../src/cli/term-context.ts"],"sourcesContent":["/**\n * Term Context\n * \n * Gathers internal contextual information for term analysis:\n * - Similar existing terms\n * - Related projects (based on topics)\n * - Domain inference\n */\n\nimport { getLogger } from '../logging';\nimport { Project, Term } from '../context/types';\nimport { ContextInstance } from '../context';\nimport * as ContentFetcher from './content-fetcher';\n\nexport interface InternalTermContext {\n similarTerms: Term[];\n relatedProjects: Project[];\n suggestedDomain?: string;\n}\n\nexport interface TermAnalysisContext {\n term: string;\n expansion?: string;\n \n // External content\n sourceContent?: string;\n sourceType?: 'url' | 'file' | 'directory' | 'github';\n sourceName?: string;\n \n // Internal context\n similarTerms: Term[];\n suggestedDomain?: string;\n \n // For project suggestions (populated after topic generation)\n topics?: string[];\n relatedProjects: Project[];\n \n // Formatted for LLM\n contextText: string;\n}\n\nexport interface TermContextInstance {\n gatherInternalContext(term: string, expansion?: string): InternalTermContext;\n findSimilarTerms(term: string): Term[];\n findProjectsByTopic(topics: string[]): Project[];\n inferDomain(term: string, expansion?: string): string | undefined;\n}\n\nexport const create = (contextInstance: ContextInstance): TermContextInstance => {\n const logger = getLogger();\n \n const findSimilarTerms = (term: string): Term[] => {\n const allTerms = contextInstance.getAllTerms();\n const termLower = term.toLowerCase();\n \n const similar = allTerms.filter((t: Term) => {\n const nameLower = t.name.toLowerCase();\n \n // Exact match (excluding self)\n if (nameLower === termLower) {\n return false;\n }\n \n // One contains the other\n if (nameLower.includes(termLower) || termLower.includes(nameLower)) {\n return true;\n }\n \n // Similar expansion\n if (t.expansion && termLower === t.expansion.toLowerCase()) {\n return true;\n }\n \n // Check sounds_like matches\n if (t.sounds_like?.some((s: string) => s.toLowerCase() === termLower)) {\n return true;\n }\n \n return false;\n });\n \n logger.debug('Found %d similar terms', similar.length);\n return similar.slice(0, 5); // Limit to top 5\n };\n \n const findProjectsByTopic = (topics: string[]): Project[] => {\n if (topics.length === 0) {\n return [];\n }\n \n const allProjects = contextInstance.getAllProjects();\n const topicsLower = topics.map(t => t.toLowerCase());\n \n // Score each project by topic overlap\n const scoredProjects = allProjects\n .map((project: Project) => {\n const projectTopics = project.classification.topics || [];\n const projectTopicsLower = projectTopics.map((t: string) => t.toLowerCase());\n \n // Count matching topics\n const matches = topicsLower.filter((topic: string) => \n projectTopicsLower.some((pt: string) => \n pt.includes(topic) || topic.includes(pt)\n )\n );\n \n return {\n project,\n score: matches.length,\n };\n })\n .filter((item: { project: Project; score: number }) => item.score > 0)\n .sort((a: { project: Project; score: number }, b: { project: Project; score: number }) => b.score - a.score);\n \n logger.debug('Found %d projects matching topics', scoredProjects.length);\n return scoredProjects.slice(0, 5).map((item: { project: Project; score: number }) => item.project);\n };\n \n const inferDomain = (term: string, expansion?: string): string | undefined => {\n const textToAnalyze = `${term} ${expansion || ''}`.toLowerCase();\n \n // Simple keyword-based domain inference\n const domainKeywords: Record<string, string[]> = {\n 'devops': ['docker', 'kubernetes', 'k8s', 'ci', 'cd', 'deployment', 'container', 'orchestration', 'jenkins', 'gitlab', 'github-actions'],\n 'engineering': ['algorithm', 'data structure', 'api', 'framework', 'library', 'code', 'programming', 'software'],\n 'cloud': ['aws', 'azure', 'gcp', 'cloud', 's3', 'lambda', 'ec2', 'cloudformation', 'terraform'],\n 'database': ['sql', 'nosql', 'database', 'postgres', 'mongo', 'redis', 'query', 'orm', 'schema'],\n 'security': ['auth', 'encryption', 'certificate', 'ssl', 'tls', 'security', 'vault', 'oauth', 'jwt'],\n 'business': ['roi', 'kpi', 'okr', 'revenue', 'cost', 'budget', 'stakeholder', 'metrics'],\n 'product': ['user', 'feature', 'roadmap', 'requirement', 'specification', 'ux', 'ui', 'design'],\n 'finance': ['accounting', 'invoice', 'payment', 'transaction', 'ledger', 'revenue', 'billing'],\n 'testing': ['test', 'qa', 'quality', 'coverage', 'mock', 'integration', 'unit', 'e2e'],\n 'frontend': ['react', 'vue', 'angular', 'javascript', 'typescript', 'css', 'html', 'component'],\n 'backend': ['api', 'server', 'microservice', 'endpoint', 'rest', 'graphql', 'grpc'],\n 'infrastructure': ['server', 'network', 'load-balancer', 'dns', 'proxy', 'infrastructure', 'platform'],\n };\n \n for (const [domain, keywords] of Object.entries(domainKeywords)) {\n if (keywords.some(keyword => textToAnalyze.includes(keyword))) {\n logger.debug('Inferred domain: %s', domain);\n return domain;\n }\n }\n \n return undefined;\n };\n \n const gatherInternalContext = (term: string, expansion?: string): InternalTermContext => {\n logger.debug('Gathering internal context for term: %s', term);\n \n return {\n similarTerms: findSimilarTerms(term),\n relatedProjects: [], // Populated after topic generation\n suggestedDomain: inferDomain(term, expansion),\n };\n };\n \n return {\n gatherInternalContext,\n findSimilarTerms,\n findProjectsByTopic,\n inferDomain,\n };\n};\n\n/**\n * Build complete context for LLM analysis\n * Combines external content (from URL/file) with internal context (similar terms, projects)\n */\nexport const buildAnalysisContext = (\n term: string,\n expansion: string | undefined,\n fetchResult: ContentFetcher.FetchResult | undefined,\n internalContext: InternalTermContext\n): TermAnalysisContext => {\n const parts: string[] = [];\n \n parts.push(`Term: ${term}`);\n \n if (expansion) {\n parts.push(`Expansion: ${expansion}`);\n }\n \n // Add source content if available\n if (fetchResult?.success && fetchResult.content) {\n parts.push('\\n--- Source Content ---');\n parts.push(fetchResult.content.substring(0, 5000)); // Limit for context\n parts.push('--- End Source Content ---\\n');\n }\n \n // Add suggested domain\n if (internalContext.suggestedDomain) {\n parts.push(`Suggested Domain: ${internalContext.suggestedDomain}`);\n }\n \n // Add similar terms\n if (internalContext.similarTerms.length > 0) {\n parts.push('\\nSimilar existing terms:');\n internalContext.similarTerms.forEach(t => {\n parts.push(`- ${t.name}${t.expansion ? ` (${t.expansion})` : ''}: ${t.description || 'No description'}`);\n if (t.domain) {\n parts.push(` Domain: ${t.domain}`);\n }\n if (t.topics && t.topics.length > 0) {\n parts.push(` Topics: ${t.topics.join(', ')}`);\n }\n });\n }\n \n return {\n term,\n expansion,\n sourceContent: fetchResult?.content,\n sourceType: fetchResult?.sourceType,\n sourceName: fetchResult?.sourceName,\n similarTerms: internalContext.similarTerms,\n suggestedDomain: internalContext.suggestedDomain,\n relatedProjects: [],\n contextText: parts.join('\\n'),\n };\n};\n\n/**\n * Enrich context with project suggestions after topic generation\n */\nexport const enrichWithProjects = (\n context: TermAnalysisContext,\n topics: string[],\n termContext: TermContextInstance\n): TermAnalysisContext => {\n const relatedProjects = termContext.findProjectsByTopic(topics);\n \n return {\n ...context,\n topics,\n relatedProjects,\n };\n};\n"],"names":[],"mappings":"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"}
|