@freesyntax/notch-cli 0.4.0 → 0.4.2
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/dist/index.js +74 -36
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,6 +22,12 @@ import path from "path";
|
|
|
22
22
|
|
|
23
23
|
// src/providers/registry.ts
|
|
24
24
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
25
|
+
var MissingApiKeyError = class extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super("NOTCH_API_KEY is not set");
|
|
28
|
+
this.name = "MissingApiKeyError";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
25
31
|
var MODEL_CATALOG = {
|
|
26
32
|
"notch-cinder": {
|
|
27
33
|
id: "notch-cinder",
|
|
@@ -74,9 +80,7 @@ function resolveModel(config) {
|
|
|
74
80
|
const baseUrl = config.baseUrl ?? process.env.NOTCH_BASE_URL ?? info.baseUrl;
|
|
75
81
|
const apiKey = config.apiKey ?? process.env.NOTCH_API_KEY;
|
|
76
82
|
if (!apiKey) {
|
|
77
|
-
throw new
|
|
78
|
-
"NOTCH_API_KEY is not set. Set it via the NOTCH_API_KEY environment variable or --api-key flag."
|
|
79
|
-
);
|
|
83
|
+
throw new MissingApiKeyError();
|
|
80
84
|
}
|
|
81
85
|
const provider = createOpenAI({
|
|
82
86
|
apiKey,
|
|
@@ -1186,8 +1190,23 @@ async function runAgentLoop(messages, config) {
|
|
|
1186
1190
|
}
|
|
1187
1191
|
};
|
|
1188
1192
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1193
|
+
var CINDER_SYSTEM_PROMPT_PARTS = [
|
|
1194
|
+
"You are Notch, an expert AI coding assistant. Built by Driftrail.",
|
|
1195
|
+
"Be concise. Think before acting. Do exactly what the user asks, nothing more.",
|
|
1196
|
+
"",
|
|
1197
|
+
"## Tools available",
|
|
1198
|
+
"Read, Write, Edit, Shell, Git, Glob, Grep, WebFetch.",
|
|
1199
|
+
"",
|
|
1200
|
+
"## Core rules",
|
|
1201
|
+
"- Read files before editing them. Never guess at file content.",
|
|
1202
|
+
"- Use exact string matching for edits.",
|
|
1203
|
+
"- If a task is complex, break it into steps.",
|
|
1204
|
+
"- If a command fails, read the error, fix it, and retry. Do not apologize \u2014 just fix it.",
|
|
1205
|
+
"- Keep responses short. No lengthy explanations unless asked."
|
|
1206
|
+
];
|
|
1207
|
+
async function buildSystemPrompt(projectRoot, modelId) {
|
|
1208
|
+
const isCinder = (modelId ?? "").toLowerCase().includes("cinder");
|
|
1209
|
+
const parts = isCinder ? [...CINDER_SYSTEM_PROMPT_PARTS] : [
|
|
1191
1210
|
"You are Notch, an expert AI coding assistant built by Driftrail.",
|
|
1192
1211
|
"You help developers write, debug, refactor, and understand code.",
|
|
1193
1212
|
"You have access to tools for reading/writing files, running shell commands, searching code, and git operations.",
|
|
@@ -1214,7 +1233,9 @@ async function buildSystemPrompt(projectRoot) {
|
|
|
1214
1233
|
}
|
|
1215
1234
|
} catch {
|
|
1216
1235
|
}
|
|
1217
|
-
|
|
1236
|
+
if (!isCinder) {
|
|
1237
|
+
parts.push("", "## Available Tools", describeTools());
|
|
1238
|
+
}
|
|
1218
1239
|
return parts.join("\n");
|
|
1219
1240
|
}
|
|
1220
1241
|
|
|
@@ -2770,26 +2791,18 @@ function formatThemeList(activeId) {
|
|
|
2770
2791
|
|
|
2771
2792
|
// src/ui/banner.ts
|
|
2772
2793
|
var MANTIS = [
|
|
2773
|
-
" \u25C9\
|
|
2774
|
-
//
|
|
2775
|
-
" \
|
|
2776
|
-
//
|
|
2777
|
-
"
|
|
2778
|
-
//
|
|
2779
|
-
"
|
|
2780
|
-
//
|
|
2781
|
-
"
|
|
2782
|
-
//
|
|
2783
|
-
"
|
|
2784
|
-
//
|
|
2785
|
-
" \u2590\u2588\u2588\u258C",
|
|
2786
|
-
// abdomen
|
|
2787
|
-
" \u2590\u2588\u2588\u258C",
|
|
2788
|
-
// abdomen
|
|
2789
|
-
" \u2584\u2580 \u2580\u2584",
|
|
2790
|
-
// legs splay
|
|
2791
|
-
" \u2580 \u2580"
|
|
2792
|
-
// feet
|
|
2794
|
+
" \u2571\u25C9\u25C9\u2572",
|
|
2795
|
+
// ╱◉◉╲ antennae + eyes
|
|
2796
|
+
" \u2588\u2588\u2588",
|
|
2797
|
+
// ███ head
|
|
2798
|
+
" \u2590\u2588\u258C",
|
|
2799
|
+
// ▐█▌ neck
|
|
2800
|
+
" \u2584\u2580\u2590\u2588\u258C\u2580\u2584",
|
|
2801
|
+
// ▄▀▐█▌▀▄ prayer arms
|
|
2802
|
+
" \u2590\u2588\u258C",
|
|
2803
|
+
// ▐█▌ abdomen
|
|
2804
|
+
" \u2580\u2580 \u2580\u2580"
|
|
2805
|
+
// ▀▀ ▀▀ feet
|
|
2793
2806
|
];
|
|
2794
2807
|
var LOGO_INLINE = [
|
|
2795
2808
|
" \u2588\u2588\u2584 \u2588 \u2584\u2580\u2580\u2584 \u2580\u2588\u2580 \u2584\u2580\u2580\u2584 \u2588 \u2588",
|
|
@@ -2798,7 +2811,7 @@ var LOGO_INLINE = [
|
|
|
2798
2811
|
];
|
|
2799
2812
|
function colorMantis(line) {
|
|
2800
2813
|
const t = theme();
|
|
2801
|
-
return line.replace(/\u25c9/g, t.mascotAccent("\u25C9")).replace(/[\u2588]/g, (ch) => t.mascot(ch)).replace(/[\u2584\u2580]/g, (ch) => t.mascot(ch)).replace(/\u2590/g, t.mascot("\u2590")).replace(/\u258c/g, t.mascot("\u258C"));
|
|
2814
|
+
return line.replace(/[\u2571\u2572]/g, (ch) => t.mascot(ch)).replace(/\u25c9/g, t.mascotAccent("\u25C9")).replace(/[\u2588]/g, (ch) => t.mascot(ch)).replace(/[\u2584\u2580]/g, (ch) => t.mascot(ch)).replace(/\u2590/g, t.mascot("\u2590")).replace(/\u258c/g, t.mascot("\u258C"));
|
|
2802
2815
|
}
|
|
2803
2816
|
function printBanner(version, modelLabel, modelId, modelSize, project) {
|
|
2804
2817
|
const t = theme();
|
|
@@ -2816,7 +2829,7 @@ function printBanner(version, modelLabel, modelId, modelSize, project) {
|
|
|
2816
2829
|
const divider = t.border(" " + "\u2500".repeat(divWidth));
|
|
2817
2830
|
console.log(divider);
|
|
2818
2831
|
console.log(
|
|
2819
|
-
t.dim(" ") + t.bold(modelLabel) + t.dim(
|
|
2832
|
+
t.dim(" ") + t.bold(modelLabel) + t.dim(" \u2502 v") + t.text(version) + t.dim(" \u2502 ") + t.dim("by ") + t.tagline("Driftrail")
|
|
2820
2833
|
);
|
|
2821
2834
|
console.log(t.dim(` ${project}`));
|
|
2822
2835
|
console.log(divider);
|
|
@@ -3716,7 +3729,7 @@ function completeFilePath(partial, cwd) {
|
|
|
3716
3729
|
|
|
3717
3730
|
// src/index.ts
|
|
3718
3731
|
import fs18 from "fs/promises";
|
|
3719
|
-
var VERSION = "0.4.
|
|
3732
|
+
var VERSION = "0.4.1";
|
|
3720
3733
|
var modelChoices = MODEL_IDS.join(", ");
|
|
3721
3734
|
var program = new Command().name("notch").description("Notch CLI \u2014 AI-powered coding assistant by Driftrail").version(VERSION).argument("[prompt...]", "One-shot prompt (runs once and exits)").option(`-m, --model <model>`, `Notch model (${modelChoices})`).option("--base-url <url>", "Override Notch API base URL").option("--api-key <key>", "Notch API key (prefer NOTCH_API_KEY env var)").option("--no-repo-map", "Disable automatic repository mapping").option("--no-markdown", "Disable markdown rendering in output").option("--max-iterations <n>", "Max tool-call rounds per turn", "25").option("-y, --yes", "Auto-confirm destructive actions").option("--trust", "Trust mode \u2014 auto-allow all tool calls").option("--theme <theme>", `UI color theme (${THEME_IDS.join(", ")})`).option("--resume", "Resume the last session for this project").option("--session <id>", "Resume a specific session by ID").option("--cwd <dir>", "Set working directory").parse(process.argv);
|
|
3722
3735
|
var opts = program.opts();
|
|
@@ -3728,9 +3741,8 @@ function printModelTable(activeModel) {
|
|
|
3728
3741
|
const info = MODEL_CATALOG[id];
|
|
3729
3742
|
const active = id === activeModel ? t.success(" \u25CF") : " ";
|
|
3730
3743
|
const label = id === activeModel ? t.bold(`${info.label}`) : t.dim(`${info.label}`);
|
|
3731
|
-
const size = t.info(info.size.padEnd(4));
|
|
3732
3744
|
const ctx = t.dim(`${(info.contextWindow / 1024).toFixed(0)}K ctx`);
|
|
3733
|
-
console.log(` ${active} ${t.brand(id.padEnd(14))} ${
|
|
3745
|
+
console.log(` ${active} ${t.brand(id.padEnd(14))} ${label} ${ctx}`);
|
|
3734
3746
|
}
|
|
3735
3747
|
console.log(t.dim(`
|
|
3736
3748
|
Switch with: /model <name>
|
|
@@ -3880,7 +3892,31 @@ async function main() {
|
|
|
3880
3892
|
setTheme(config.theme);
|
|
3881
3893
|
}
|
|
3882
3894
|
let activeModelId = config.models.chat.model;
|
|
3883
|
-
let model
|
|
3895
|
+
let model;
|
|
3896
|
+
try {
|
|
3897
|
+
model = resolveModel(config.models.chat);
|
|
3898
|
+
} catch (err) {
|
|
3899
|
+
if (err instanceof MissingApiKeyError) {
|
|
3900
|
+
console.log("");
|
|
3901
|
+
console.log(" \x1B[1m\x1B[36m\u26A1 Welcome to Notch CLI\x1B[0m");
|
|
3902
|
+
console.log("");
|
|
3903
|
+
console.log(" To get started, you need a Notch API key.");
|
|
3904
|
+
console.log("");
|
|
3905
|
+
console.log(" \x1B[1mOption 1:\x1B[0m Log in via browser (recommended)");
|
|
3906
|
+
console.log(" \x1B[33m$ notch login\x1B[0m");
|
|
3907
|
+
console.log("");
|
|
3908
|
+
console.log(" \x1B[1mOption 2:\x1B[0m Set your API key directly");
|
|
3909
|
+
console.log(" \x1B[33m$ export NOTCH_API_KEY=your-key-here\x1B[0m");
|
|
3910
|
+
console.log("");
|
|
3911
|
+
console.log(" \x1B[1mOption 3:\x1B[0m Pass it inline");
|
|
3912
|
+
console.log(" \x1B[33m$ notch --api-key your-key-here\x1B[0m");
|
|
3913
|
+
console.log("");
|
|
3914
|
+
console.log(" Get your key at: \x1B[4mhttps://freesyntax.com/settings\x1B[0m");
|
|
3915
|
+
console.log("");
|
|
3916
|
+
process.exit(0);
|
|
3917
|
+
}
|
|
3918
|
+
throw err;
|
|
3919
|
+
}
|
|
3884
3920
|
const info = MODEL_CATALOG[activeModelId];
|
|
3885
3921
|
printBanner(VERSION, info.label, info.id, info.size, config.projectRoot);
|
|
3886
3922
|
checkForUpdates(VERSION).then((msg) => {
|
|
@@ -3912,10 +3948,12 @@ async function main() {
|
|
|
3912
3948
|
spinner.warn("Could not build repo map");
|
|
3913
3949
|
}
|
|
3914
3950
|
}
|
|
3915
|
-
const baseSystemPrompt = await buildSystemPrompt(config.projectRoot);
|
|
3951
|
+
const baseSystemPrompt = await buildSystemPrompt(config.projectRoot, activeModelId);
|
|
3952
|
+
const isCinder = activeModelId.includes("cinder");
|
|
3916
3953
|
const systemPrompt = [
|
|
3917
3954
|
baseSystemPrompt,
|
|
3918
|
-
|
|
3955
|
+
// Skip repo map for Cinder — too many tokens for a 4B model
|
|
3956
|
+
!isCinder && repoMapStr ? `
|
|
3919
3957
|
## Repository Map
|
|
3920
3958
|
${repoMapStr}` : ""
|
|
3921
3959
|
].join("");
|
|
@@ -4126,7 +4164,7 @@ Analyze the above input.`;
|
|
|
4126
4164
|
config.models.chat.model = activeModelId;
|
|
4127
4165
|
model = resolveModel(config.models.chat);
|
|
4128
4166
|
const switchedInfo = MODEL_CATALOG[activeModelId];
|
|
4129
|
-
console.log(chalk8.green(` Switched to ${switchedInfo.label} (${switchedInfo.id}
|
|
4167
|
+
console.log(chalk8.green(` Switched to ${switchedInfo.label} (${switchedInfo.id})
|
|
4130
4168
|
`));
|
|
4131
4169
|
rl.prompt();
|
|
4132
4170
|
return;
|
|
@@ -4707,7 +4745,7 @@ async function handleRalphSubcommand(args, cliOpts) {
|
|
|
4707
4745
|
const config = await loadConfig(cliOpts.cwd ? { projectRoot: cliOpts.cwd } : {});
|
|
4708
4746
|
if (cliOpts.model) config.models.chat.model = cliOpts.model;
|
|
4709
4747
|
const model = resolveModel(config.models.chat);
|
|
4710
|
-
const systemPrompt = await buildSystemPrompt(config.projectRoot);
|
|
4748
|
+
const systemPrompt = await buildSystemPrompt(config.projectRoot, config.models.chat.model);
|
|
4711
4749
|
const toolCtx = {
|
|
4712
4750
|
cwd: config.projectRoot,
|
|
4713
4751
|
requireConfirm: false,
|