create-chat-gpt-repo-memory 0.1.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/LICENSE +21 -0
- package/README.md +275 -0
- package/bin/cli.js +84 -0
- package/package.json +35 -0
- package/src/gitignore.js +81 -0
- package/src/init.js +205 -0
- package/src/paths.js +21 -0
- package/src/projectName.js +5 -0
- package/src/templateResolver.js +27 -0
- package/templates/dotnet/AGENTS.md +129 -0
- package/templates/dotnet/architecture.md +47 -0
- package/templates/dotnet/conventions.md +69 -0
- package/templates/dotnet/project-map.md +104 -0
- package/templates/dotnet/prompts/fill-project-map.md +50 -0
- package/templates/dotnet/prompts/start-session.md +30 -0
- package/templates/dotnet/update-project-map.md +61 -0
- package/templates/dotnet/workflows.md +67 -0
- package/templates/generic/AGENTS.md +119 -0
- package/templates/generic/architecture.md +47 -0
- package/templates/generic/conventions.md +49 -0
- package/templates/generic/project-map.md +84 -0
- package/templates/generic/prompts/fill-project-map.md +39 -0
- package/templates/generic/prompts/start-session.md +22 -0
- package/templates/generic/update-project-map.md +61 -0
- package/templates/generic/workflows.md +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# create-chat-gpt-repo-memory
|
|
2
|
+
|
|
3
|
+
`create-chat-gpt-repo-memory` scaffolds Git-tracked repo memory files for ChatGPT and Codex-style coding workflows.
|
|
4
|
+
|
|
5
|
+
It creates a root `AGENTS.md` instruction file plus a shared `.agent-memory/` folder containing durable project memory templates. The package scaffolds structure and template content only. It does not analyze the target repository.
|
|
6
|
+
|
|
7
|
+
## Quickstart
|
|
8
|
+
|
|
9
|
+
### Step 1 — scaffold the files
|
|
10
|
+
|
|
11
|
+
Run this inside any repository:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx create-chat-gpt-repo-memory
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This creates `AGENTS.md` and an `.agent-memory/` directory with template memory files, and updates `.gitignore` to exclude local agent cache files.
|
|
18
|
+
|
|
19
|
+
### Step 2 — let ChatGPT fill them in
|
|
20
|
+
|
|
21
|
+
Open a ChatGPT session with access to your repository and run:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Use AGENTS.md as your operating instructions for this repository. Then read .agent-memory/prompts/fill-project-map.md and execute it. Fill or update the .agent-memory files using only verified repository facts. Do not include secrets.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
ChatGPT will inspect your repository and populate the memory files with your actual stack, architecture, conventions, entry points, workflows, and more.
|
|
28
|
+
|
|
29
|
+
### Step 3 — commit
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git add AGENTS.md .agent-memory/ .gitignore
|
|
33
|
+
git commit -m "Add ChatGPT repo memory"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Done. Every future session that reads `AGENTS.md` and `.agent-memory/` will have full project context before doing anything else.
|
|
37
|
+
|
|
38
|
+
## Why `AGENTS.md` Instead of `CHATGPT.md`
|
|
39
|
+
|
|
40
|
+
This package uses `AGENTS.md` because that is the Codex-style repository instruction convention.
|
|
41
|
+
|
|
42
|
+
That keeps one shared instruction surface for mixed workflows:
|
|
43
|
+
|
|
44
|
+
- Codex-style agents can start from `AGENTS.md`
|
|
45
|
+
- ChatGPT Projects can upload or reference the same files
|
|
46
|
+
- Teams can track one repo-memory structure in Git
|
|
47
|
+
|
|
48
|
+
This package does not generate `CHATGPT.md`.
|
|
49
|
+
|
|
50
|
+
## Why `.agent-memory/` Instead of `.chatgpt/`
|
|
51
|
+
|
|
52
|
+
This package uses `.agent-memory/` as shared Git-tracked project memory:
|
|
53
|
+
|
|
54
|
+
- readable by humans and coding agents
|
|
55
|
+
- easy to version in Git
|
|
56
|
+
- neutral naming that works across tools
|
|
57
|
+
- separate from local cache artifacts
|
|
58
|
+
|
|
59
|
+
This package does not generate `.chatgpt/`.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
Use with `npx`:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx create-chat-gpt-repo-memory
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or install globally:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install -g create-chat-gpt-repo-memory
|
|
73
|
+
create-chat-gpt-repo-memory
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx create-chat-gpt-repo-memory
|
|
80
|
+
npx create-chat-gpt-repo-memory --template dotnet
|
|
81
|
+
npx create-chat-gpt-repo-memory --force
|
|
82
|
+
npx create-chat-gpt-repo-memory --no-gitignore
|
|
83
|
+
npx create-chat-gpt-repo-memory --cwd ../some-project
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Options
|
|
87
|
+
|
|
88
|
+
- `--force`: overwrite existing generated files
|
|
89
|
+
- `--no-gitignore`: skip `.gitignore` updates
|
|
90
|
+
- `--template <name>`: choose `generic` or `dotnet`
|
|
91
|
+
- `--cwd <path>`: target directory to scaffold into
|
|
92
|
+
|
|
93
|
+
## Files Generated
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
AGENTS.md
|
|
97
|
+
.agent-memory/project-map.md
|
|
98
|
+
.agent-memory/architecture.md
|
|
99
|
+
.agent-memory/conventions.md
|
|
100
|
+
.agent-memory/workflows.md
|
|
101
|
+
.agent-memory/update-project-map.md
|
|
102
|
+
.agent-memory/prompts/fill-project-map.md
|
|
103
|
+
.agent-memory/prompts/start-session.md
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The package does not create `.agent-memory-local/`. That path is added to `.gitignore` only.
|
|
107
|
+
|
|
108
|
+
## Template Options
|
|
109
|
+
|
|
110
|
+
- `generic`: baseline repository memory template
|
|
111
|
+
- `dotnet`: generic template plus .NET-specific guidance
|
|
112
|
+
|
|
113
|
+
Template variables:
|
|
114
|
+
|
|
115
|
+
- `{{PROJECT_NAME}}`
|
|
116
|
+
- `{{TEMPLATE_NAME}}`
|
|
117
|
+
- `{{GENERATED_BY}}`
|
|
118
|
+
|
|
119
|
+
## Initial Map-Fill Prompt
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
Use AGENTS.md as your operating instructions for this repository. Then read .agent-memory/prompts/fill-project-map.md and execute it. Fill or update the .agent-memory files using only verified repository facts. Do not include secrets.
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Future Session-Start Prompt
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
Use AGENTS.md as your operating instructions, then read .agent-memory/prompts/start-session.md and follow it for this task.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Overwrite Safety
|
|
132
|
+
|
|
133
|
+
The CLI never silently overwrites generated files.
|
|
134
|
+
|
|
135
|
+
- If a file does not exist, it is created.
|
|
136
|
+
- If a file exists and `--force` is not set, it is skipped by default.
|
|
137
|
+
- If a file exists and `--force` is set, it is overwritten.
|
|
138
|
+
|
|
139
|
+
For an existing `AGENTS.md`, the CLI is more careful:
|
|
140
|
+
|
|
141
|
+
- If the file does not already contain repo-memory guidance, the CLI appends a managed repo-memory instructions block instead of replacing the whole file.
|
|
142
|
+
- If that managed block already exists, the CLI updates just that block on later runs.
|
|
143
|
+
- If the existing `AGENTS.md` already contains its own repo-memory guidance and the CLI cannot safely merge it, the CLI asks whether to skip or overwrite when running interactively.
|
|
144
|
+
- In a non-interactive environment, that unmergeable case falls back to skip.
|
|
145
|
+
|
|
146
|
+
## `.gitignore` Behavior
|
|
147
|
+
|
|
148
|
+
Unless `--no-gitignore` is used, the CLI updates or creates `.gitignore` and adds this local-only block when needed:
|
|
149
|
+
|
|
150
|
+
```gitignore
|
|
151
|
+
# Local agent memory/cache
|
|
152
|
+
.agent-memory-local/
|
|
153
|
+
.agent-memory/**/*.db
|
|
154
|
+
.agent-memory/**/*.sqlite
|
|
155
|
+
.agent-memory/**/*.sqlite3
|
|
156
|
+
.agent-memory/**/*.log
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The update is idempotent. If `.gitignore` already contains `.agent-memory-local/`, the block is not appended again.
|
|
160
|
+
|
|
161
|
+
The package also removes legacy `.chatgpt-local/` and `.chatgpt/**/*.(db|sqlite|sqlite3|log)` ignore lines when it updates `.gitignore`.
|
|
162
|
+
|
|
163
|
+
The Git-tracked memory files themselves are never ignored by this package.
|
|
164
|
+
|
|
165
|
+
## Notes for Codex-Style Usage
|
|
166
|
+
|
|
167
|
+
- `AGENTS.md` is the root instruction file.
|
|
168
|
+
- Codex-style agents should start from the repo root so `AGENTS.md` can be discovered.
|
|
169
|
+
- Keep `.agent-memory/project-map.md` concise and move detail into supporting memory files.
|
|
170
|
+
|
|
171
|
+
## Notes for ChatGPT Project Usage
|
|
172
|
+
|
|
173
|
+
- ChatGPT Projects do not automatically treat `.agent-memory/` as a magic folder.
|
|
174
|
+
- Add `AGENTS.md` and `.agent-memory/` files to the project, or make sure they are available in repository context.
|
|
175
|
+
- Start future sessions by telling ChatGPT to read `AGENTS.md` and the relevant `.agent-memory/` files.
|
|
176
|
+
|
|
177
|
+
## Publishing
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm login
|
|
181
|
+
npm publish --access public
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Local Testing
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm link
|
|
188
|
+
create-chat-gpt-repo-memory --cwd ../some-test-repo
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Manual Test Plan
|
|
192
|
+
|
|
193
|
+
Create a temporary test project:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
mkdir /tmp/chatgpt-memory-test
|
|
197
|
+
cd /tmp/chatgpt-memory-test
|
|
198
|
+
node /path/to/create-chat-gpt-repo-memory/bin/cli.js
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Verify:
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
AGENTS.md exists
|
|
205
|
+
.agent-memory/project-map.md exists
|
|
206
|
+
.agent-memory/architecture.md exists
|
|
207
|
+
.agent-memory/conventions.md exists
|
|
208
|
+
.agent-memory/workflows.md exists
|
|
209
|
+
.agent-memory/update-project-map.md exists
|
|
210
|
+
.agent-memory/prompts/fill-project-map.md exists
|
|
211
|
+
.agent-memory/prompts/start-session.md exists
|
|
212
|
+
.gitignore contains Local agent memory/cache block
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Run it again without `--force`.
|
|
216
|
+
|
|
217
|
+
Expected:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
files are skipped
|
|
221
|
+
.gitignore is unchanged
|
|
222
|
+
no duplicate gitignore block
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Run with `--force`.
|
|
226
|
+
|
|
227
|
+
Expected:
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
existing generated files are overwritten
|
|
231
|
+
.gitignore remains unchanged
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Run with dotnet template:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
mkdir /tmp/chatgpt-memory-dotnet-test
|
|
238
|
+
node /path/to/create-chat-gpt-repo-memory/bin/cli.js --template dotnet --cwd /tmp/chatgpt-memory-dotnet-test
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Expected:
|
|
242
|
+
|
|
243
|
+
```text
|
|
244
|
+
dotnet-specific sections are present
|
|
245
|
+
.agent-memory/prompts/start-session.md exists
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Run against an invalid template:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
node /path/to/create-chat-gpt-repo-memory/bin/cli.js --template invalid
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Expected:
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
clear unsupported-template error
|
|
258
|
+
exit code 1
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Search for stale terms:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
grep -R "CHATGPT.md\|\.chatgpt\|CLAUDE.md\|\.claude\|create-claude" .
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Expected:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
No stale references, except intentional README explanation if present.
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { resolveTargetDirectory } from "../src/paths.js";
|
|
5
|
+
import { initChatGptRepoMemory } from "../src/init.js";
|
|
6
|
+
import { SUPPORTED_TEMPLATES } from "../src/templateResolver.js";
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name("create-chat-gpt-repo-memory")
|
|
12
|
+
.description("Scaffold Git-tracked repo memory files for ChatGPT and Codex-style coding workflows.")
|
|
13
|
+
.version("0.1.0");
|
|
14
|
+
|
|
15
|
+
function addOptions(cmd) {
|
|
16
|
+
return cmd
|
|
17
|
+
.option("--force", "Overwrite existing generated files.", false)
|
|
18
|
+
.option("--no-gitignore", "Do not update .gitignore.")
|
|
19
|
+
.option("--template <name>", `Template to use. Supported values: ${SUPPORTED_TEMPLATES.join(", ")}.`, "generic")
|
|
20
|
+
.option("--cwd <path>", "Directory where files should be created.", process.cwd());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function runInit(options) {
|
|
24
|
+
const { force, gitignore: updateGitignore, template, cwd } = options;
|
|
25
|
+
|
|
26
|
+
let rootDir;
|
|
27
|
+
try {
|
|
28
|
+
rootDir = await resolveTargetDirectory(cwd);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
console.error(`Error: ${err.message}`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let result;
|
|
35
|
+
try {
|
|
36
|
+
result = await initChatGptRepoMemory({ rootDir, force, updateGitignore, template });
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error(`Error: ${err.message}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { created, overwritten, skipped, gitignoreStatus } = result;
|
|
43
|
+
|
|
44
|
+
console.log("\nChatGPT/Codex repo memory initialized.\n");
|
|
45
|
+
|
|
46
|
+
if (created.length > 0) {
|
|
47
|
+
console.log("Created:");
|
|
48
|
+
for (const f of created) console.log(` - ${f}`);
|
|
49
|
+
console.log();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (overwritten.length > 0) {
|
|
53
|
+
console.log("Overwritten:");
|
|
54
|
+
for (const f of overwritten) console.log(` - ${f}`);
|
|
55
|
+
console.log();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (skipped.length > 0) {
|
|
59
|
+
console.log("Skipped:");
|
|
60
|
+
for (const f of skipped) console.log(` - ${f}`);
|
|
61
|
+
console.log();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(`Gitignore: ${gitignoreStatus}\n`);
|
|
65
|
+
|
|
66
|
+
console.log("Next steps:");
|
|
67
|
+
console.log(" 1. Commit AGENTS.md and .agent-memory/ files.");
|
|
68
|
+
console.log(" 2. For Codex-style agents, start from the repo root so the agent can read AGENTS.md.");
|
|
69
|
+
console.log(" 3. For ChatGPT Projects, add AGENTS.md and .agent-memory/ as project files or make sure they are available in the repository context.");
|
|
70
|
+
console.log(' 4. Kick off the initial map fill with:');
|
|
71
|
+
console.log(' "Use AGENTS.md as your operating instructions for this repository. Then read .agent-memory/prompts/fill-project-map.md and execute it. Fill or update the .agent-memory files using only verified repository facts. Do not include secrets."');
|
|
72
|
+
console.log();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
addOptions(program);
|
|
76
|
+
|
|
77
|
+
program.action(async () => {
|
|
78
|
+
await runInit(program.opts());
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
82
|
+
console.error(`Error: ${err.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-chat-gpt-repo-memory",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold Git-tracked repo memory files for ChatGPT and Codex-style coding workflows.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-chat-gpt-repo-memory": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src",
|
|
12
|
+
"templates",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"chatgpt",
|
|
21
|
+
"codex",
|
|
22
|
+
"openai",
|
|
23
|
+
"ai",
|
|
24
|
+
"agents",
|
|
25
|
+
"repository",
|
|
26
|
+
"project-map",
|
|
27
|
+
"repo-memory",
|
|
28
|
+
"developer-tools",
|
|
29
|
+
"cli"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"commander": "^12.1.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/gitignore.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const GITIGNORE_MARKER = ".agent-memory-local/";
|
|
5
|
+
const GITIGNORE_BLOCK = [
|
|
6
|
+
"# Local agent memory/cache",
|
|
7
|
+
".agent-memory-local/",
|
|
8
|
+
".agent-memory/**/*.db",
|
|
9
|
+
".agent-memory/**/*.sqlite",
|
|
10
|
+
".agent-memory/**/*.sqlite3",
|
|
11
|
+
".agent-memory/**/*.log"
|
|
12
|
+
].join("\n");
|
|
13
|
+
|
|
14
|
+
const LEGACY_PREFIX = "\\." + "chatgpt";
|
|
15
|
+
const LEGACY_PATTERNS = [
|
|
16
|
+
new RegExp("^# .*" + "chatgpt" + ".*$", "i"),
|
|
17
|
+
new RegExp(`^${LEGACY_PREFIX}-local/$`),
|
|
18
|
+
new RegExp(`^${LEGACY_PREFIX}/\\*\\*/\\*\\.db$`),
|
|
19
|
+
new RegExp(`^${LEGACY_PREFIX}/\\*\\*/\\*\\.sqlite$`),
|
|
20
|
+
new RegExp(`^${LEGACY_PREFIX}/\\*\\*/\\*\\.sqlite3$`),
|
|
21
|
+
new RegExp(`^${LEGACY_PREFIX}/\\*\\*/\\*\\.log$`)
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function stripLegacyLines(content) {
|
|
25
|
+
const lines = content.replace(/\r\n/g, "\n").split("\n");
|
|
26
|
+
const filtered = [];
|
|
27
|
+
let changed = false;
|
|
28
|
+
|
|
29
|
+
for (const line of lines) {
|
|
30
|
+
const isLegacy = LEGACY_PATTERNS.some((pattern) => pattern.test(line.trim()));
|
|
31
|
+
if (isLegacy) {
|
|
32
|
+
changed = true;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
filtered.push(line);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const normalized = filtered.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
40
|
+
return {
|
|
41
|
+
changed,
|
|
42
|
+
content: normalized
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function appendManagedBlock(content) {
|
|
47
|
+
const trimmed = content.replace(/\s*$/, "");
|
|
48
|
+
if (trimmed.length === 0) {
|
|
49
|
+
return `${GITIGNORE_BLOCK}\n`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return `${trimmed}\n\n${GITIGNORE_BLOCK}\n`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function updateGitignoreFile(rootDir) {
|
|
56
|
+
const gitignorePath = path.join(rootDir, ".gitignore");
|
|
57
|
+
let current = "";
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
current = await fs.readFile(gitignorePath, "utf8");
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (error && error.code !== "ENOENT") {
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { changed: removedLegacy, content: withoutLegacy } = stripLegacyLines(current);
|
|
68
|
+
|
|
69
|
+
if (withoutLegacy.includes(GITIGNORE_MARKER)) {
|
|
70
|
+
if (!removedLegacy) {
|
|
71
|
+
return "unchanged";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await fs.writeFile(gitignorePath, `${withoutLegacy.replace(/\s*$/, "")}\n`, "utf8");
|
|
75
|
+
return "updated";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const nextContent = appendManagedBlock(withoutLegacy);
|
|
79
|
+
await fs.writeFile(gitignorePath, nextContent, "utf8");
|
|
80
|
+
return "updated";
|
|
81
|
+
}
|
package/src/init.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createInterface } from "node:readline/promises";
|
|
4
|
+
import { updateGitignoreFile } from "./gitignore.js";
|
|
5
|
+
import { getProjectName } from "./projectName.js";
|
|
6
|
+
import { getPackageRoot } from "./paths.js";
|
|
7
|
+
import { applyTemplateVariables, validateTemplateName } from "./templateResolver.js";
|
|
8
|
+
|
|
9
|
+
const GENERATED_BY = "create-chat-gpt-repo-memory";
|
|
10
|
+
const MANAGED_AGENTS_START = "<!-- create-chat-gpt-repo-memory:start -->";
|
|
11
|
+
const MANAGED_AGENTS_END = "<!-- create-chat-gpt-repo-memory:end -->";
|
|
12
|
+
|
|
13
|
+
const FILES_TO_GENERATE = [
|
|
14
|
+
{ source: "AGENTS.md", target: "AGENTS.md" },
|
|
15
|
+
{ source: "project-map.md", target: ".agent-memory/project-map.md" },
|
|
16
|
+
{ source: "architecture.md", target: ".agent-memory/architecture.md" },
|
|
17
|
+
{ source: "conventions.md", target: ".agent-memory/conventions.md" },
|
|
18
|
+
{ source: "workflows.md", target: ".agent-memory/workflows.md" },
|
|
19
|
+
{ source: "update-project-map.md", target: ".agent-memory/update-project-map.md" },
|
|
20
|
+
{ source: "prompts/fill-project-map.md", target: ".agent-memory/prompts/fill-project-map.md" },
|
|
21
|
+
{ source: "prompts/start-session.md", target: ".agent-memory/prompts/start-session.md" }
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const packageRoot = getPackageRoot();
|
|
25
|
+
|
|
26
|
+
function normalizeNewlines(content) {
|
|
27
|
+
return content.replace(/\r\n/g, "\n");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createManagedAgentsBlock(renderedTemplate) {
|
|
31
|
+
const body = normalizeNewlines(renderedTemplate)
|
|
32
|
+
.replace(/^# .*?\n+/, "")
|
|
33
|
+
.trim();
|
|
34
|
+
|
|
35
|
+
return [
|
|
36
|
+
MANAGED_AGENTS_START,
|
|
37
|
+
"## Repo Memory Instructions",
|
|
38
|
+
"",
|
|
39
|
+
body,
|
|
40
|
+
MANAGED_AGENTS_END
|
|
41
|
+
].join("\n");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isRepoMemoryAwareAgentsFile(content) {
|
|
45
|
+
return [
|
|
46
|
+
".agent-memory/project-map.md",
|
|
47
|
+
".agent-memory/",
|
|
48
|
+
"Use AGENTS.md as your operating instructions",
|
|
49
|
+
"Project Memory Workflow"
|
|
50
|
+
].some((needle) => content.includes(needle));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function promptForAgentsConflict(relativeTarget) {
|
|
54
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
55
|
+
return "skip";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const readline = createInterface({
|
|
59
|
+
input: process.stdin,
|
|
60
|
+
output: process.stdout
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
while (true) {
|
|
65
|
+
const answer = (await readline.question(
|
|
66
|
+
`${relativeTarget} already exists and could not be merged automatically. Choose [s]kip or [o]verwrite: `
|
|
67
|
+
))
|
|
68
|
+
.trim()
|
|
69
|
+
.toLowerCase();
|
|
70
|
+
|
|
71
|
+
if (answer === "s" || answer === "skip") {
|
|
72
|
+
return "skip";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (answer === "o" || answer === "overwrite") {
|
|
76
|
+
return "overwrite";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} finally {
|
|
80
|
+
readline.close();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function handleExistingAgentsFile({
|
|
85
|
+
targetPath,
|
|
86
|
+
relativeTarget,
|
|
87
|
+
existingContent,
|
|
88
|
+
renderedContent,
|
|
89
|
+
result
|
|
90
|
+
}) {
|
|
91
|
+
const normalizedExisting = normalizeNewlines(existingContent);
|
|
92
|
+
const managedBlock = createManagedAgentsBlock(renderedContent);
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
normalizedExisting.includes(MANAGED_AGENTS_START) &&
|
|
96
|
+
normalizedExisting.includes(MANAGED_AGENTS_END)
|
|
97
|
+
) {
|
|
98
|
+
const nextContent = normalizedExisting.replace(
|
|
99
|
+
new RegExp(
|
|
100
|
+
`${MANAGED_AGENTS_START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${MANAGED_AGENTS_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`
|
|
101
|
+
),
|
|
102
|
+
managedBlock
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
if (nextContent === normalizedExisting) {
|
|
106
|
+
result.skipped.push(relativeTarget);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await fs.writeFile(targetPath, nextContent, "utf8");
|
|
111
|
+
result.overwritten.push(`${relativeTarget} (merged)`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!isRepoMemoryAwareAgentsFile(existingContent)) {
|
|
116
|
+
const nextContent = `${normalizedExisting.trimEnd()}\n\n${managedBlock}\n`;
|
|
117
|
+
await fs.writeFile(targetPath, nextContent, "utf8");
|
|
118
|
+
result.overwritten.push(`${relativeTarget} (merged)`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const choice = await promptForAgentsConflict(relativeTarget);
|
|
123
|
+
|
|
124
|
+
if (choice === "overwrite") {
|
|
125
|
+
await fs.writeFile(targetPath, renderedContent, "utf8");
|
|
126
|
+
result.overwritten.push(relativeTarget);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
result.skipped.push(relativeTarget);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function initChatGptRepoMemory(options) {
|
|
134
|
+
const rootDir = path.resolve(options.rootDir);
|
|
135
|
+
const template = options.template ?? "generic";
|
|
136
|
+
|
|
137
|
+
validateTemplateName(template);
|
|
138
|
+
|
|
139
|
+
const variables = {
|
|
140
|
+
PROJECT_NAME: getProjectName(rootDir),
|
|
141
|
+
TEMPLATE_NAME: template,
|
|
142
|
+
GENERATED_BY: GENERATED_BY
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const result = {
|
|
146
|
+
rootDir,
|
|
147
|
+
template,
|
|
148
|
+
created: [],
|
|
149
|
+
overwritten: [],
|
|
150
|
+
skipped: [],
|
|
151
|
+
gitignoreStatus: "skipped"
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
for (const file of FILES_TO_GENERATE) {
|
|
155
|
+
const templatePath = path.join(packageRoot, "templates", template, file.source);
|
|
156
|
+
const targetPath = path.join(rootDir, file.target);
|
|
157
|
+
const relativeTarget = path.relative(rootDir, targetPath) || file.target;
|
|
158
|
+
const templateContent = await fs.readFile(templatePath, "utf8");
|
|
159
|
+
const rendered = applyTemplateVariables(templateContent, variables);
|
|
160
|
+
|
|
161
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
162
|
+
|
|
163
|
+
let exists = false;
|
|
164
|
+
try {
|
|
165
|
+
await fs.access(targetPath);
|
|
166
|
+
exists = true;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (error && error.code !== "ENOENT") {
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!exists) {
|
|
174
|
+
await fs.writeFile(targetPath, rendered, "utf8");
|
|
175
|
+
result.created.push(relativeTarget.replace(/\\/g, "/"));
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (options.force) {
|
|
180
|
+
await fs.writeFile(targetPath, rendered, "utf8");
|
|
181
|
+
result.overwritten.push(relativeTarget.replace(/\\/g, "/"));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (file.target === "AGENTS.md") {
|
|
186
|
+
const existingContent = await fs.readFile(targetPath, "utf8");
|
|
187
|
+
await handleExistingAgentsFile({
|
|
188
|
+
targetPath,
|
|
189
|
+
relativeTarget: relativeTarget.replace(/\\/g, "/"),
|
|
190
|
+
existingContent,
|
|
191
|
+
renderedContent: rendered,
|
|
192
|
+
result
|
|
193
|
+
});
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
result.skipped.push(relativeTarget.replace(/\\/g, "/"));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (options.updateGitignore) {
|
|
201
|
+
result.gitignoreStatus = await updateGitignoreFile(rootDir);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return result;
|
|
205
|
+
}
|