@redaksjon/kronologi 0.0.4

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 (47) hide show
  1. package/.kodrdriv/config.yaml +10 -0
  2. package/.kodrdriv/context/content.md +1 -0
  3. package/.mindshahn/config.yaml +1 -0
  4. package/.mindshahn/emails-summary/config.yaml +37 -0
  5. package/.mindshahn/emails-summary/instructions.md +37 -0
  6. package/.mindshahn/emails-summary/persona.md +13 -0
  7. package/.nvmrc +2 -0
  8. package/LICENSE.md +65 -0
  9. package/README.md +92 -0
  10. package/dist/analysis/configLoader.js +86 -0
  11. package/dist/analysis/configLoader.js.map +1 -0
  12. package/dist/analysis/file.js +54 -0
  13. package/dist/analysis/file.js.map +1 -0
  14. package/dist/analysis/inputs.js +43 -0
  15. package/dist/analysis/inputs.js.map +1 -0
  16. package/dist/analysis/prompt.js +169 -0
  17. package/dist/analysis/prompt.js.map +1 -0
  18. package/dist/analysis/section.js +43 -0
  19. package/dist/analysis/section.js.map +1 -0
  20. package/dist/arguments.js +143 -0
  21. package/dist/arguments.js.map +1 -0
  22. package/dist/constants.js +49 -0
  23. package/dist/constants.js.map +1 -0
  24. package/dist/error/ArgumentError.js +26 -0
  25. package/dist/error/ArgumentError.js.map +1 -0
  26. package/dist/kronologi.js +123 -0
  27. package/dist/kronologi.js.map +1 -0
  28. package/dist/logging.js +46 -0
  29. package/dist/logging.js.map +1 -0
  30. package/dist/main.js +6 -0
  31. package/dist/main.js.map +1 -0
  32. package/dist/output.js +15 -0
  33. package/dist/output.js.map +1 -0
  34. package/dist/run.js +28 -0
  35. package/dist/run.js.map +1 -0
  36. package/dist/types.js +23 -0
  37. package/dist/types.js.map +1 -0
  38. package/dist/util/dates.js +14 -0
  39. package/dist/util/dates.js.map +1 -0
  40. package/dist/util/storage.js +126 -0
  41. package/dist/util/storage.js.map +1 -0
  42. package/eslint.config.mjs +82 -0
  43. package/nodemon.json +14 -0
  44. package/package.json +76 -0
  45. package/tsconfig.tsbuildinfo +1 -0
  46. package/vite.config.ts +96 -0
  47. package/vitest.config.ts +28 -0
@@ -0,0 +1,10 @@
1
+ verbose: false
2
+ model: gpt-4o
3
+ contextDirectories:
4
+ - .gitcarve/context
5
+ commit:
6
+ cached: true
7
+ sendit: true
8
+ release:
9
+ from: main
10
+ to: HEAD
@@ -0,0 +1 @@
1
+ Mindshahn is a way to review and summarize files.
@@ -0,0 +1 @@
1
+ model: gpt-4o
@@ -0,0 +1,37 @@
1
+ model: gpt-4o
2
+ temperature: 0.7
3
+ maxCompletionTokens: 4096
4
+ parameters:
5
+ year:
6
+ type: number
7
+ description: The year to summarize
8
+ required: true
9
+ month:
10
+ type: number
11
+ description: The month to summarize
12
+ required: true
13
+ context:
14
+ people:
15
+ directory: ./people
16
+ projects:
17
+ directory: ./projects
18
+ content:
19
+ emails:
20
+ directory: email
21
+ pattern: "**/*.txt"
22
+ output:
23
+ summary:
24
+ type: summary
25
+ format: markdown
26
+ name: Emails Summary
27
+ pattern: "emails-summary.md"
28
+ completion:
29
+ type: completion
30
+ format: json
31
+ name: Emails Summary Completion
32
+ pattern: "emails-summary.completion.json"
33
+ inputs:
34
+ type: inputs
35
+ format: json
36
+ name: Emails Summary Inputs
37
+ pattern: "emails-summary.inputs.json"
@@ -0,0 +1,37 @@
1
+ Please analyze the following monthly email content and create a summary of the emails received and sent in the month {{parameters.month}}/{{parameters.year}}.
2
+
3
+ Use the provided context to enhance the analysis.
4
+
5
+ The email data will be presented as text files that adhere to the following structure:
6
+
7
+ Subject: <message subject>
8
+ Date: <date received or sent>
9
+ From: <from email address>
10
+ To: <one or more recipients>
11
+
12
+ <message body>
13
+
14
+
15
+ The output format should adhere to the following Markdown:
16
+
17
+ # Email Summary for <month> <year>
18
+
19
+ ## Email Summary for <owner>>/<reposiory> in <month> <year>
20
+ Total emails in <owner>>/<reposiory> for <month> <year>: <total emails>
21
+
22
+ - Emails Received: <number of emails received>
23
+ - Emails Sent: <number of emails sent>
24
+
25
+ <content generated>
26
+
27
+ EVERY header must contain the terms "Emails in <month> <year>" - for example, if there is a header for an "Overview" it should be "Overview of Emails in <month> <year>". Or if there is a header, "Analysis of Technology Trends" it should be "Analysis of Technology Trends in Emails in <month> <year>". It is important for the headers to be explicit because the output may be combined with data from other months.
28
+
29
+ In the context, there will be two types of files - files from "received" are the emails that were received, and emails in "sent" are the emails that were sent.
30
+
31
+ # Guidance for Analysis
32
+
33
+ This analysis is looking for trends related to the activity for issues in the array of projects that have been presented.
34
+
35
+ Try to identify relationships between emails and identify important emails senders.
36
+
37
+
@@ -0,0 +1,13 @@
1
+ You are an expert at analyzing documents and creating summaries.
2
+
3
+ Please analyze the provided monthly content and create a summary of key topics and themes discussed.
4
+
5
+ When generating a summary, don't put too much context into the summary.
6
+
7
+ For example, don't reference the founder's name or talk about about the goals for that person.
8
+
9
+ Also, assume that the person reading this summary has a basic understanding of what the projects are.
10
+
11
+ This summary is for the team.
12
+
13
+ I really am not looking for useless buzzwords and sterile corporate report. Instead what I'm looking for is more direct and actionable information.
package/.nvmrc ADDED
@@ -0,0 +1,2 @@
1
+ 20
2
+
package/LICENSE.md ADDED
@@ -0,0 +1,65 @@
1
+ Copyright 2025 Simran Jafari
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
15
+ Apache License
16
+ Version 2.0, January 2004
17
+ http://www.apache.org/licenses/
18
+
19
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
20
+
21
+ 1. Definitions.
22
+
23
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
24
+
25
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
26
+
27
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
28
+
29
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
30
+
31
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
32
+
33
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
36
+
37
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
38
+
39
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
40
+
41
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
42
+
43
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
44
+
45
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
46
+
47
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
48
+
49
+ You must give any other recipients of the Work or Derivative Works a copy of this License; and
50
+ You must cause any modified files to carry prominent notices stating that You changed the files; and
51
+ You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
52
+ If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
53
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
54
+
55
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
56
+
57
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
58
+
59
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
60
+
61
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
62
+
63
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
64
+
65
+ END OF TERMS AND CONDITIONS
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # Kronologi
2
+
3
+ Kronologi is a powerful tool for generating intelligent monthly summaries from activity and context. It uses AI to analyze and synthesize information, making it easier to create comprehensive and meaningful documentation for your work.
4
+
5
+ ## Features
6
+
7
+ - Generate intelligent release notes and change logs
8
+ - Analyze Git history with customizable time periods
9
+ - AI-powered summarization of code changes
10
+ - Flexible configuration options
11
+ - Support for multiple output formats
12
+ - Context-aware analysis
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install -g @redaksjon/kronologi
18
+ ```
19
+
20
+ ## Command Line Usage
21
+
22
+ Kronologi provides a rich set of command line options to customize its behavior:
23
+
24
+ ### Required Arguments
25
+
26
+ - `<summaryType>`: Type of summary to generate
27
+ - `<year>`: Year for the summary (must be between 1900 and 2100)
28
+ - `<month>`: Month for the summary (1-12)
29
+
30
+ ### Optional Arguments
31
+
32
+ - `[historyMonths]`: Number of months of history to include (default: 1)
33
+ - `[summaryMonths]`: Number of months to summarize (default: 1)
34
+
35
+ ### Options
36
+
37
+ - `--dry-run`: Perform a dry run without saving files (default: false)
38
+ - `--verbose`: Enable verbose logging (default: false)
39
+ - `--debug`: Enable debug logging (default: false)
40
+ - `--timezone <timezone>`: Timezone for date calculations (default: system timezone)
41
+ - `--openai-api-key <openaiApiKey>`: OpenAI API key (can also be set via OPENAI_API_KEY environment variable)
42
+ - `--model <model>`: OpenAI model to use (default: gpt-4)
43
+ - `--config-dir <configDir>`: Config directory (default: ./config)
44
+ - `--context-directory <contextDirectory>`: Directory containing context files to be included in prompts (default: ./context)
45
+ - `--activity-directory <activityDirectory>`: Directory containing activity files to be included in prompts (default: ./activity)
46
+ - `--summary-directory <summaryDirectory>`: Directory containing summary files to be included in prompts (default: ./summary)
47
+ - `--replace`: Replace existing summary files if they exist (default: false)
48
+ - `--version`: Display version information
49
+
50
+ ### Examples
51
+
52
+ 1. Generate a summary for January 2024:
53
+ ```bash
54
+ kronologi release-notes 2024 1
55
+ ```
56
+
57
+ 2. Generate a summary with 3 months of history:
58
+ ```bash
59
+ kronologi release-notes 2024 1 3
60
+ ```
61
+
62
+ 3. Generate a summary with custom directories:
63
+ ```bash
64
+ kronologi release-notes 2024 1 --config-dir ./my-config --context-directory ./my-context
65
+ ```
66
+
67
+ 4. Generate a summary with a specific timezone:
68
+ ```bash
69
+ kronologi release-notes 2024 1 --timezone America/New_York
70
+ ```
71
+
72
+ ## How It Works
73
+
74
+ Kronologi analyzes your Git history and related content using a sophisticated analysis engine that:
75
+
76
+ 1. Reads and processes configuration files from the specified config directory
77
+ 2. Gathers context from various sources including:
78
+ - Static context files
79
+ - Historical context from previous summaries
80
+ - Activity files from the specified period
81
+ 3. Processes and combines this information using AI to generate meaningful summaries
82
+ 4. Outputs the results in the specified format
83
+
84
+ The analysis engine is highly configurable, allowing you to:
85
+ - Define custom parameters and their types
86
+ - Specify which context sources to include
87
+ - Control the temperature and token limits for AI processing
88
+ - Customize the output format and structure
89
+
90
+ ## Name Origin
91
+
92
+ The name "Kronologi" comes from the Norwegian word for "chronology" or "timeline", reflecting its purpose of creating temporal summaries and documentation of your work over time.
@@ -0,0 +1,86 @@
1
+ import { join } from 'path';
2
+ import { load } from 'js-yaml';
3
+ import { JOB_CONFIG_FILE, DEFAULT_CHARACTER_ENCODING } from '../constants.js';
4
+ import { getLogger } from '../logging.js';
5
+ import { create } from '../util/storage.js';
6
+
7
+ /**
8
+ * Creates and validates a configuration from the config file
9
+ */ const createConfig = async (jobName, configPath)=>{
10
+ const logger = getLogger();
11
+ const storage = create({
12
+ log: logger.debug
13
+ });
14
+ // Read and parse YAML config
15
+ const config = load(await storage.readFile(join(configPath, JOB_CONFIG_FILE), DEFAULT_CHARACTER_ENCODING));
16
+ config.name = jobName;
17
+ // Validate required config properties
18
+ if (!config.model) {
19
+ throw new Error(`Missing required config property in ${configPath}/config.yaml: model`);
20
+ }
21
+ // Validate each context directory has required properties
22
+ for (const [key, value] of Object.entries(config.context)){
23
+ // Validate required name property
24
+ if (!value.name) {
25
+ throw new Error(`Missing required name property for context ${key} in ${configPath}/config.yaml`);
26
+ }
27
+ // Validate based on context type
28
+ switch(value.type){
29
+ case 'static':
30
+ if (!value.directory) {
31
+ throw new Error(`Missing required directory property for ${value.type} context ${key} in ${configPath}/config.yaml`);
32
+ }
33
+ break;
34
+ case 'history':
35
+ if (!value.from) {
36
+ throw new Error(`Missing required 'from' property for history context ${key} in ${configPath}/config.yaml`);
37
+ }
38
+ // months is optional but must be a number if provided
39
+ if (value.months && typeof value.months !== 'number' && !(typeof value.months === 'string' && /^\${.*}$/.test(value.months))) {
40
+ throw new Error(`Invalid months property for history context ${key} in ${configPath}/config.yaml - must be a number or parameter reference`);
41
+ }
42
+ // If months is a parameter reference, validate it points to a valid numeric parameter
43
+ if (typeof value.months === 'string' && /^\${parameters\.(.*)}$/.test(value.months)) {
44
+ var _config_parameters;
45
+ const paramMatch = value.months.match(/^\${parameters\.(.*)}$/);
46
+ const paramName = paramMatch[1];
47
+ const param = (_config_parameters = config.parameters) === null || _config_parameters === void 0 ? void 0 : _config_parameters[paramName];
48
+ if (!param) {
49
+ throw new Error(`Parameter ${paramName} referenced in months for history context ${key} not found in config parameters`);
50
+ }
51
+ if (param.type !== 'number') {
52
+ throw new Error(`Parameter ${paramName} referenced in months for history context ${key} must be of type number`);
53
+ }
54
+ if (!param.required && param.default === undefined) {
55
+ throw new Error(`Parameter ${paramName} referenced in months for history context ${key} must be required or have a default value`);
56
+ }
57
+ }
58
+ break;
59
+ default:
60
+ throw new Error(`Invalid context type '${value}' for context ${key} in ${configPath}/config.yaml`);
61
+ }
62
+ }
63
+ return config;
64
+ };
65
+ /**
66
+ * Creates parameter objects from configuration and input parameters
67
+ */ const createParameters = (config, params)=>{
68
+ const parameters = {};
69
+ // Check to see if the params has all of the required parameters from the configuration. If one is missing, throw an error stating which one is missing.
70
+ for (const [key, value] of Object.entries(config.parameters)){
71
+ if (value.required && params[key] === undefined) {
72
+ throw new Error(`Missing required parameter: ${key}`);
73
+ }
74
+ }
75
+ // Iterate through all of the parameters defined in the configuration, and assign either the value from the params object or the default value from the configuration.
76
+ for (const [key, value] of Object.entries(config.parameters)){
77
+ parameters[key] = {
78
+ ...value,
79
+ value: params[key] === undefined ? value.default : params[key]
80
+ };
81
+ }
82
+ return parameters;
83
+ };
84
+
85
+ export { createConfig, createParameters };
86
+ //# sourceMappingURL=configLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configLoader.js","sources":["../../src/analysis/configLoader.ts"],"sourcesContent":["import { join } from 'path';\nimport { load as loadYaml } from 'js-yaml';\nimport { DEFAULT_CHARACTER_ENCODING, JOB_CONFIG_FILE } from '../constants';\nimport { getLogger } from '../logging';\nimport { AnalysisConfig, Parameters } from '../types';\nimport * as Storage from '../util/storage';\n\n/**\n * Creates and validates a configuration from the config file\n */\nexport const createConfig = async (jobName: string, configPath: string): Promise<AnalysisConfig> => {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n\n // Read and parse YAML config\n const config = loadYaml(\n await storage.readFile(join(configPath, JOB_CONFIG_FILE), DEFAULT_CHARACTER_ENCODING)\n ) as AnalysisConfig;\n\n config.name = jobName;\n\n // Validate required config properties\n if (!config.model) {\n throw new Error(`Missing required config property in ${configPath}/config.yaml: model`);\n }\n\n // Validate each context directory has required properties\n for (const [key, value] of Object.entries(config.context)) {\n // Validate required name property\n if (!value.name) {\n throw new Error(`Missing required name property for context ${key} in ${configPath}/config.yaml`);\n }\n\n // Validate based on context type\n switch (value.type) {\n case 'static':\n if (!value.directory) {\n throw new Error(`Missing required directory property for ${value.type} context ${key} in ${configPath}/config.yaml`);\n }\n break;\n\n case 'history':\n if (!value.from) {\n throw new Error(`Missing required 'from' property for history context ${key} in ${configPath}/config.yaml`);\n }\n // months is optional but must be a number if provided\n if (value.months && (typeof value.months !== 'number' && !(typeof value.months === 'string' && /^\\${.*}$/.test(value.months)))) {\n throw new Error(`Invalid months property for history context ${key} in ${configPath}/config.yaml - must be a number or parameter reference`);\n }\n\n // If months is a parameter reference, validate it points to a valid numeric parameter\n if (typeof value.months === 'string' && /^\\${parameters\\.(.*)}$/.test(value.months)) {\n const paramMatch = value.months.match(/^\\${parameters\\.(.*)}$/);\n const paramName = paramMatch![1];\n const param = config.parameters?.[paramName];\n\n if (!param) {\n throw new Error(`Parameter ${paramName} referenced in months for history context ${key} not found in config parameters`);\n }\n\n if (param.type !== 'number') {\n throw new Error(`Parameter ${paramName} referenced in months for history context ${key} must be of type number`);\n }\n\n if (!param.required && param.default === undefined) {\n throw new Error(`Parameter ${paramName} referenced in months for history context ${key} must be required or have a default value`);\n }\n }\n break;\n\n default:\n throw new Error(`Invalid context type '${value}' for context ${key} in ${configPath}/config.yaml`);\n }\n }\n\n return config;\n}\n\n/**\n * Creates parameter objects from configuration and input parameters\n */\nexport const createParameters = (config: AnalysisConfig, params: Record<string, string | number>): Parameters => {\n const parameters: Parameters = {};\n\n // Check to see if the params has all of the required parameters from the configuration. If one is missing, throw an error stating which one is missing.\n for (const [key, value] of Object.entries(config.parameters)) {\n if (value.required && params[key] === undefined) {\n throw new Error(`Missing required parameter: ${key}`);\n }\n }\n\n // Iterate through all of the parameters defined in the configuration, and assign either the value from the params object or the default value from the configuration.\n for (const [key, value] of Object.entries(config.parameters)) {\n parameters[key] = {\n ...value,\n value: params[key] === undefined ? value.default : params[key]\n };\n }\n\n return parameters;\n} "],"names":["createConfig","jobName","configPath","logger","getLogger","storage","Storage","log","debug","config","loadYaml","readFile","join","JOB_CONFIG_FILE","DEFAULT_CHARACTER_ENCODING","name","model","Error","key","value","Object","entries","context","type","directory","from","months","test","paramMatch","match","paramName","param","parameters","required","default","undefined","createParameters","params"],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { glob } from 'glob';
2
+ import { join } from 'path';
3
+ import { JOB_REQUIRED_FILES, DEFAULT_CHARACTER_ENCODING } from '../constants.js';
4
+ import { getLogger } from '../logging.js';
5
+ import { create } from '../util/storage.js';
6
+
7
+ /**
8
+ * Reads files from a directory that match a given pattern.
9
+ */ async function readFiles(directory, pattern) {
10
+ const logger = getLogger();
11
+ const storage = create({
12
+ log: logger.debug
13
+ });
14
+ const fileContents = {};
15
+ // If no pattern is specified, default to all files
16
+ const filePattern = pattern || '**/*';
17
+ // Get all files matching the pattern in the directory
18
+ const files = glob.sync(filePattern, {
19
+ cwd: directory,
20
+ nodir: true // Only return files, not directories
21
+ });
22
+ // Read the contents of each file
23
+ for (const file of files){
24
+ const filePath = join(directory, file);
25
+ try {
26
+ logger.debug(`Reading file ${filePath}`);
27
+ const content = await storage.readFile(filePath, DEFAULT_CHARACTER_ENCODING);
28
+ fileContents[filePath] = content;
29
+ } catch (error) {
30
+ logger.warn(`Could not read file ${filePath}: ${error}`);
31
+ }
32
+ }
33
+ return fileContents;
34
+ }
35
+ /**
36
+ * Checks if a directory exists and contains required files.
37
+ */ const checkDirectory = async (directory)=>{
38
+ const logger = getLogger();
39
+ const storage = create({
40
+ log: logger.debug
41
+ });
42
+ if (!await storage.exists(directory)) {
43
+ throw new Error(`Configuration Directory ${directory} does not exist`);
44
+ }
45
+ // Check for required files
46
+ for (const file of JOB_REQUIRED_FILES){
47
+ if (!await storage.exists(join(directory, file))) {
48
+ throw new Error(`Missing required file in ${directory}: ${file}`);
49
+ }
50
+ }
51
+ };
52
+
53
+ export { checkDirectory, readFiles };
54
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.js","sources":["../../src/analysis/file.ts"],"sourcesContent":["import { glob } from 'glob';\nimport { join } from 'path';\nimport { DEFAULT_CHARACTER_ENCODING, JOB_REQUIRED_FILES } from '../constants';\nimport { getLogger } from '../logging';\nimport { FileContents } from '../types';\nimport * as Storage from '../util/storage';\n\n/**\n * Reads files from a directory that match a given pattern.\n */\nexport async function readFiles(directory: string, pattern?: string): Promise<FileContents> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n const fileContents: FileContents = {};\n\n // If no pattern is specified, default to all files\n const filePattern = pattern || '**/*';\n\n // Get all files matching the pattern in the directory\n const files = glob.sync(filePattern, {\n cwd: directory,\n nodir: true // Only return files, not directories\n });\n\n // Read the contents of each file\n for (const file of files) {\n const filePath = join(directory, file);\n try {\n logger.debug(`Reading file ${filePath}`);\n const content = await storage.readFile(filePath, DEFAULT_CHARACTER_ENCODING);\n fileContents[filePath] = content;\n } catch (error) {\n logger.warn(`Could not read file ${filePath}: ${error}`);\n }\n }\n return fileContents;\n}\n\n/**\n * Checks if a directory exists and contains required files.\n */\nexport const checkDirectory = async (directory: string) => {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n\n if (!(await storage.exists(directory))) {\n throw new Error(`Configuration Directory ${directory} does not exist`);\n }\n\n // Check for required files\n for (const file of JOB_REQUIRED_FILES) {\n if (!(await storage.exists(join(directory, file)))) {\n throw new Error(`Missing required file in ${directory}: ${file}`);\n }\n }\n} "],"names":["readFiles","directory","pattern","logger","getLogger","storage","Storage","log","debug","fileContents","filePattern","files","glob","sync","cwd","nodir","file","filePath","join","content","readFile","DEFAULT_CHARACTER_ENCODING","error","warn","checkDirectory","exists","Error","JOB_REQUIRED_FILES"],"mappings":";;;;;;AAOA;;AAEC,IACM,eAAeA,SAAAA,CAAUC,SAAiB,EAAEC,OAAgB,EAAA;AAC/D,IAAA,MAAMC,MAAAA,GAASC,SAAAA,EAAAA;IACf,MAAMC,OAAAA,GAAUC,MAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKJ,OAAOK;AAAM,KAAA,CAAA;AACnD,IAAA,MAAMC,eAA6B,EAAC;;AAGpC,IAAA,MAAMC,cAAcR,OAAAA,IAAW,MAAA;;AAG/B,IAAA,MAAMS,KAAAA,GAAQC,IAAAA,CAAKC,IAAI,CAACH,WAAAA,EAAa;QACjCI,GAAAA,EAAKb,SAAAA;AACLc,QAAAA,KAAAA,EAAO;AACX,KAAA,CAAA;;IAGA,KAAK,MAAMC,QAAQL,KAAAA,CAAO;QACtB,MAAMM,QAAAA,GAAWC,KAAKjB,SAAAA,EAAWe,IAAAA,CAAAA;QACjC,IAAI;AACAb,YAAAA,MAAAA,CAAOK,KAAK,CAAC,CAAC,aAAa,EAAES,QAAAA,CAAAA,CAAU,CAAA;AACvC,YAAA,MAAME,OAAAA,GAAU,MAAMd,OAAAA,CAAQe,QAAQ,CAACH,QAAAA,EAAUI,0BAAAA,CAAAA;YACjDZ,YAAY,CAACQ,SAAS,GAAGE,OAAAA;AAC7B,QAAA,CAAA,CAAE,OAAOG,KAAAA,EAAO;YACZnB,MAAAA,CAAOoB,IAAI,CAAC,CAAC,oBAAoB,EAAEN,QAAAA,CAAS,EAAE,EAAEK,KAAAA,CAAAA,CAAO,CAAA;AAC3D,QAAA;AACJ,IAAA;IACA,OAAOb,YAAAA;AACX;AAEA;;IAGO,MAAMe,cAAAA,GAAiB,OAAOvB,SAAAA,GAAAA;AACjC,IAAA,MAAME,MAAAA,GAASC,SAAAA,EAAAA;IACf,MAAMC,OAAAA,GAAUC,MAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKJ,OAAOK;AAAM,KAAA,CAAA;AAEnD,IAAA,IAAI,CAAE,MAAMH,OAAAA,CAAQoB,MAAM,CAACxB,SAAAA,CAAAA,EAAa;AACpC,QAAA,MAAM,IAAIyB,KAAAA,CAAM,CAAC,wBAAwB,EAAEzB,SAAAA,CAAU,eAAe,CAAC,CAAA;AACzE,IAAA;;IAGA,KAAK,MAAMe,QAAQW,kBAAAA,CAAoB;AACnC,QAAA,IAAI,CAAE,MAAMtB,OAAAA,CAAQoB,MAAM,CAACP,IAAAA,CAAKjB,WAAWe,IAAAA,CAAAA,CAAAA,EAAS;YAChD,MAAM,IAAIU,MAAM,CAAC,yBAAyB,EAAEzB,SAAAA,CAAU,EAAE,EAAEe,IAAAA,CAAAA,CAAM,CAAA;AACpE,QAAA;AACJ,IAAA;AACJ;;;;"}
@@ -0,0 +1,43 @@
1
+ import { createPrompt, Formatter } from '@riotprompt/riotprompt';
2
+ import { join } from 'path';
3
+ import { checkDirectory } from './file.js';
4
+ import { createConfig, createParameters } from './configLoader.js';
5
+ import { generatePersona, generateInstructions, generateContext, generateContent } from './prompt.js';
6
+ import { replaceParameters } from './section.js';
7
+
8
+ /**
9
+ * Main function that creates inputs for analysis by combining configuration, parameters, and content generation
10
+ */ const createInputs = async (analysisName, params, mindshahnConfig, jobConfig)=>{
11
+ const configPath = join(mindshahnConfig.configDirectory, jobConfig.job);
12
+ checkDirectory(configPath);
13
+ // Load and validate configuration
14
+ const config = await createConfig(jobConfig.job, configPath);
15
+ // Process parameters
16
+ const parameters = createParameters(config, params);
17
+ // Generate prompt sections
18
+ let persona = await generatePersona(configPath);
19
+ let instructions = await generateInstructions(configPath);
20
+ // Replace parameters in text
21
+ persona = replaceParameters(persona, parameters);
22
+ instructions = replaceParameters(instructions, parameters);
23
+ // Generate context and content
24
+ const context = await generateContext(config, parameters, mindshahnConfig);
25
+ const content = await generateContent(config, parameters, mindshahnConfig);
26
+ // Create the complete prompt with sections object
27
+ const prompt = createPrompt({
28
+ persona,
29
+ instructions,
30
+ contexts: context,
31
+ contents: content
32
+ });
33
+ // Format for the model using formatter instance
34
+ const formatter = Formatter.create();
35
+ const request = formatter.formatPrompt(mindshahnConfig.model, prompt);
36
+ return {
37
+ config,
38
+ request
39
+ };
40
+ };
41
+
42
+ export { createInputs };
43
+ //# sourceMappingURL=inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.js","sources":["../../src/analysis/inputs.ts"],"sourcesContent":["import { Content, Context, createPrompt, Formatter, Instruction, Model, Prompt, Request, Section } from '@riotprompt/riotprompt';\nimport { join } from 'path';\nimport { JobConfig, KronologiConfig } from '../types';\nimport { checkDirectory } from './file';\nimport { Inputs } from '../types';\nimport { createConfig, createParameters } from './configLoader';\nimport { generateContent, generateContext, generateInstructions, generatePersona } from './prompt';\nimport { replaceParameters } from './section';\n\n/**\n * Main function that creates inputs for analysis by combining configuration, parameters, and content generation\n */\nexport const createInputs = async (analysisName: string, params: Record<string, string | number>, mindshahnConfig: KronologiConfig, jobConfig: JobConfig): Promise<Inputs> => {\n const configPath = join(mindshahnConfig.configDirectory, jobConfig.job);\n checkDirectory(configPath);\n\n // Load and validate configuration\n const config = await createConfig(jobConfig.job, configPath);\n\n // Process parameters\n const parameters = createParameters(config, params);\n\n // Generate prompt sections\n let persona: Section<Instruction> = await generatePersona(configPath);\n let instructions: Section<Instruction> = await generateInstructions(configPath);\n\n // Replace parameters in text\n persona = replaceParameters(persona, parameters);\n instructions = replaceParameters(instructions, parameters);\n\n // Generate context and content\n const context: Section<Context> = await generateContext(config, parameters, mindshahnConfig);\n const content: Section<Content> = await generateContent(config, parameters, mindshahnConfig);\n\n // Create the complete prompt with sections object\n const prompt: Prompt = createPrompt({\n persona,\n instructions,\n contexts: context,\n contents: content\n });\n\n // Format for the model using formatter instance\n const formatter = Formatter.create();\n const request: Request = formatter.formatPrompt(mindshahnConfig.model as Model, prompt);\n\n return {\n config,\n request\n };\n}\n\n"],"names":["createInputs","analysisName","params","mindshahnConfig","jobConfig","configPath","join","configDirectory","job","checkDirectory","config","createConfig","parameters","createParameters","persona","generatePersona","instructions","generateInstructions","replaceParameters","context","generateContext","content","generateContent","prompt","createPrompt","contexts","contents","formatter","Formatter","create","request","formatPrompt","model"],"mappings":";;;;;;;AASA;;AAEC,IACM,MAAMA,YAAAA,GAAe,OAAOC,YAAAA,EAAsBC,QAAyCC,eAAAA,EAAkCC,SAAAA,GAAAA;AAChI,IAAA,MAAMC,aAAaC,IAAAA,CAAKH,eAAAA,CAAgBI,eAAe,EAAEH,UAAUI,GAAG,CAAA;IACtEC,cAAAA,CAAeJ,UAAAA,CAAAA;;AAGf,IAAA,MAAMK,MAAAA,GAAS,MAAMC,YAAAA,CAAaP,SAAAA,CAAUI,GAAG,EAAEH,UAAAA,CAAAA;;IAGjD,MAAMO,UAAAA,GAAaC,iBAAiBH,MAAAA,EAAQR,MAAAA,CAAAA;;IAG5C,IAAIY,OAAAA,GAAgC,MAAMC,eAAAA,CAAgBV,UAAAA,CAAAA;IAC1D,IAAIW,YAAAA,GAAqC,MAAMC,oBAAAA,CAAqBZ,UAAAA,CAAAA;;AAGpES,IAAAA,OAAAA,GAAUI,kBAAkBJ,OAAAA,EAASF,UAAAA,CAAAA;AACrCI,IAAAA,YAAAA,GAAeE,kBAAkBF,YAAAA,EAAcJ,UAAAA,CAAAA;;AAG/C,IAAA,MAAMO,OAAAA,GAA4B,MAAMC,eAAAA,CAAgBV,MAAAA,EAAQE,UAAAA,EAAYT,eAAAA,CAAAA;AAC5E,IAAA,MAAMkB,OAAAA,GAA4B,MAAMC,eAAAA,CAAgBZ,MAAAA,EAAQE,UAAAA,EAAYT,eAAAA,CAAAA;;AAG5E,IAAA,MAAMoB,SAAiBC,YAAAA,CAAa;AAChCV,QAAAA,OAAAA;AACAE,QAAAA,YAAAA;QACAS,QAAAA,EAAUN,OAAAA;QACVO,QAAAA,EAAUL;AACd,KAAA,CAAA;;IAGA,MAAMM,SAAAA,GAAYC,UAAUC,MAAM,EAAA;AAClC,IAAA,MAAMC,UAAmBH,SAAAA,CAAUI,YAAY,CAAC5B,eAAAA,CAAgB6B,KAAK,EAAWT,MAAAA,CAAAA;IAEhF,OAAO;AACHb,QAAAA,MAAAA;AACAoB,QAAAA;AACJ,KAAA;AACJ;;;;"}