letmecook 0.0.15 → 0.0.17
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/package.json +1 -1
- package/src/agents-md.ts +16 -27
- package/src/flows/add-repos.ts +132 -22
- package/src/flows/edit-session.ts +86 -15
- package/src/flows/new-session.ts +159 -34
- package/src/flows/resume-session.ts +53 -33
- package/src/git.ts +77 -39
- package/src/process-registry.ts +179 -0
- package/src/reference-repo.ts +288 -0
- package/src/tui-mode.ts +14 -1
- package/src/types.ts +2 -4
- package/src/ui/add-repos.ts +26 -70
- package/src/ui/background-warning.ts +196 -0
- package/src/ui/common/command-runner.ts +270 -69
- package/src/ui/common/keyboard.ts +26 -0
- package/src/ui/common/repo-formatter.ts +4 -9
- package/src/ui/new-session.ts +2 -3
- package/src/ui/progress.ts +1 -1
- package/src/ui/session-settings.ts +2 -17
- package/src/utils/stream.ts +89 -0
package/src/ui/new-session.ts
CHANGED
|
@@ -27,11 +27,10 @@ export function showNewSessionPrompt(
|
|
|
27
27
|
|
|
28
28
|
repos.forEach((repo, i) => {
|
|
29
29
|
const branch = repo.branch ? ` (${repo.branch})` : " (default)";
|
|
30
|
-
const
|
|
31
|
-
const latestMarker = repo.latest ? " [Latest]" : "";
|
|
30
|
+
const refMarker = repo.reference ? " [Ref]" : "";
|
|
32
31
|
const repoText = new TextRenderable(renderer, {
|
|
33
32
|
id: `repo-${i}`,
|
|
34
|
-
content: ` - ${repo.owner}/${repo.name}${branch}${
|
|
33
|
+
content: ` - ${repo.owner}/${repo.name}${branch}${refMarker}`,
|
|
35
34
|
fg: "#94a3b8",
|
|
36
35
|
});
|
|
37
36
|
content.add(repoText);
|
package/src/ui/progress.ts
CHANGED
|
@@ -52,7 +52,7 @@ function getPhasePresentation(phase: ProgressPhase): { content: string; fg: stri
|
|
|
52
52
|
case "installing-skills":
|
|
53
53
|
return { content: "Installing skills...", fg: "#38bdf8" };
|
|
54
54
|
case "refreshing":
|
|
55
|
-
return { content: "Refreshing
|
|
55
|
+
return { content: "Refreshing reference repositories...", fg: "#38bdf8" };
|
|
56
56
|
case "done":
|
|
57
57
|
return { content: "Ready!", fg: "#22c55e" };
|
|
58
58
|
default:
|
|
@@ -208,7 +208,7 @@ export function showSessionSettings(
|
|
|
208
208
|
if (selectedTarget === "goal") {
|
|
209
209
|
customActions.push("Enter Edit");
|
|
210
210
|
} else if (selectedTarget === "repo") {
|
|
211
|
-
customActions.push("r Toggle
|
|
211
|
+
customActions.push("r Toggle Ref", "a Add repos");
|
|
212
212
|
} else if (selectedTarget === "skill") {
|
|
213
213
|
customActions.push("x Remove", "a Add repos");
|
|
214
214
|
}
|
|
@@ -342,22 +342,7 @@ export function showSessionSettings(
|
|
|
342
342
|
if (key.name === "r" && selectedTarget === "repo") {
|
|
343
343
|
const repo = updatedRepos[selectedRepoIndex];
|
|
344
344
|
if (repo) {
|
|
345
|
-
repo.
|
|
346
|
-
if (!repo.readOnly) {
|
|
347
|
-
repo.latest = false;
|
|
348
|
-
}
|
|
349
|
-
updateReposList();
|
|
350
|
-
}
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (key.name === "l" && selectedTarget === "repo") {
|
|
355
|
-
const repo = updatedRepos[selectedRepoIndex];
|
|
356
|
-
if (repo) {
|
|
357
|
-
repo.latest = !repo.latest;
|
|
358
|
-
if (repo.latest) {
|
|
359
|
-
repo.readOnly = true;
|
|
360
|
-
}
|
|
345
|
+
repo.reference = !repo.reference;
|
|
361
346
|
updateReposList();
|
|
362
347
|
}
|
|
363
348
|
return;
|
package/src/utils/stream.ts
CHANGED
|
@@ -51,6 +51,12 @@ interface ReadProcessOutputWithBufferOptions {
|
|
|
51
51
|
onBufferUpdate?: (buffer: string[]) => void;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export interface ReadWithControlOptions {
|
|
55
|
+
maxBufferLines?: number;
|
|
56
|
+
onBufferUpdate?: (buffer: string[]) => void;
|
|
57
|
+
shouldStop?: () => boolean; // Check if we should stop early
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
export async function readProcessOutputWithBuffer(
|
|
55
61
|
proc: ReturnType<typeof Bun.spawn>,
|
|
56
62
|
options?: ReadProcessOutputWithBufferOptions,
|
|
@@ -106,3 +112,86 @@ export async function readProcessOutputWithBuffer(
|
|
|
106
112
|
fullOutput: fullOutputParts.join(""),
|
|
107
113
|
};
|
|
108
114
|
}
|
|
115
|
+
|
|
116
|
+
export async function readProcessOutputWithControl(
|
|
117
|
+
proc: ReturnType<typeof Bun.spawn>,
|
|
118
|
+
options?: ReadWithControlOptions,
|
|
119
|
+
): Promise<{ success: boolean; output: string[]; fullOutput: string; wasInterrupted: boolean }> {
|
|
120
|
+
const { maxBufferLines, onBufferUpdate, shouldStop } = options || {};
|
|
121
|
+
const outputBuffer: string[] = [];
|
|
122
|
+
let wasInterrupted = false;
|
|
123
|
+
|
|
124
|
+
const addLine = (line: string) => {
|
|
125
|
+
const trimmed = line.trim();
|
|
126
|
+
if (trimmed) {
|
|
127
|
+
outputBuffer.push(trimmed);
|
|
128
|
+
if (maxBufferLines && outputBuffer.length > maxBufferLines) {
|
|
129
|
+
outputBuffer.shift();
|
|
130
|
+
}
|
|
131
|
+
onBufferUpdate?.([...outputBuffer]);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const fullOutputParts: string[] = [];
|
|
136
|
+
|
|
137
|
+
const readStream = async (stream: ReadableStream<Uint8Array> | number | undefined) => {
|
|
138
|
+
if (!stream || typeof stream === "number") return;
|
|
139
|
+
|
|
140
|
+
const reader = stream.getReader();
|
|
141
|
+
const decoder = new TextDecoder();
|
|
142
|
+
let buffer = "";
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
while (true) {
|
|
146
|
+
// Check if we should stop before each read
|
|
147
|
+
if (shouldStop?.()) {
|
|
148
|
+
wasInterrupted = true;
|
|
149
|
+
reader.releaseLock();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const { done, value } = await reader.read();
|
|
154
|
+
if (done) break;
|
|
155
|
+
|
|
156
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
157
|
+
fullOutputParts.push(chunk);
|
|
158
|
+
buffer += chunk;
|
|
159
|
+
|
|
160
|
+
const lines = buffer.split(/[\r\n]+/);
|
|
161
|
+
buffer = lines.pop() || "";
|
|
162
|
+
|
|
163
|
+
for (const line of lines) {
|
|
164
|
+
addLine(line);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check again after processing
|
|
168
|
+
if (shouldStop?.()) {
|
|
169
|
+
wasInterrupted = true;
|
|
170
|
+
reader.releaseLock();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (buffer.trim()) {
|
|
176
|
+
addLine(buffer);
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
// Stream may have been cancelled, that's ok
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
await Promise.all([readStream(proc.stdout), readStream(proc.stderr)]);
|
|
184
|
+
|
|
185
|
+
// Only wait for exit if not interrupted
|
|
186
|
+
let exitCode = 1;
|
|
187
|
+
if (!wasInterrupted) {
|
|
188
|
+
exitCode = await proc.exited;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
success: !wasInterrupted && exitCode === 0,
|
|
193
|
+
output: outputBuffer,
|
|
194
|
+
fullOutput: fullOutputParts.join(""),
|
|
195
|
+
wasInterrupted,
|
|
196
|
+
};
|
|
197
|
+
}
|