letmecook 0.0.21 → 0.0.22
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/index.ts +85 -256
- package/package.json +5 -1
- package/src/agents-md.ts +12 -15
- package/src/cli-mode.ts +266 -0
- package/src/flows/add-repos.ts +51 -115
- package/src/flows/new-session.ts +58 -141
- package/src/flows/resume-session.ts +33 -37
- package/src/git.ts +39 -77
- package/src/naming.ts +1 -1
- package/src/splash.ts +199 -0
- package/src/tui-mode.ts +2 -0
- package/src/types.ts +4 -2
- package/src/ui/add-repos.ts +34 -26
- package/src/ui/common/repo-formatter.ts +4 -4
- package/src/ui/new-session.ts +2 -2
- package/src/ui/progress.ts +1 -1
- package/src/ui/renderer.ts +7 -14
- package/src/ui/session-settings.ts +4 -3
- package/src/reference-repo.ts +0 -288
package/index.ts
CHANGED
|
@@ -1,50 +1,73 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import pkg from "./package.json";
|
|
4
|
-
import { parseRepoSpec, type RepoSpec } from "./src/types";
|
|
5
|
-
import {
|
|
6
|
-
listSessions,
|
|
7
|
-
getSession,
|
|
8
|
-
updateLastAccessed,
|
|
9
|
-
deleteAllSessions,
|
|
10
|
-
deleteSession,
|
|
11
|
-
} from "./src/sessions";
|
|
12
|
-
import { createRenderer, destroyRenderer } from "./src/ui/renderer";
|
|
13
|
-
import { showNewSessionPrompt } from "./src/ui/new-session";
|
|
14
|
-
import { showSessionList } from "./src/ui/list";
|
|
15
|
-
import { showNukeConfirm } from "./src/ui/confirm-nuke";
|
|
16
|
-
import { createNewSession, resumeSession } from "./src/flows";
|
|
17
4
|
import { handleTUIMode } from "./src/tui-mode";
|
|
5
|
+
import { handleCLIMode } from "./src/cli-mode";
|
|
6
|
+
|
|
7
|
+
const block = (r: number, g: number, b: number): string => `\x1b[48;2;${r};${g};${b}m \x1b[0m`;
|
|
18
8
|
|
|
19
9
|
function printUsage(): void {
|
|
20
10
|
console.log(`
|
|
21
11
|
letmecook - Multi-repo workspace manager for AI coding sessions
|
|
22
12
|
|
|
23
13
|
Usage:
|
|
24
|
-
letmecook Launch interactive TUI (
|
|
14
|
+
letmecook Launch interactive TUI (default)
|
|
25
15
|
letmecook --tui Launch interactive TUI explicitly
|
|
26
|
-
letmecook <owner/repo> [
|
|
27
|
-
letmecook --list
|
|
28
|
-
letmecook --resume <session-name>
|
|
29
|
-
letmecook --delete <session-name>
|
|
30
|
-
letmecook --nuke [--yes]
|
|
16
|
+
letmecook --cli <owner/repo> [...] Create or resume a session (CLI mode)
|
|
17
|
+
letmecook --cli --list List all sessions
|
|
18
|
+
letmecook --cli --resume <session-name> Resume a session
|
|
19
|
+
letmecook --cli --delete <session-name> Delete a session
|
|
20
|
+
letmecook --cli --nuke [--yes] Nuke everything
|
|
31
21
|
letmecook --why Show why this tool exists
|
|
32
22
|
letmecook --help Show this help
|
|
33
23
|
letmecook --version Show version
|
|
34
24
|
|
|
35
25
|
Examples:
|
|
36
|
-
# Interactive mode (
|
|
26
|
+
# Interactive mode (default, recommended)
|
|
37
27
|
letmecook
|
|
38
28
|
|
|
39
|
-
# CLI mode
|
|
40
|
-
letmecook microsoft/playwright
|
|
41
|
-
letmecook facebook/react openai/agents
|
|
42
|
-
letmecook --resume playwright-agent-tests
|
|
29
|
+
# CLI mode (requires --cli prefix)
|
|
30
|
+
letmecook --cli microsoft/playwright
|
|
31
|
+
letmecook --cli facebook/react openai/agents
|
|
32
|
+
letmecook --cli --resume playwright-agent-tests
|
|
43
33
|
`);
|
|
44
34
|
}
|
|
45
35
|
|
|
46
36
|
function printWhy(): void {
|
|
37
|
+
const palette: Record<string, string> = {
|
|
38
|
+
".": " ",
|
|
39
|
+
s: block(200, 200, 200), // steam
|
|
40
|
+
d: block(88, 62, 52), // dark brown
|
|
41
|
+
l: block(121, 85, 72), // light brown (crust)
|
|
42
|
+
r: block(214, 64, 36), // red (pepperoni)
|
|
43
|
+
o: block(245, 124, 0), // orange
|
|
44
|
+
y: block(255, 193, 7), // yellow (cheese)
|
|
45
|
+
Y: block(255, 220, 80), // bright yellow (cheese highlight)
|
|
46
|
+
g: block(76, 175, 80), // green (basil)
|
|
47
|
+
k: block(20, 20, 20), // black (nori)
|
|
48
|
+
w: block(236, 236, 236), // white (rice)
|
|
49
|
+
b: block(79, 118, 170), // blue (fish)
|
|
50
|
+
};
|
|
51
|
+
const arts = [
|
|
52
|
+
// Pizza slice (7x7)
|
|
53
|
+
["..yy...", ".yyyy..", ".yryry.", "yyyyyyy", "yygyrry", "lllllll", "ddddddd"],
|
|
54
|
+
// Burger (7x7)
|
|
55
|
+
[".yyyyy.", "ggggggg", "rrrrrrr", "ddddddd", "ggggggg", "ooooooo", ".yyyyy."],
|
|
56
|
+
// Fried egg (7x7)
|
|
57
|
+
["..www..", ".wwwww.", "wwwyyww", "wwyyyyw", "wwwyyww", ".wwwww.", "..www.."],
|
|
58
|
+
];
|
|
59
|
+
const artRows = arts[Math.floor(Math.random() * arts.length)]!;
|
|
60
|
+
const art = artRows
|
|
61
|
+
.map((row) =>
|
|
62
|
+
row
|
|
63
|
+
.split("")
|
|
64
|
+
.map((cell) => palette[cell] ?? " ")
|
|
65
|
+
.join(""),
|
|
66
|
+
)
|
|
67
|
+
.join("\n");
|
|
47
68
|
console.log(`
|
|
69
|
+
${art}
|
|
70
|
+
|
|
48
71
|
Your dev folder is full of traps: outdated code, abandoned experiments, naming
|
|
49
72
|
collisions that send agents down rabbit holes until they hit context limits.
|
|
50
73
|
|
|
@@ -54,257 +77,63 @@ Agents are good at problem-solving when you give them what they need and let the
|
|
|
54
77
|
`);
|
|
55
78
|
}
|
|
56
79
|
|
|
57
|
-
async function handleNewSessionCLI(repos: RepoSpec[]): Promise<void> {
|
|
58
|
-
const renderer = await createRenderer();
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
const { goal, cancelled } = await showNewSessionPrompt(renderer, repos);
|
|
62
|
-
|
|
63
|
-
if (cancelled) {
|
|
64
|
-
destroyRenderer();
|
|
65
|
-
console.log("\nCancelled.");
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const result = await createNewSession(renderer, {
|
|
70
|
-
repos,
|
|
71
|
-
goal,
|
|
72
|
-
mode: "cli",
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
if (!result) {
|
|
76
|
-
destroyRenderer();
|
|
77
|
-
console.log("\nCancelled.");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const { session, skipped } = result;
|
|
82
|
-
|
|
83
|
-
if (skipped) {
|
|
84
|
-
destroyRenderer();
|
|
85
|
-
console.log(`\nResuming existing session: ${session.name}\n`);
|
|
86
|
-
await resumeSession(renderer, {
|
|
87
|
-
session,
|
|
88
|
-
mode: "cli",
|
|
89
|
-
initialRefresh: true,
|
|
90
|
-
});
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
destroyRenderer();
|
|
95
|
-
console.log(`\nSession created: ${session.name}`);
|
|
96
|
-
console.log(`Path: ${session.path}\n`);
|
|
97
|
-
|
|
98
|
-
await resumeSession(renderer, {
|
|
99
|
-
session,
|
|
100
|
-
mode: "cli",
|
|
101
|
-
initialRefresh: false,
|
|
102
|
-
});
|
|
103
|
-
} catch (error) {
|
|
104
|
-
destroyRenderer();
|
|
105
|
-
console.error("\nError:", error instanceof Error ? error.message : error);
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function handleList(): Promise<void> {
|
|
111
|
-
const renderer = await createRenderer();
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
while (true) {
|
|
115
|
-
const sessions = await listSessions();
|
|
116
|
-
const action = await showSessionList(renderer, sessions);
|
|
117
|
-
|
|
118
|
-
switch (action.type) {
|
|
119
|
-
case "resume":
|
|
120
|
-
destroyRenderer();
|
|
121
|
-
await updateLastAccessed(action.session.name);
|
|
122
|
-
console.log(`\nResuming session: ${action.session.name}\n`);
|
|
123
|
-
await resumeSession(renderer, {
|
|
124
|
-
session: action.session,
|
|
125
|
-
mode: "cli",
|
|
126
|
-
initialRefresh: true,
|
|
127
|
-
});
|
|
128
|
-
return;
|
|
129
|
-
|
|
130
|
-
case "delete":
|
|
131
|
-
console.log("[TODO] Delete session flow");
|
|
132
|
-
break;
|
|
133
|
-
|
|
134
|
-
case "nuke": {
|
|
135
|
-
const choice = await showNukeConfirm(renderer, sessions.length);
|
|
136
|
-
if (choice === "confirm") {
|
|
137
|
-
const count = await deleteAllSessions();
|
|
138
|
-
destroyRenderer();
|
|
139
|
-
console.log(`\nNuked ${count} session(s) and all data.`);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
case "quit":
|
|
146
|
-
destroyRenderer();
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
} catch (error) {
|
|
151
|
-
destroyRenderer();
|
|
152
|
-
console.error("\nError:", error instanceof Error ? error.message : error);
|
|
153
|
-
process.exit(1);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async function handleResume(sessionName: string): Promise<void> {
|
|
158
|
-
const session = await getSession(sessionName);
|
|
159
|
-
|
|
160
|
-
if (!session) {
|
|
161
|
-
console.error(`Session not found: ${sessionName}`);
|
|
162
|
-
console.log("\nAvailable sessions:");
|
|
163
|
-
const sessions = await listSessions();
|
|
164
|
-
if (sessions.length === 0) {
|
|
165
|
-
console.log(" (none)");
|
|
166
|
-
} else {
|
|
167
|
-
sessions.forEach((s) => console.log(` - ${s.name}`));
|
|
168
|
-
}
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
await updateLastAccessed(session.name);
|
|
173
|
-
console.log(`\nResuming session: ${session.name}\n`);
|
|
174
|
-
|
|
175
|
-
const renderer = await createRenderer();
|
|
176
|
-
await resumeSession(renderer, {
|
|
177
|
-
session,
|
|
178
|
-
mode: "cli",
|
|
179
|
-
initialRefresh: true,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async function handleDelete(sessionName: string): Promise<void> {
|
|
184
|
-
const session = await getSession(sessionName);
|
|
185
|
-
|
|
186
|
-
if (!session) {
|
|
187
|
-
console.error(`Session not found: ${sessionName}`);
|
|
188
|
-
const sessions = await listSessions();
|
|
189
|
-
if (sessions.length > 0) {
|
|
190
|
-
console.log("\nAvailable sessions:");
|
|
191
|
-
sessions.forEach((s) => console.log(` - ${s.name}`));
|
|
192
|
-
}
|
|
193
|
-
process.exit(1);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const deleted = await deleteSession(sessionName);
|
|
197
|
-
if (deleted) {
|
|
198
|
-
console.log(`Deleted session: ${sessionName}`);
|
|
199
|
-
} else {
|
|
200
|
-
console.error(`Failed to delete session: ${sessionName}`);
|
|
201
|
-
process.exit(1);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async function handleNuke(skipConfirm = false): Promise<void> {
|
|
206
|
-
const sessions = await listSessions();
|
|
207
|
-
if (sessions.length === 0) {
|
|
208
|
-
console.log("Nothing to nuke.");
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Skip confirmation if --yes flag or non-interactive (piped input)
|
|
213
|
-
if (skipConfirm || !process.stdin.isTTY) {
|
|
214
|
-
const count = await deleteAllSessions();
|
|
215
|
-
console.log(`Nuked ${count} session(s) and all data.`);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const renderer = await createRenderer();
|
|
220
|
-
const choice = await showNukeConfirm(renderer, sessions.length);
|
|
221
|
-
destroyRenderer();
|
|
222
|
-
|
|
223
|
-
if (choice === "confirm") {
|
|
224
|
-
const count = await deleteAllSessions();
|
|
225
|
-
console.log(`Nuked ${count} session(s) and all data.`);
|
|
226
|
-
} else {
|
|
227
|
-
console.log("Cancelled.");
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async function handleCLIMode(args: string[]): Promise<void> {
|
|
232
|
-
const firstArg = args[0];
|
|
233
|
-
|
|
234
|
-
if (firstArg === "--list" || firstArg === "-l") {
|
|
235
|
-
await handleList();
|
|
236
|
-
} else if (firstArg === "--resume" || firstArg === "-r") {
|
|
237
|
-
const sessionName = args[1];
|
|
238
|
-
if (!sessionName) {
|
|
239
|
-
console.error("Missing session name. Usage: letmecook --resume <session-name>");
|
|
240
|
-
process.exit(1);
|
|
241
|
-
}
|
|
242
|
-
await handleResume(sessionName);
|
|
243
|
-
} else if (firstArg === "--delete" || firstArg === "-d") {
|
|
244
|
-
const sessionName = args[1];
|
|
245
|
-
if (!sessionName) {
|
|
246
|
-
console.error("Missing session name. Usage: letmecook --delete <session-name>");
|
|
247
|
-
process.exit(1);
|
|
248
|
-
}
|
|
249
|
-
await handleDelete(sessionName);
|
|
250
|
-
} else if (firstArg === "--nuke") {
|
|
251
|
-
const hasYes = args.includes("--yes") || args.includes("-y");
|
|
252
|
-
await handleNuke(hasYes);
|
|
253
|
-
} else if (firstArg?.startsWith("-")) {
|
|
254
|
-
console.error(`Unknown option: ${firstArg}`);
|
|
255
|
-
printUsage();
|
|
256
|
-
process.exit(1);
|
|
257
|
-
} else {
|
|
258
|
-
try {
|
|
259
|
-
const repos = parseRepos(args);
|
|
260
|
-
await handleNewSessionCLI(repos);
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
263
|
-
process.exit(1);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function parseRepos(args: string[]): RepoSpec[] {
|
|
269
|
-
const repos: RepoSpec[] = [];
|
|
270
|
-
|
|
271
|
-
for (const arg of args) {
|
|
272
|
-
if (!arg || arg.startsWith("-")) continue;
|
|
273
|
-
|
|
274
|
-
if (!arg.includes("/")) {
|
|
275
|
-
throw new Error(`Invalid repo format: ${arg} (expected owner/repo)`);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const repo = parseRepoSpec(arg);
|
|
279
|
-
repos.push(repo);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return repos;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
80
|
console.clear();
|
|
286
81
|
const args = process.argv.slice(2);
|
|
287
82
|
const firstArg = args[0];
|
|
288
83
|
|
|
84
|
+
// Version flag
|
|
289
85
|
if (firstArg === "--version" || firstArg === "-v") {
|
|
290
86
|
console.log(`letmecook v${pkg.version}`);
|
|
291
87
|
process.exit(0);
|
|
292
88
|
}
|
|
293
89
|
|
|
90
|
+
// Why flag
|
|
294
91
|
if (firstArg === "--why") {
|
|
295
92
|
printWhy();
|
|
296
93
|
process.exit(0);
|
|
297
94
|
}
|
|
298
95
|
|
|
299
|
-
|
|
96
|
+
// Help flag
|
|
97
|
+
if (firstArg === "--help" || firstArg === "-h") {
|
|
300
98
|
printUsage();
|
|
301
99
|
process.exit(0);
|
|
302
100
|
}
|
|
303
101
|
|
|
102
|
+
// CLI mode with --cli prefix
|
|
103
|
+
if (firstArg === "--cli") {
|
|
104
|
+
const cliArgs = args.slice(1);
|
|
105
|
+
await handleCLIMode(cliArgs);
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Explicit TUI mode
|
|
304
110
|
if (firstArg === "--tui") {
|
|
305
111
|
await handleTUIMode();
|
|
306
|
-
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Default: TUI mode (no args)
|
|
116
|
+
if (args.length === 0) {
|
|
307
117
|
await handleTUIMode();
|
|
308
|
-
|
|
309
|
-
await handleCLIMode(args);
|
|
118
|
+
process.exit(0);
|
|
310
119
|
}
|
|
120
|
+
|
|
121
|
+
// Catch bare repo args without --cli prefix
|
|
122
|
+
if (firstArg && !firstArg.startsWith("-") && firstArg.includes("/")) {
|
|
123
|
+
console.error(`Error: Repo arguments require --cli prefix.`);
|
|
124
|
+
console.log(`\nUsage: letmecook --cli ${args.join(" ")}`);
|
|
125
|
+
console.log(`\nOr launch the interactive TUI: letmecook`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Unknown flag
|
|
130
|
+
if (firstArg?.startsWith("-")) {
|
|
131
|
+
console.error(`Unknown option: ${firstArg}`);
|
|
132
|
+
printUsage();
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Unknown positional argument that's not a repo
|
|
137
|
+
console.error(`Unknown argument: ${firstArg}`);
|
|
138
|
+
printUsage();
|
|
139
|
+
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "letmecook",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/rustydotwtf/letmecook.git"
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"format:check": "oxfmt --check .",
|
|
29
29
|
"check": "bun run typecheck && bun run lint && bun run format:check",
|
|
30
30
|
"fix": "bun run lint:fix && bun run format",
|
|
31
|
+
"test": "bun test",
|
|
32
|
+
"test:unit": "bun test tests/unit",
|
|
33
|
+
"test:integration": "bun test tests/integration",
|
|
34
|
+
"test:tui": "bun test tests/tui",
|
|
31
35
|
"docs": "cd docs && bun start",
|
|
32
36
|
"docs:build": "cd docs && bun run build",
|
|
33
37
|
"docs:serve": "cd docs && bun run serve"
|
package/src/agents-md.ts
CHANGED
|
@@ -11,19 +11,19 @@ export function generateAgentsMd(session: Session): string {
|
|
|
11
11
|
minute: "2-digit",
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const hasReadOnlyRepos = session.repos.some((repo) => repo.readOnly);
|
|
15
15
|
const hasSkills = session.skills && session.skills.length > 0;
|
|
16
16
|
|
|
17
17
|
const repoRows = session.repos
|
|
18
18
|
.map((repo) => {
|
|
19
19
|
const branch = repo.branch || "default";
|
|
20
20
|
const url = `https://github.com/${repo.owner}/${repo.name}`;
|
|
21
|
-
const
|
|
22
|
-
return `| \`${repo.dir}/\` | [${repo.owner}/${repo.name}](${url}) | ${branch} | ${
|
|
21
|
+
const readOnlyStatus = repo.readOnly ? "**YES**" : "no";
|
|
22
|
+
return `| \`${repo.dir}/\` | [${repo.owner}/${repo.name}](${url}) | ${branch} | ${readOnlyStatus} |`;
|
|
23
23
|
})
|
|
24
24
|
.join("\n");
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const readOnlyRepos = session.repos.filter((repo) => repo.readOnly);
|
|
27
27
|
|
|
28
28
|
const skillsSection = hasSkills
|
|
29
29
|
? `
|
|
@@ -37,24 +37,21 @@ These skills are available for use in this session and are automatically updated
|
|
|
37
37
|
`
|
|
38
38
|
: "";
|
|
39
39
|
|
|
40
|
-
const
|
|
40
|
+
const readOnlyWarning = hasReadOnlyRepos
|
|
41
41
|
? `
|
|
42
|
-
## ⚠️
|
|
42
|
+
## ⚠️ Read-Only Repositories
|
|
43
43
|
|
|
44
|
-
**WARNING: The following repositories are
|
|
44
|
+
**WARNING: The following repositories are marked as READ-ONLY:**
|
|
45
45
|
|
|
46
|
-
${
|
|
46
|
+
${readOnlyRepos.map((repo) => `- \`${repo.dir}/\` (${repo.owner}/${repo.name})`).join("\n")}
|
|
47
47
|
|
|
48
48
|
**AI agents must NOT:**
|
|
49
49
|
- Create, modify, or delete any files in these directories
|
|
50
50
|
- Make commits affecting these repositories
|
|
51
51
|
- Use bash commands to circumvent file permissions
|
|
52
52
|
|
|
53
|
-
**Why are these
|
|
54
|
-
|
|
55
|
-
- Any modifications would affect ALL sessions using this repository
|
|
56
|
-
- They are automatically refreshed to latest before each session resume
|
|
57
|
-
- They are included for reference only - the user wants to read and understand the code without risk of accidental modifications
|
|
53
|
+
**Why are these read-only?**
|
|
54
|
+
These repositories are included for reference only. The user wants to read and understand the code without risk of accidental modifications.
|
|
58
55
|
`
|
|
59
56
|
: "";
|
|
60
57
|
|
|
@@ -66,10 +63,10 @@ ${session.goal ? `> ${session.goal}\n` : ""}
|
|
|
66
63
|
|
|
67
64
|
## Repositories
|
|
68
65
|
|
|
69
|
-
| Directory | Repository | Branch |
|
|
66
|
+
| Directory | Repository | Branch | Read-Only |
|
|
70
67
|
|-----------|------------|--------|-----------|
|
|
71
68
|
${repoRows}
|
|
72
|
-
${
|
|
69
|
+
${readOnlyWarning}
|
|
73
70
|
${skillsSection}
|
|
74
71
|
## Important Notes
|
|
75
72
|
|