@nueldotdev/amnesiac 1.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.
- package/.npmignore +24 -0
- package/README.md +228 -0
- package/bin/cli.js +276 -0
- package/package.json +39 -0
package/.npmignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Ignore all files so that nothing is published to npm except what is explicitly whitelisted in package.json "files" or .npmignore negations
|
|
2
|
+
|
|
3
|
+
*
|
|
4
|
+
!.npmignore
|
|
5
|
+
!bin/
|
|
6
|
+
!lib/
|
|
7
|
+
!package.json
|
|
8
|
+
!README.md
|
|
9
|
+
!LICENSE
|
|
10
|
+
|
|
11
|
+
# Ignore config, test, and local files
|
|
12
|
+
amnesiac.config.*
|
|
13
|
+
.env
|
|
14
|
+
.DS_Store
|
|
15
|
+
node_modules/
|
|
16
|
+
test/
|
|
17
|
+
tests/
|
|
18
|
+
coverage/
|
|
19
|
+
.idea/
|
|
20
|
+
.vscode/
|
|
21
|
+
*.log
|
|
22
|
+
*.local
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Amnesiac
|
|
2
|
+
|
|
3
|
+
Amnesiac is a CLI tool for keeping track of whatβs changed in your code. It looks at your recent Git commits and diffs, uses Gemini to summarize them, and spits out a tidy, bullet-point for your changelog.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#features)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Getting Started](#getting-started)
|
|
10
|
+
- [Configuration & Profiles](#configuration--profiles)
|
|
11
|
+
- [Configuration Loading Hierarchy](#configuration-loading-hierarchy)
|
|
12
|
+
- [Global Configuration (`~/.amnesiac/config.json`)](#global-configuration-amnesiacconfigjson)
|
|
13
|
+
- [Local Project Configuration (`amnesiac.config.js`)](#local-project-configuration-amnesiacconfigjs)
|
|
14
|
+
- [Commands](#commands)
|
|
15
|
+
- [`amnesiac`](#amnesiac)
|
|
16
|
+
- [`amnesiac init`](#amnesiac-init)
|
|
17
|
+
- [`amnesiac config`](#amnesiac-config)
|
|
18
|
+
- [`amnesiac use <profile_name>`](#amnesiac-use-profile_name)
|
|
19
|
+
- [`amnesiac status`](#amnesiac-status)
|
|
20
|
+
- [`amnesiac reset`](#amnesiac-reset)
|
|
21
|
+
- [`amnesiac --version`](#amnesiac---version)
|
|
22
|
+
- [API Key and Model Information](#api-key-and-model-information)
|
|
23
|
+
- [Getting Your API Key](#getting-your-api-key)
|
|
24
|
+
- [Keeping Your API Key Secure](#keeping-your-api-key-secure)
|
|
25
|
+
- [Understanding Gemini Models](#understanding-gemini-models)
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- **Automated Changelog Generation:** Generate changelog entries from Git diffs and commit messages.
|
|
30
|
+
- **Flexible Configuration:** Supports global profiles, local project-specific configurations, and CLI overrides.
|
|
31
|
+
- **Profile Management:** Create, edit, list, and delete multiple configuration profiles.
|
|
32
|
+
- **Active Profile Switching:** Easily switch between global profiles.
|
|
33
|
+
- **Secure API Key Handling:** API key input is masked, and the status command redacts it.
|
|
34
|
+
- **Intuitive CLI:** User-friendly commands for initialization, configuration, and status checks.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
To install Amnesiac, you will first need to have [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/) installed on your system.
|
|
39
|
+
|
|
40
|
+
Then, you can install Amnesiac globally via npm:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g amnesiac
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This will make the `amnesiac` command available from any directory in your terminal.
|
|
47
|
+
|
|
48
|
+
### Updating Amnesiac
|
|
49
|
+
|
|
50
|
+
To update your globally installed Amnesiac to the latest version, simply run:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm update -g amnesiac
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Getting Started
|
|
57
|
+
|
|
58
|
+
1. **Initialize your project (optional, but recommended for project-specific settings):**
|
|
59
|
+
```bash
|
|
60
|
+
amnesiac init
|
|
61
|
+
```
|
|
62
|
+
This command creates an `amnesiac.config.js` file in your project root with default settings.
|
|
63
|
+
|
|
64
|
+
2. **Configure your API Key and Model:**
|
|
65
|
+
Run `amnesiac config` to set up your global default profile or create a new one. You'll be prompted for your Gemini API key and preferred model.
|
|
66
|
+
```bash
|
|
67
|
+
amnesiac config
|
|
68
|
+
```
|
|
69
|
+
*(See [Configuration & Profiles](#configuration--profiles) for more details on managing profiles.)*
|
|
70
|
+
|
|
71
|
+
3. **Generate Changelog Entry:**
|
|
72
|
+
Once configured, you can generate a changelog entry by running:
|
|
73
|
+
```bash
|
|
74
|
+
amnesiac
|
|
75
|
+
```
|
|
76
|
+
This command will:
|
|
77
|
+
- Detect recent Git changes (staged, uncommitted, and committed).
|
|
78
|
+
- Send the diff to the Gemini API using your active configuration.
|
|
79
|
+
- Receive a concise changelog entry.
|
|
80
|
+
- Prepend the new entry to your `CHANGELOG.md` file (or the file specified in your config).
|
|
81
|
+
|
|
82
|
+
## Configuration & Profiles
|
|
83
|
+
|
|
84
|
+
Amnesiac offers a flexible configuration system that allows you to manage settings at different levels: per-project, globally, or as a one-off CLI override.
|
|
85
|
+
|
|
86
|
+
### Configuration Loading Hierarchy
|
|
87
|
+
|
|
88
|
+
Amnesiac loads configurations with the following priority (highest to lowest):
|
|
89
|
+
|
|
90
|
+
1. **CLI Overrides:** Options passed directly to the `amnesiac` command (e.g., `--use <profile>`, `--prompt <text>`, `--model <name>`). These are temporary for a single run.
|
|
91
|
+
2. **Local Project Configuration:** An `amnesiac.config.js` file in your current project's root directory. This takes precedence over your global active profile for that specific project.
|
|
92
|
+
3. **Global Active Profile:** The profile marked as `activeProfile` in your `~/.amnesiac/config.json` file. This is your default fallback.
|
|
93
|
+
|
|
94
|
+
### Local Project Configuration (`amnesiac.config.js`)
|
|
95
|
+
|
|
96
|
+
You can create an `amnesiac.config.js` file in the root of your project to define project-specific settings. This configuration will override your global active profile settings when you run `amnesiac` within that project, unless a `--use` flag is provided via CLI.
|
|
97
|
+
|
|
98
|
+
**Example `amnesiac.config.js`:**
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
export default {
|
|
102
|
+
apiKey: process.env.GEMINI_API_KEY, // Can be sourced from environment variables
|
|
103
|
+
model: "gemini-1.5-pro",
|
|
104
|
+
outputFile: "PROJECT_CHANGELOG.md",
|
|
105
|
+
prompt: `
|
|
106
|
+
Generate a comprehensive changelog entry focusing on new features and bug fixes for this project.
|
|
107
|
+
Include PR numbers if available.
|
|
108
|
+
`
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Commands
|
|
113
|
+
|
|
114
|
+
Amnesiac provides several commands to manage your configurations and generate changelogs.
|
|
115
|
+
|
|
116
|
+
### `amnesiac`
|
|
117
|
+
|
|
118
|
+
The main command to generate a changelog entry. It uses the configuration determined by the [loading hierarchy](#configuration-loading-hierarchy).
|
|
119
|
+
|
|
120
|
+
**Usage:**
|
|
121
|
+
```bash
|
|
122
|
+
amnesiac
|
|
123
|
+
amnesiac -p "Custom prompt for this run" # Override prompt for a single run
|
|
124
|
+
amnesiac -m "gemini-pro" # Override model for a single run
|
|
125
|
+
amnesiac -u work # Use 'work' profile for a single run
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `amnesiac init`
|
|
129
|
+
|
|
130
|
+
Initializes a local `amnesiac.config.js` file in the current project directory with default settings. It will prompt for confirmation if the file already exists.
|
|
131
|
+
|
|
132
|
+
**Usage:**
|
|
133
|
+
```bash
|
|
134
|
+
amnesiac init
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `amnesiac config`
|
|
138
|
+
|
|
139
|
+
Manages your global Amnesiac profiles (stored in `~/.amnesiac/config.json`).
|
|
140
|
+
|
|
141
|
+
**Usage:**
|
|
142
|
+
|
|
143
|
+
- **Set up or edit a profile (will prompt for details):**
|
|
144
|
+
```bash
|
|
145
|
+
amnesiac config
|
|
146
|
+
amnesiac config --profile my-dev-profile # Directly specify a profile to create/edit
|
|
147
|
+
```
|
|
148
|
+
When prompted for the API key, your input will be masked for security.
|
|
149
|
+
|
|
150
|
+
- **List all available profiles:**
|
|
151
|
+
```bash
|
|
152
|
+
amnesiac config --list
|
|
153
|
+
# or
|
|
154
|
+
amnesiac config -l
|
|
155
|
+
```
|
|
156
|
+
This will also indicate which profile is currently active.
|
|
157
|
+
|
|
158
|
+
- **Delete a specified profile:**
|
|
159
|
+
```bash
|
|
160
|
+
amnesiac config --delete my-old-profile
|
|
161
|
+
# or
|
|
162
|
+
amnesiac config -d my-old-profile
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### `amnesiac use <profile_name>`
|
|
166
|
+
|
|
167
|
+
Sets the specified profile as the globally active profile in `~/.amnesiac/config.json`. This profile will be used by default for subsequent `amnesiac` runs unless overridden by a local config or CLI flag.
|
|
168
|
+
|
|
169
|
+
**Usage:**
|
|
170
|
+
```bash
|
|
171
|
+
amnesiac use work
|
|
172
|
+
amnesiac use personal
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### `amnesiac status`
|
|
176
|
+
|
|
177
|
+
Displays the currently active Amnesiac configuration, including the active profile, model, output file, and a snippet of the default prompt. The API key is masked for security.
|
|
178
|
+
|
|
179
|
+
**Usage:**
|
|
180
|
+
```bash
|
|
181
|
+
amnesiac status
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### `amnesiac reset`
|
|
185
|
+
|
|
186
|
+
Deletes the entire global Amnesiac configuration file (`~/.amnesiac/config.json`), effectively removing all saved profiles and resetting global settings. This command requires user confirmation.
|
|
187
|
+
|
|
188
|
+
**Usage:**
|
|
189
|
+
```bash
|
|
190
|
+
amnesiac reset
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### `amnesiac --version`
|
|
194
|
+
|
|
195
|
+
Displays the current version of the Amnesiac CLI tool.
|
|
196
|
+
|
|
197
|
+
**Usage:**
|
|
198
|
+
```bash
|
|
199
|
+
amnesiac --version
|
|
200
|
+
# or
|
|
201
|
+
amnesiac -V
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## API Key and Model Information
|
|
205
|
+
|
|
206
|
+
### Getting Your API Key
|
|
207
|
+
|
|
208
|
+
Amnesiac uses the Google Gemini API to generate changelog entries. You'll need an API key to use the tool.
|
|
209
|
+
|
|
210
|
+
1. Visit [Google AI Studio](https://aistudio.google.com/app/apikey).
|
|
211
|
+
2. Follow the instructions to create a new API key.
|
|
212
|
+
3. Once you have your key, you can configure it using `amnesiac config` or by setting it in your local `amnesiac.config.js` file or as an environment variable (e.g., `GEMINI_API_KEY`).
|
|
213
|
+
|
|
214
|
+
### Keeping Your API Key Secure
|
|
215
|
+
|
|
216
|
+
Your API key is a sensitive credential. Treat it like a password:
|
|
217
|
+
- **Do not commit it directly into your project's `amnesiac.config.js`** if the file is shared publicly. Instead, use environment variables (`process.env.GEMINI_API_KEY`) as shown in the local config example.
|
|
218
|
+
- When entering your API key via `amnesiac config`, the input is masked.
|
|
219
|
+
- When viewing your configuration with `amnesiac status`, the API key is partially masked.
|
|
220
|
+
|
|
221
|
+
### Understanding Gemini Models
|
|
222
|
+
|
|
223
|
+
The `model` parameter (e.g., `gemini-1.5-flash`, `gemini-1.5-pro`) determines which Gemini model Amnesiac uses for content generation.
|
|
224
|
+
|
|
225
|
+
- **`gemini-1.5-flash`:** A faster, more cost-effective model, suitable for many common tasks. This is the default.
|
|
226
|
+
- **`gemini-1.5-pro`:** A more capable model for complex tasks, offering higher quality but potentially at a higher latency or cost.
|
|
227
|
+
|
|
228
|
+
You can specify the model in your global or local configurations, or override it for a single run using `amnesiac -m <model_name>`. Refer to the [Gemini API documentation](https://ai.google.dev/models/gemini) for the latest information on available models and their capabilities.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import inquirer from "inquirer";
|
|
7
|
+
import { generateDocs } from "../lib/doc_generator.js";
|
|
8
|
+
import { loadConfig } from "../lib/config.js";
|
|
9
|
+
import { readFileSync } from 'fs';
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url)));
|
|
13
|
+
|
|
14
|
+
// Handle Ctrl+C gracefully
|
|
15
|
+
process.on('SIGINT', () => {
|
|
16
|
+
console.log('\nOperation cancelled by user.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
program.version(packageJson.version);
|
|
21
|
+
|
|
22
|
+
program
|
|
23
|
+
.command("init")
|
|
24
|
+
.description("Initialize a local amnesiac.config.js file")
|
|
25
|
+
.action(async () => {
|
|
26
|
+
const localConfigPath = path.resolve(process.cwd(), "amnesiac.config.js");
|
|
27
|
+
const defaultConfigContent = `export default {
|
|
28
|
+
apiKey: process.env.GEMINI_API_KEY || "", // Consider adding a placeholder for API key
|
|
29
|
+
model: "gemini-1.5-flash",
|
|
30
|
+
outputFile: "CHANGELOG.md",
|
|
31
|
+
prompt: \`
|
|
32
|
+
You are an assistant that generates clean, developer-friendly changelog entries.
|
|
33
|
+
Summarize commit messages and diffs into concise bullet points.
|
|
34
|
+
Output only valid markdown for a CHANGELOG.md file.
|
|
35
|
+
\`
|
|
36
|
+
};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
if (fs.existsSync(localConfigPath)) {
|
|
40
|
+
const { overwrite } = await inquirer.prompt([
|
|
41
|
+
{
|
|
42
|
+
type: "confirm",
|
|
43
|
+
name: "overwrite",
|
|
44
|
+
message: "amnesiac.config.js already exists. Overwrite?",
|
|
45
|
+
default: false,
|
|
46
|
+
},
|
|
47
|
+
]);
|
|
48
|
+
if (!overwrite) {
|
|
49
|
+
console.log("Initialization cancelled.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
fs.writeFileSync(localConfigPath, defaultConfigContent.trim());
|
|
56
|
+
console.log(`β
Created amnesiac.config.js at ${localConfigPath}`);
|
|
57
|
+
console.log(`π‘ Remember to add your Gemini API key to your environment variables (e.g., GEMINI_API_KEY=YOUR_KEY) or directly into amnesiac.config.js`);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(`β Failed to create amnesiac.config.js: ${error.message}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
program
|
|
65
|
+
.command("reset")
|
|
66
|
+
.description("Delete the global Amnesiac config file and all profiles")
|
|
67
|
+
.action(async () => {
|
|
68
|
+
const globalConfigPath = path.join(os.homedir(), ".amnesiac", "config.json");
|
|
69
|
+
|
|
70
|
+
if (!fs.existsSync(globalConfigPath)) {
|
|
71
|
+
console.log("π€·ββοΈ No global config file found to reset.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { confirmReset } = await inquirer.prompt([
|
|
76
|
+
{
|
|
77
|
+
type: "confirm",
|
|
78
|
+
name: "confirmReset",
|
|
79
|
+
message: "This will delete your global Amnesiac config file (~/.amnesiac/config.json) and ALL saved profiles. Are you sure?",
|
|
80
|
+
default: false,
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
if (confirmReset) {
|
|
85
|
+
try {
|
|
86
|
+
fs.unlinkSync(globalConfigPath);
|
|
87
|
+
console.log("β
Global Amnesiac config and all profiles have been reset.");
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("β Failed to delete global config file:", error.message);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
console.log("Reset cancelled.");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
program
|
|
97
|
+
.command("status")
|
|
98
|
+
.description("Display the currently active Amnesiac configuration")
|
|
99
|
+
.action(async () => {
|
|
100
|
+
try {
|
|
101
|
+
const config = await loadConfig({}); // Load config without CLI overrides for status display
|
|
102
|
+
|
|
103
|
+
console.log("\n--- Amnesiac Configuration Status ---\n");
|
|
104
|
+
console.log(`Active Profile: ${config.activeProfile || 'N/A (using local/CLI defaults)'}`);
|
|
105
|
+
console.log(`API Key: ${config.apiKey ? '********' + config.apiKey.slice(-4) : 'Not Set'}`); // Mask API key
|
|
106
|
+
console.log(`Model: ${config.model}`);
|
|
107
|
+
console.log(`Output File: ${config.outputFile}`);
|
|
108
|
+
console.log(`Default Prompt: ${config.prompt.split('\n')[0]}...`); // Show first line of prompt
|
|
109
|
+
console.log("\n-------------------------------------\n");
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error(`\nβ An error occurred while fetching status: ${error.message}`);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
program
|
|
117
|
+
.command("config")
|
|
118
|
+
.description("Set up or edit Amnesiac config")
|
|
119
|
+
.option("-p, --profile <name>", "Specify a profile name", "default")
|
|
120
|
+
.option("-l, --list", "List all available profiles")
|
|
121
|
+
.option("-d, --delete <name>", "Delete a specified profile")
|
|
122
|
+
.action(async (options) => {
|
|
123
|
+
try {
|
|
124
|
+
const dir = path.join(os.homedir(), ".amnesiac");
|
|
125
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
|
126
|
+
|
|
127
|
+
const globalConfigPath = path.join(dir, "config.json");
|
|
128
|
+
let globalConfig = { activeProfile: "default", profiles: {} };
|
|
129
|
+
|
|
130
|
+
if (fs.existsSync(globalConfigPath)) {
|
|
131
|
+
try {
|
|
132
|
+
globalConfig = JSON.parse(fs.readFileSync(globalConfigPath, "utf-8"));
|
|
133
|
+
} catch (e) {
|
|
134
|
+
console.error("β Error reading global config file. It might be corrupted. You can reset it with 'amnesiac reset'.", e.message);
|
|
135
|
+
// Continue with default empty config if file is corrupted, but alert user
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (options.list) {
|
|
140
|
+
console.log("Available profiles:");
|
|
141
|
+
const profiles = Object.keys(globalConfig.profiles);
|
|
142
|
+
if (profiles.length > 0) {
|
|
143
|
+
profiles.forEach(profile => {
|
|
144
|
+
const activeIndicator = profile === globalConfig.activeProfile ? " (active)" : "";
|
|
145
|
+
console.log(`- ${profile}${activeIndicator}`);
|
|
146
|
+
});
|
|
147
|
+
} else {
|
|
148
|
+
console.log("No profiles found.");
|
|
149
|
+
}
|
|
150
|
+
return; // Exit after listing profiles
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (options.delete) {
|
|
154
|
+
const profileToDelete = options.delete;
|
|
155
|
+
if (globalConfig.profiles[profileToDelete]) {
|
|
156
|
+
delete globalConfig.profiles[profileToDelete];
|
|
157
|
+
if (globalConfig.activeProfile === profileToDelete) {
|
|
158
|
+
globalConfig.activeProfile = "default"; // Reset active profile if deleted
|
|
159
|
+
}
|
|
160
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 2));
|
|
161
|
+
console.log(`β
Profile "${profileToDelete}" deleted successfully.`);
|
|
162
|
+
} else {
|
|
163
|
+
console.log(`β Profile "${profileToDelete}" not found.`);
|
|
164
|
+
}
|
|
165
|
+
return; // Exit after deleting profile
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Ask for profile name if not provided via flag
|
|
169
|
+
let profile = options.profile;
|
|
170
|
+
if (profile === 'default') {
|
|
171
|
+
const answers = await inquirer.prompt([
|
|
172
|
+
{
|
|
173
|
+
type: "input",
|
|
174
|
+
name: "profile",
|
|
175
|
+
message: "Profile name (default = 'default'):",
|
|
176
|
+
default: "default",
|
|
177
|
+
},
|
|
178
|
+
]);
|
|
179
|
+
profile = answers.profile;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Load existing profile config for editing
|
|
183
|
+
let existingConfig = globalConfig.profiles[profile] || {};
|
|
184
|
+
if (Object.keys(existingConfig).length > 0) {
|
|
185
|
+
console.log(`π Editing existing profile "${profile}"...`);
|
|
186
|
+
} else {
|
|
187
|
+
console.log(`π Creating new profile "${profile}"...`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const answers = await inquirer.prompt([
|
|
191
|
+
{
|
|
192
|
+
type: "password",
|
|
193
|
+
name: "apiKey",
|
|
194
|
+
message: "Enter your API key:",
|
|
195
|
+
default: existingConfig.apiKey || "",
|
|
196
|
+
validate: (input) =>
|
|
197
|
+
input.trim() !== "" ? true : "API key is required.",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
type: "input",
|
|
201
|
+
name: "model",
|
|
202
|
+
message: "Enter model name:",
|
|
203
|
+
default: existingConfig.model || "gemini-1.5-flash",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
type: "input",
|
|
207
|
+
name: "prompt",
|
|
208
|
+
message: "Enter your default prompt (leave blank to use default):",
|
|
209
|
+
default:
|
|
210
|
+
existingConfig.prompt ||
|
|
211
|
+
"Generate a clear changelog entry for these changes.",
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
type: "input",
|
|
215
|
+
name: "outputFile",
|
|
216
|
+
message: "Enter output file name:",
|
|
217
|
+
default: existingConfig.outputFile || "CHANGELOG.md",
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
|
|
221
|
+
globalConfig.profiles[profile] = answers;
|
|
222
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 2));
|
|
223
|
+
console.log(`β
Config saved at ${globalConfigPath}`);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if (error.name === 'ExitPromptError') {
|
|
226
|
+
console.log('\nOperation cancelled by user.');
|
|
227
|
+
process.exit(1);
|
|
228
|
+
} else {
|
|
229
|
+
console.error(`\nβ An unexpected error occurred during config: ${error.message}`);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
program
|
|
236
|
+
.command("use <profile_name>")
|
|
237
|
+
.description("Set the active profile for Amnesiac")
|
|
238
|
+
.action(async (profile_name) => {
|
|
239
|
+
const dir = path.join(os.homedir(), ".amnesiac");
|
|
240
|
+
const globalConfigPath = path.join(dir, "config.json");
|
|
241
|
+
let globalConfig = { activeProfile: "default", profiles: {} };
|
|
242
|
+
|
|
243
|
+
if (fs.existsSync(globalConfigPath)) {
|
|
244
|
+
try {
|
|
245
|
+
globalConfig = JSON.parse(fs.readFileSync(globalConfigPath, "utf-8"));
|
|
246
|
+
} catch (e) {
|
|
247
|
+
console.error("β Error reading global config file. It might be corrupted. You can reset it with 'amnesiac reset'.", e.message);
|
|
248
|
+
return; // Exit if global config is unreadable for 'use' command
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (globalConfig.profiles[profile_name]) {
|
|
253
|
+
globalConfig.activeProfile = profile_name;
|
|
254
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 2));
|
|
255
|
+
console.log(`β
Active profile set to "${profile_name}".`);
|
|
256
|
+
} else {
|
|
257
|
+
console.log(`β Profile "${profile_name}" not found. Please create it first using 'amnesiac config --profile ${profile_name}'.`);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
program
|
|
262
|
+
.option("-u, --use <profile>", "Use a specific profile for this run")
|
|
263
|
+
.option("-p, --prompt <text>", "Override prompt")
|
|
264
|
+
.option("-m, --model <name>", "Override model")
|
|
265
|
+
// Future: .option("-u, --use <profile>", "Use specific profile")
|
|
266
|
+
.action(async (opts) => {
|
|
267
|
+
try {
|
|
268
|
+
const config = await loadConfig(opts);
|
|
269
|
+
await generateDocs(config);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.error(`\nβ An error occurred: ${error.message}`);
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nueldotdev/amnesiac",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A command-line tool to automatically generate documentation for recent codebase changes using the Gemini API.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli-tool",
|
|
7
|
+
"documentation-generator",
|
|
8
|
+
"changelog",
|
|
9
|
+
"auto-docs",
|
|
10
|
+
"git-diff",
|
|
11
|
+
"git-integration",
|
|
12
|
+
"ai-powered",
|
|
13
|
+
"gemini-api",
|
|
14
|
+
"llm",
|
|
15
|
+
"google-ai",
|
|
16
|
+
"developer-tools",
|
|
17
|
+
"productivity"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/nueldotdev/amnesiac#readme",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/nueldotdev/amnesiac/issues"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/nueldotdev/amnesiac.git"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"author": "nueldotdev",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"bin": {
|
|
31
|
+
"amnesiac": "bin/cli.js"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@google/generative-ai": "^0.24.1",
|
|
35
|
+
"commander": "^14.0.1",
|
|
36
|
+
"inquirer": "^12.9.6",
|
|
37
|
+
"simple-git": "^3.28.0"
|
|
38
|
+
}
|
|
39
|
+
}
|