@freesyntax/notch-cli 0.5.12 → 0.5.14

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.
Files changed (2) hide show
  1. package/dist/index.js +55 -61
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2576,7 +2576,7 @@ async function buildSystemPrompt(projectRoot, modelId) {
2576
2576
  } catch {
2577
2577
  }
2578
2578
  try {
2579
- const memoryStr = await formatMemoriesForPrompt(projectRoot);
2579
+ const memoryStr = await formatMemoriesForPrompt();
2580
2580
  if (memoryStr) {
2581
2581
  parts.push("", "## Saved Context (Memory)", memoryStr);
2582
2582
  }
@@ -6390,8 +6390,8 @@ function clearMenu(state) {
6390
6390
  if (state.renderedLines === 0) return "";
6391
6391
  const lines = state.renderedLines;
6392
6392
  state.renderedLines = 0;
6393
- let ansi = "";
6394
- for (let i = 0; i < lines; i++) {
6393
+ let ansi = "\x1B[2K";
6394
+ for (let i = 0; i < lines + 1; i++) {
6395
6395
  ansi += "\x1B[1A\x1B[2K";
6396
6396
  }
6397
6397
  return ansi;
@@ -6456,16 +6456,15 @@ function attachSlashMenu(rl) {
6456
6456
  const shouldShow = updateMenu(state, line);
6457
6457
  if (wasVisible && !shouldShow) {
6458
6458
  process.stdout.write(clearMenu(state));
6459
+ rewritePromptLine(rl);
6459
6460
  } else if (shouldShow) {
6460
6461
  if (wasVisible) {
6461
6462
  process.stdout.write(clearMenu(state));
6462
6463
  }
6463
6464
  const menuStr = renderMenu(state);
6464
6465
  if (menuStr) {
6465
- process.stdout.write("\x1B[s");
6466
6466
  process.stdout.write(menuStr + "\n");
6467
6467
  rewritePromptLine(rl);
6468
- process.stdout.write("\x1B[u");
6469
6468
  }
6470
6469
  }
6471
6470
  }
@@ -6897,7 +6896,8 @@ Analyze the above input.`;
6897
6896
  promptTokens: response.usage.promptTokens,
6898
6897
  completionTokens: response.usage.completionTokens,
6899
6898
  totalTokens: response.usage.totalTokens,
6900
- model: activeModelId
6899
+ toolCalls: response.toolCallCount,
6900
+ iterations: response.iterations
6901
6901
  });
6902
6902
  costTracker.record(activeModelId, response.usage.promptTokens, response.usage.completionTokens);
6903
6903
  console.log(usage.formatLast() + " " + costTracker.formatLastCost());
@@ -6942,7 +6942,7 @@ Analyze the above input.`;
6942
6942
  if (messages.length > 0) {
6943
6943
  try {
6944
6944
  const name = getSessionName();
6945
- const id = await saveSession(config.projectRoot, messages, { model: activeModelId });
6945
+ const id = await saveSession(messages, config.projectRoot, activeModelId);
6946
6946
  console.log(chalk27.gray(` Session saved: ${id}${name ? ` (${name})` : ""}`));
6947
6947
  } catch {
6948
6948
  }
@@ -7068,7 +7068,7 @@ Analyze the above input.`;
7068
7068
  } else {
7069
7069
  for (const df of diffs) {
7070
7070
  console.log(chalk27.cyan(` ${df.path}:`));
7071
- console.log(unifiedDiff(df.before, df.after, df.path));
7071
+ console.log(unifiedDiff(df.before ?? "", df.after ?? "", df.path));
7072
7072
  console.log("");
7073
7073
  }
7074
7074
  }
@@ -7076,12 +7076,11 @@ Analyze the above input.`;
7076
7076
  return;
7077
7077
  }
7078
7078
  if (input.startsWith("/export")) {
7079
- const exportPath = input.replace("/export", "").trim() || void 0;
7079
+ const exportPath = input.replace("/export", "").trim() || "notch-export.md";
7080
7080
  try {
7081
- const ePath = await exportSession(messages, {
7081
+ const ePath = await exportSession(messages, exportPath, {
7082
7082
  model: activeModelId,
7083
- projectRoot: config.projectRoot,
7084
- outputPath: exportPath
7083
+ project: config.projectRoot
7085
7084
  });
7086
7085
  console.log(chalk27.green(` Exported to ${ePath}
7087
7086
  `));
@@ -7094,7 +7093,7 @@ Analyze the above input.`;
7094
7093
  }
7095
7094
  if (input === "/save") {
7096
7095
  try {
7097
- const id = await saveSession(config.projectRoot, messages, { model: activeModelId });
7096
+ const id = await saveSession(messages, config.projectRoot, activeModelId);
7098
7097
  sessionId = id;
7099
7098
  console.log(chalk27.green(` Session saved: ${id}
7100
7099
  `));
@@ -7107,13 +7106,13 @@ Analyze the above input.`;
7107
7106
  }
7108
7107
  if (input === "/sessions") {
7109
7108
  try {
7110
- const sessions = await listSessions(config.projectRoot);
7109
+ const sessions = await listSessions();
7111
7110
  if (sessions.length === 0) {
7112
7111
  console.log(chalk27.gray(" No saved sessions.\n"));
7113
7112
  } else {
7114
7113
  console.log(chalk27.gray("\n Saved sessions:\n"));
7115
7114
  for (const s of sessions.slice(0, 10)) {
7116
- console.log(chalk27.gray(` ${s.id} ${s.turns} turns ${s.date} ${s.model}`));
7115
+ console.log(chalk27.gray(` ${s.id} ${s.turns} turns ${s.updated} ${s.model}`));
7117
7116
  }
7118
7117
  console.log("");
7119
7118
  }
@@ -7191,7 +7190,7 @@ Analyze the above input.`;
7191
7190
  const task = input.replace("/plan ", "").trim();
7192
7191
  const planSpinner = ora4("Generating plan...").start();
7193
7192
  try {
7194
- activePlan = await generatePlan(task, model, systemPrompt);
7193
+ activePlan = await generatePlan(task, model, { cwd: config.projectRoot, repoMap: repoMapStr || void 0, history: messages });
7195
7194
  planSpinner.succeed("Plan generated");
7196
7195
  console.log(formatPlan(activePlan));
7197
7196
  console.log(chalk27.gray(" Use /plan approve to execute, /plan edit to modify, or /plan cancel to discard.\n"));
@@ -7210,6 +7209,7 @@ Analyze the above input.`;
7210
7209
  console.log(chalk27.green(" Executing plan...\n"));
7211
7210
  while (!isPlanComplete(activePlan)) {
7212
7211
  const stepPrompt = currentStepPrompt(activePlan);
7212
+ if (!stepPrompt) break;
7213
7213
  messages.push({ role: "user", content: stepPrompt });
7214
7214
  const planStepSpinner = ora4(`Step ${activePlan.currentStep + 1}/${activePlan.steps.length}...`).start();
7215
7215
  try {
@@ -7234,7 +7234,7 @@ Analyze the above input.`;
7234
7234
  console.log("\n");
7235
7235
  messages.length = 0;
7236
7236
  messages.push(...response.messages);
7237
- activePlan = advancePlan(activePlan);
7237
+ advancePlan(activePlan);
7238
7238
  } catch (err) {
7239
7239
  planStepSpinner.fail(`Step failed: ${err.message}`);
7240
7240
  break;
@@ -7267,36 +7267,36 @@ Analyze the above input.`;
7267
7267
  }
7268
7268
  if (input.startsWith("/agent ")) {
7269
7269
  const task = input.replace("/agent ", "").trim();
7270
- const agentId = nextSubagentId();
7270
+ const agentId = nextSubagentId("general");
7271
7271
  console.log(chalk27.cyan(` Spawning subagent #${agentId}: ${task}
7272
7272
  `));
7273
7273
  spawnSubagent({
7274
7274
  id: agentId,
7275
- task,
7275
+ type: "general",
7276
+ prompt: task,
7276
7277
  model,
7277
- systemPrompt,
7278
7278
  toolContext: toolCtx,
7279
- contextWindow: MODEL_CATALOG[activeModelId].contextWindow,
7280
- onComplete: (result) => {
7281
- console.log(chalk27.green(`
7279
+ onStatus: (id, status) => {
7280
+ console.log(chalk27.gray(` [${id}] ${status}`));
7281
+ }
7282
+ }).then((result) => {
7283
+ console.log(chalk27.green(`
7282
7284
  Subagent #${agentId} finished:`));
7283
- console.log(chalk27.gray(` ${result.slice(0, 200)}
7285
+ console.log(chalk27.gray(` ${result.text.slice(0, 200)}
7284
7286
  `));
7285
- rl.prompt();
7286
- },
7287
- onError: (err) => {
7288
- console.log(chalk27.red(`
7289
- Subagent #${agentId} failed: ${err}
7287
+ rl.prompt();
7288
+ }).catch((err) => {
7289
+ console.log(chalk27.red(`
7290
+ Subagent #${agentId} failed: ${err.message}
7290
7291
  `));
7291
- rl.prompt();
7292
- }
7292
+ rl.prompt();
7293
7293
  });
7294
7294
  rl.prompt();
7295
7295
  return;
7296
7296
  }
7297
7297
  if (input === "/memory") {
7298
7298
  try {
7299
- const memories = await loadMemories(config.projectRoot);
7299
+ const memories = await loadMemories();
7300
7300
  if (memories.length === 0) {
7301
7301
  console.log(chalk27.gray(" No saved memories.\n"));
7302
7302
  } else {
@@ -7318,7 +7318,7 @@ Analyze the above input.`;
7318
7318
  if (input.startsWith("/memory search ")) {
7319
7319
  const query = input.replace("/memory search ", "").trim();
7320
7320
  try {
7321
- const results = await searchMemories(config.projectRoot, query);
7321
+ const results = await searchMemories(query);
7322
7322
  if (results.length === 0) {
7323
7323
  console.log(chalk27.gray(` No memories matching "${query}"
7324
7324
  `));
@@ -7337,9 +7337,9 @@ Analyze the above input.`;
7337
7337
  }
7338
7338
  if (input === "/memory clear") {
7339
7339
  try {
7340
- const memories = await loadMemories(config.projectRoot);
7340
+ const memories = await loadMemories();
7341
7341
  for (const m of memories) {
7342
- await deleteMemory(config.projectRoot, m.id);
7342
+ await deleteMemory(m.filename);
7343
7343
  }
7344
7344
  console.log(chalk27.yellow(` Cleared ${memories.length} memories.
7345
7345
  `));
@@ -7360,8 +7360,8 @@ Analyze the above input.`;
7360
7360
  const goal = input.replace("/ralph plan ", "").trim();
7361
7361
  const planSpinner = ora4("Ralph is planning...").start();
7362
7362
  try {
7363
- ralphPlan = await generateRalphPlan(goal, model, systemPrompt);
7364
- await savePlan(config.projectRoot, ralphPlan);
7363
+ ralphPlan = await generateRalphPlan(goal, model, config.projectRoot);
7364
+ await savePlan(ralphPlan, config.projectRoot);
7365
7365
  planSpinner.succeed(`Ralph planned ${ralphPlan.tasks.length} tasks`);
7366
7366
  console.log(formatRalphStatus(ralphPlan));
7367
7367
  } catch (err) {
@@ -7378,18 +7378,13 @@ Analyze the above input.`;
7378
7378
  }
7379
7379
  console.log(chalk27.green(" Ralph is running...\n"));
7380
7380
  try {
7381
- ralphPlan = await runRalphLoop(ralphPlan, {
7382
- model,
7383
- systemPrompt,
7384
- toolContext: toolCtx,
7385
- contextWindow: MODEL_CATALOG[activeModelId].contextWindow,
7386
- onTaskStart: (task) => console.log(chalk27.cyan(` \u25B6 Task: ${task.description}`)),
7387
- onTaskComplete: (task) => console.log(chalk27.green(` \u2713 Done: ${task.description}
7381
+ ralphPlan = await runRalphLoop(ralphPlan, model, toolCtx, config.projectRoot, {
7382
+ onTaskStart: (task) => console.log(chalk27.cyan(` \u25B6 Task: ${task.title}`)),
7383
+ onTaskEnd: (task) => console.log(chalk27.green(` \u2713 Done: ${task.title}
7388
7384
  `)),
7389
- onTaskFail: (task, err) => console.log(chalk27.red(` \u2717 Failed: ${task.description} (${err})
7390
- `))
7385
+ onText: (chunk) => process.stdout.write(chunk)
7391
7386
  });
7392
- await savePlan(config.projectRoot, ralphPlan);
7387
+ await savePlan(ralphPlan, config.projectRoot);
7393
7388
  console.log(formatRalphStatus(ralphPlan));
7394
7389
  } catch (err) {
7395
7390
  console.log(chalk27.red(` Ralph error: ${err.message}
@@ -7565,7 +7560,8 @@ Analyze the above input.`;
7565
7560
  promptTokens: response.usage.promptTokens,
7566
7561
  completionTokens: response.usage.completionTokens,
7567
7562
  totalTokens: response.usage.totalTokens,
7568
- model: activeModelId
7563
+ toolCalls: response.toolCallCount,
7564
+ iterations: response.iterations
7569
7565
  });
7570
7566
  costTracker.record(activeModelId, response.usage.promptTokens, response.usage.completionTokens);
7571
7567
  console.log(usage.formatLast() + " " + costTracker.formatLastCost());
@@ -7583,8 +7579,10 @@ Analyze the above input.`;
7583
7579
  const memMatch = lastText.match(/\[(?:MEMORY|memory):\s*([^\]]+)\]/);
7584
7580
  if (memMatch) {
7585
7581
  try {
7586
- await saveMemory(config.projectRoot, {
7587
- type: "auto",
7582
+ await saveMemory({
7583
+ name: "auto-saved",
7584
+ description: memMatch[1].slice(0, 80),
7585
+ type: "project",
7588
7586
  content: memMatch[1]
7589
7587
  });
7590
7588
  console.log(chalk27.gray(" (Saved to memory)\n"));
@@ -7631,8 +7629,8 @@ async function handleRalphSubcommand(args, cliOpts) {
7631
7629
  process.exit(1);
7632
7630
  }
7633
7631
  const spinner = ora4("Ralph is planning...").start();
7634
- const plan = await generateRalphPlan(goal, model, systemPrompt);
7635
- await savePlan(config.projectRoot, plan);
7632
+ const plan = await generateRalphPlan(goal, model, config.projectRoot);
7633
+ await savePlan(plan, config.projectRoot);
7636
7634
  spinner.succeed(`Planned ${plan.tasks.length} tasks`);
7637
7635
  console.log(formatRalphStatus(plan));
7638
7636
  } else if (subcommand === "run") {
@@ -7641,16 +7639,12 @@ async function handleRalphSubcommand(args, cliOpts) {
7641
7639
  console.error(chalk27.red(" No plan found. Run: notch ralph plan <goal>"));
7642
7640
  process.exit(1);
7643
7641
  }
7644
- plan = await runRalphLoop(plan, {
7645
- model,
7646
- systemPrompt,
7647
- toolContext: toolCtx,
7648
- contextWindow: MODEL_CATALOG[config.models.chat.model].contextWindow,
7649
- onTaskStart: (t) => console.log(chalk27.cyan(` \u25B6 ${t.description}`)),
7650
- onTaskComplete: (t) => console.log(chalk27.green(` \u2713 ${t.description}`)),
7651
- onTaskFail: (t, e) => console.log(chalk27.red(` \u2717 ${t.description}: ${e}`))
7642
+ plan = await runRalphLoop(plan, model, toolCtx, config.projectRoot, {
7643
+ onTaskStart: (t) => console.log(chalk27.cyan(` \u25B6 ${t.title}`)),
7644
+ onTaskEnd: (t) => console.log(chalk27.green(` \u2713 ${t.title}`)),
7645
+ onText: (chunk) => process.stdout.write(chunk)
7652
7646
  });
7653
- await savePlan(config.projectRoot, plan);
7647
+ await savePlan(plan, config.projectRoot);
7654
7648
  console.log(formatRalphStatus(plan));
7655
7649
  } else if (subcommand === "status") {
7656
7650
  const plan = await loadPlan(config.projectRoot);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesyntax/notch-cli",
3
- "version": "0.5.12",
3
+ "version": "0.5.14",
4
4
  "description": "Notch CLI — AI-powered coding assistant by Driftrail",
5
5
  "type": "module",
6
6
  "bin": {