letmecook 0.0.21 → 0.0.23

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.
@@ -22,13 +22,14 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
22
22
 
23
23
  const repos: RepoSpec[] = [];
24
24
  let currentInput = "";
25
- let currentReference = false;
25
+ let currentReadOnly = false;
26
+ let currentLatest = false;
26
27
  let currentValidRepo: RepoSpec | null = null;
27
28
  let selectedMatchIndex = -1; // -1 means no match selected, user is typing freely
28
29
  let lastQuery = ""; // Track the query that generated current matches
29
30
  let isNavigating = false; // Flag to prevent input handler from resetting when navigating
30
31
  let isConfirming = false; // Flag for confirmation mode (showing checkboxes)
31
- let confirmOptionIndex = 0; // 0 = reference, 1 = confirm button
32
+ let confirmOptionIndex = 0; // 0 = read-only, 1 = confirm button
32
33
 
33
34
  // Repository input
34
35
  const repoLabel = new TextRenderable(renderer, {
@@ -78,13 +79,13 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
78
79
  });
79
80
  content.add(detailsLabel);
80
81
 
81
- const detailsReference = new TextRenderable(renderer, {
82
- id: "details-reference",
82
+ const detailsLatest = new TextRenderable(renderer, {
83
+ id: "details-latest",
83
84
  content: "",
84
85
  fg: "#94a3b8",
85
86
  marginTop: 0,
86
87
  });
87
- content.add(detailsReference);
88
+ content.add(detailsLatest);
88
89
 
89
90
  const confirmButton = new TextRenderable(renderer, {
90
91
  id: "confirm-button",
@@ -103,7 +104,8 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
103
104
  const repo = validateRepo(currentInput.trim());
104
105
  currentValidRepo = repo;
105
106
  if (repo) {
106
- currentReference = false;
107
+ currentReadOnly = false;
108
+ currentLatest = false;
107
109
  }
108
110
  } else {
109
111
  statusText.content = "";
@@ -151,8 +153,8 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
151
153
  } else {
152
154
  reposList.content = repos
153
155
  .map((repo, i) => {
154
- const refMarker = repo.reference ? " [Ref]" : "";
155
- return ` ${i + 1}. ${repo.spec}${refMarker}`;
156
+ const roMarker = repo.readOnly ? " [Read-only]" : "";
157
+ return ` ${i + 1}. ${repo.spec}${roMarker}`;
156
158
  })
157
159
  .join("\n");
158
160
  reposList.fg = "#94a3b8";
@@ -165,22 +167,22 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
165
167
  detailsLabel.content = `\nConfigure options for: ${currentInput.trim()}`;
166
168
  detailsLabel.fg = "#38bdf8";
167
169
 
168
- const refCheckbox = currentReference ? "[✓]" : "[ ]";
169
- const refSelected = confirmOptionIndex === 0;
170
- detailsReference.content = ` ${refSelected ? "▶" : " "} ${refCheckbox} Reference [r] (read-only, shared cache, auto-refresh)`;
171
- detailsReference.fg = refSelected ? "#f8fafc" : currentReference ? "#22d3ee" : "#94a3b8";
170
+ const latestCheckbox = currentLatest ? "[✓]" : "[ ]";
171
+ const latestSelected = confirmOptionIndex === 0;
172
+ detailsLatest.content = ` ${latestSelected ? "▶" : " "} ${latestCheckbox} Read-only [l]`;
173
+ detailsLatest.fg = latestSelected ? "#f8fafc" : currentLatest ? "#22d3ee" : "#94a3b8";
172
174
 
173
175
  const confirmSelected = confirmOptionIndex === 1;
174
176
  confirmButton.content = ` ${confirmSelected ? "▶" : " "} [Add repository]`;
175
177
  confirmButton.fg = confirmSelected ? "#10b981" : "#64748b";
176
178
  } else if (currentValidRepo) {
177
179
  detailsLabel.content = "\nPress Enter to configure options";
178
- detailsLabel.fg = "#64748b";
179
- detailsReference.content = "";
180
+ detailsLabel.fg = "#64798b";
181
+ detailsLatest.content = "";
180
182
  confirmButton.content = "";
181
183
  } else {
182
184
  detailsLabel.content = "";
183
- detailsReference.content = "";
185
+ detailsLatest.content = "";
184
186
  confirmButton.content = "";
185
187
  }
186
188
  }
@@ -250,7 +252,8 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
250
252
  const repo = validateRepo(selectedMatch.trim());
251
253
  currentValidRepo = repo;
252
254
  if (repo) {
253
- currentReference = false;
255
+ currentReadOnly = false;
256
+ currentLatest = false;
254
257
  }
255
258
 
256
259
  updateMatches(); // Refresh display with new selection (matches stay the same, just highlight changes)
@@ -271,13 +274,15 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
271
274
  }
272
275
 
273
276
  const repoToAdd = { ...currentValidRepo };
274
- repoToAdd.reference = currentReference;
277
+ repoToAdd.readOnly = currentReadOnly;
278
+ repoToAdd.latest = currentLatest;
275
279
  repos.push(repoToAdd);
276
280
 
277
281
  currentInput = "";
278
282
  repoInput.value = "";
279
283
  currentValidRepo = null;
280
- currentReference = false;
284
+ currentReadOnly = false;
285
+ currentLatest = false;
281
286
  updateReposList();
282
287
  lastQuery = "";
283
288
  selectedMatchIndex = -1;
@@ -289,7 +294,7 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
289
294
 
290
295
  function enterConfirmMode() {
291
296
  isConfirming = true;
292
- confirmOptionIndex = 1; // Start on confirm button for quick add
297
+ confirmOptionIndex = 2; // Start on confirm button for quick add
293
298
  repoInput.blur();
294
299
  updateDetails();
295
300
  updateFooter();
@@ -305,8 +310,9 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
305
310
 
306
311
  function toggleCurrentOption() {
307
312
  if (confirmOptionIndex === 0) {
308
- // Toggle reference
309
- currentReference = !currentReference;
313
+ // Toggle read-only
314
+ currentLatest = !currentLatest;
315
+ currentReadOnly = currentLatest;
310
316
  } else if (confirmOptionIndex === 1) {
311
317
  // Confirm button - add the repo
312
318
  addCurrentRepo();
@@ -321,7 +327,7 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
321
327
  navigate: true,
322
328
  select: false,
323
329
  back: true,
324
- custom: ["r Reference", "space Toggle", "enter Add"],
330
+ custom: ["l Read-only", "space Toggle", "enter Add"],
325
331
  });
326
332
  } else {
327
333
  showFooter(renderer, content, {
@@ -348,9 +354,10 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
348
354
 
349
355
  // Confirmation mode handling
350
356
  if (isConfirming) {
351
- // Toggle reference with 'r' hotkey
352
- if (key.name === "r") {
353
- currentReference = !currentReference;
357
+ // Toggle read-only with 'l' hotkey
358
+ if (key.name === "l") {
359
+ currentLatest = !currentLatest;
360
+ currentReadOnly = currentLatest;
354
361
  updateDetails();
355
362
  return;
356
363
  }
@@ -446,7 +453,8 @@ export async function showAddReposPrompt(renderer: CliRenderer): Promise<AddRepo
446
453
  const repo = validateRepo(value.trim());
447
454
  currentValidRepo = repo;
448
455
  if (repo) {
449
- currentReference = false;
456
+ currentReadOnly = false;
457
+ currentLatest = false;
450
458
  }
451
459
  } else {
452
460
  statusText.content = "";
@@ -8,7 +8,15 @@ export interface AgentProposal {
8
8
  goal?: string;
9
9
  }
10
10
 
11
- export function showAgentProposal(renderer: CliRenderer, proposal: AgentProposal): void {
11
+ export interface AgentProposalResult {
12
+ sessionNameText: TextRenderable;
13
+ content: ReturnType<typeof createBaseLayout>["content"];
14
+ }
15
+
16
+ export function showAgentProposal(
17
+ renderer: CliRenderer,
18
+ proposal: AgentProposal,
19
+ ): AgentProposalResult {
12
20
  clearLayout(renderer);
13
21
 
14
22
  const { content } = createBaseLayout(renderer, "Agent Proposal");
@@ -77,4 +85,8 @@ export function showAgentProposal(renderer: CliRenderer, proposal: AgentProposal
77
85
  marginTop: 1,
78
86
  });
79
87
  content.add(continueText);
88
+
89
+ renderer.requestRender();
90
+
91
+ return { sessionNameText, content };
80
92
  }
@@ -0,0 +1,151 @@
1
+ import { type CliRenderer, TextRenderable, type KeyEvent } from "@opentui/core";
2
+ import { createBaseLayout, clearLayout } from "./renderer";
3
+ import { showFooter, hideFooter } from "./common/footer";
4
+ import { isEnter, isEscape, isKey } from "./common/keyboard";
5
+ import type { ChatConfig } from "../flows/chat-to-config";
6
+
7
+ export type ConfirmationAction = "confirm" | "edit" | "cancel" | "back";
8
+
9
+ export interface ConfirmationResult {
10
+ action: ConfirmationAction;
11
+ }
12
+
13
+ export function showChatConfirmation(
14
+ renderer: CliRenderer,
15
+ config: ChatConfig,
16
+ ): Promise<ConfirmationResult> {
17
+ return new Promise((resolve) => {
18
+ clearLayout(renderer);
19
+
20
+ const { content } = createBaseLayout(renderer, "Review Configuration");
21
+
22
+ // Title
23
+ const title = new TextRenderable(renderer, {
24
+ id: "confirm-title",
25
+ content: "Here's what I'll set up for you:",
26
+ fg: "#e2e8f0",
27
+ marginBottom: 2,
28
+ });
29
+ content.add(title);
30
+
31
+ // Repositories
32
+ const reposLabel = new TextRenderable(renderer, {
33
+ id: "repos-label",
34
+ content: "📦 Repositories:",
35
+ fg: "#38bdf8",
36
+ marginBottom: 0,
37
+ });
38
+ content.add(reposLabel);
39
+
40
+ if (config.repos.length > 0) {
41
+ config.repos.forEach((repo, i) => {
42
+ const repoText = new TextRenderable(renderer, {
43
+ id: `repo-${i}`,
44
+ content: ` • ${repo}`,
45
+ fg: "#94a3b8",
46
+ });
47
+ content.add(repoText);
48
+ });
49
+ } else {
50
+ const noRepos = new TextRenderable(renderer, {
51
+ id: "no-repos",
52
+ content: " (none)",
53
+ fg: "#64748b",
54
+ });
55
+ content.add(noRepos);
56
+ }
57
+
58
+ // Skills
59
+ const skillsLabel = new TextRenderable(renderer, {
60
+ id: "skills-label",
61
+ content: "\n🛠️ Skills:",
62
+ fg: "#38bdf8",
63
+ marginBottom: 0,
64
+ });
65
+ content.add(skillsLabel);
66
+
67
+ if (config.skills && config.skills.length > 0) {
68
+ config.skills.forEach((skill, i) => {
69
+ const skillText = new TextRenderable(renderer, {
70
+ id: `skill-${i}`,
71
+ content: ` • ${skill}`,
72
+ fg: "#94a3b8",
73
+ });
74
+ content.add(skillText);
75
+ });
76
+ } else {
77
+ const noSkills = new TextRenderable(renderer, {
78
+ id: "no-skills",
79
+ content: " (none)",
80
+ fg: "#64748b",
81
+ });
82
+ content.add(noSkills);
83
+ }
84
+
85
+ // Goal
86
+ const goalLabel = new TextRenderable(renderer, {
87
+ id: "goal-label",
88
+ content: "\n🎯 Goal:",
89
+ fg: "#38bdf8",
90
+ marginBottom: 0,
91
+ });
92
+ content.add(goalLabel);
93
+
94
+ const goalText = new TextRenderable(renderer, {
95
+ id: "goal-text",
96
+ content: config.goal ? ` ${config.goal}` : " (none)",
97
+ fg: config.goal ? "#94a3b8" : "#64748b",
98
+ marginBottom: 2,
99
+ });
100
+ content.add(goalText);
101
+
102
+ // Confirmation question
103
+ const confirmText = new TextRenderable(renderer, {
104
+ id: "confirm-question",
105
+ content: "Does this look right?",
106
+ fg: "#e2e8f0",
107
+ marginTop: 2,
108
+ });
109
+ content.add(confirmText);
110
+
111
+ const cleanup = () => {
112
+ renderer.keyInput.off("keypress", handleKeypress);
113
+ hideFooter(renderer);
114
+ clearLayout(renderer);
115
+ };
116
+
117
+ const handleKeypress = (key: KeyEvent) => {
118
+ if (isEscape(key)) {
119
+ cleanup();
120
+ resolve({ action: "cancel" });
121
+ return;
122
+ }
123
+
124
+ if (isEnter(key)) {
125
+ cleanup();
126
+ resolve({ action: "confirm" });
127
+ return;
128
+ }
129
+
130
+ if (isKey(key, "e")) {
131
+ cleanup();
132
+ resolve({ action: "edit" });
133
+ return;
134
+ }
135
+
136
+ if (isKey(key, "b")) {
137
+ cleanup();
138
+ resolve({ action: "back" });
139
+ return;
140
+ }
141
+ };
142
+
143
+ showFooter(renderer, content, {
144
+ navigate: false,
145
+ select: false,
146
+ back: true,
147
+ custom: ["Enter Confirm", "b Back to Chat", "e Manual Edit", "Esc Cancel"],
148
+ });
149
+ renderer.keyInput.on("keypress", handleKeypress);
150
+ });
151
+ }