@hasna/coders 0.0.15 → 0.1.0

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 (3) hide show
  1. package/dist/cli.mjs +1851 -1689
  2. package/dist/cli.mjs.map +4 -4
  3. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -58441,7 +58441,7 @@ var init_client = __esm({
58441
58441
  "Content-Type": "application/json",
58442
58442
  "anthropic-version": "2023-06-01",
58443
58443
  "anthropic-beta": BETA_HEADERS.join(","),
58444
- "User-Agent": `coders/${"0.0.15"}`
58444
+ "User-Agent": `coders/${"0.1.0"}`
58445
58445
  };
58446
58446
  if (key.isOAuth) {
58447
58447
  headers["Authorization"] = `Bearer ${key.apiKey}`;
@@ -58639,237 +58639,680 @@ var init_client = __esm({
58639
58639
  }
58640
58640
  });
58641
58641
 
58642
- // src/ui/screen/terminal.ts
58643
- var terminal_exports = {};
58644
- __export(terminal_exports, {
58645
- detectTerminal: () => detectTerminal,
58646
- getTerminalSize: () => getTerminalSize,
58647
- onResize: () => onResize
58648
- });
58649
- function detectTerminal() {
58650
- const termProgram = process.env.TERM_PROGRAM ?? "";
58651
- const term = process.env.TERM ?? "";
58652
- const colorTerm = process.env.COLORTERM ?? "";
58653
- const caps = {
58654
- name: detectTerminalName(termProgram, term),
58655
- colorDepth: detectColorDepth(termProgram, colorTerm, term),
58656
- unicode: detectUnicode(),
58657
- hyperlinks: detectHyperlinks(termProgram),
58658
- kittyProtocol: detectKittyProtocol(termProgram),
58659
- mouseSupport: true,
58660
- // Most modern terminals support SGR mouse
58661
- sixelGraphics: detectSixel(termProgram),
58662
- iterm2Images: termProgram === "iTerm.app"
58663
- };
58664
- return caps;
58665
- }
58666
- function detectTerminalName(termProgram, term) {
58667
- if (termProgram === "iTerm.app") return "iTerm2";
58668
- if (termProgram === "WezTerm") return "WezTerm";
58669
- if (termProgram === "vscode") return "VSCode";
58670
- if (termProgram === "Alacritty") return "Alacritty";
58671
- if (termProgram === "ghostty") return "Ghostty";
58672
- if (termProgram === "contour") return "Contour";
58673
- if (termProgram === "mintty") return "Mintty";
58674
- if (process.env.KITTY_WINDOW_ID) return "Kitty";
58675
- if (termProgram === "kitty") return "Kitty";
58676
- if (term === "foot" || term === "foot-extra") return "foot";
58677
- if (process.env.WARP_IS_LOCAL_SHELL_SESSION) return "Warp";
58678
- if (termProgram === "Warp") return "Warp";
58679
- if (process.env.WT_SESSION) return "Windows Terminal";
58680
- if (process.env.ConEmuANSI || process.env.ConEmuPID) return "ConEmu";
58681
- const vteVersion = process.env.VTE_VERSION;
58682
- if (vteVersion) {
58683
- const ver = parseInt(vteVersion, 10);
58684
- if (ver >= 6800) return "VTE (modern)";
58685
- return "VTE";
58686
- }
58687
- if (term.startsWith("xterm")) return "xterm";
58688
- if (term.startsWith("screen")) return "screen";
58689
- if (term.startsWith("tmux")) return "tmux";
58690
- return "unknown";
58691
- }
58692
- function detectColorDepth(termProgram, colorTerm, term) {
58693
- if (colorTerm === "truecolor" || colorTerm === "24bit") return 24;
58694
- const truecolorTerminals = [
58695
- "iTerm.app",
58696
- "WezTerm",
58697
- "Alacritty",
58698
- "kitty",
58699
- "ghostty",
58700
- "contour",
58701
- "foot"
58702
- ];
58703
- if (truecolorTerminals.includes(termProgram)) return 24;
58704
- if (process.env.KITTY_WINDOW_ID) return 24;
58705
- if (process.env.WT_SESSION) return 24;
58706
- if (termProgram === "vscode") return 24;
58707
- if (term.includes("256color")) return 8;
58708
- if (colorTerm) return 8;
58709
- if (term.includes("color") || term.startsWith("xterm")) return 4;
58710
- if (term === "dumb" || !process.stdout.isTTY) return 1;
58711
- return 4;
58712
- }
58713
- function detectUnicode() {
58714
- const lang = process.env.LANG ?? process.env.LC_ALL ?? process.env.LC_CTYPE ?? "";
58715
- return lang.toLowerCase().includes("utf");
58716
- }
58717
- function detectHyperlinks(termProgram) {
58718
- const supported = [
58719
- "iTerm.app",
58720
- "WezTerm",
58721
- "Alacritty",
58722
- "kitty",
58723
- "ghostty",
58724
- "contour",
58725
- "foot",
58726
- "vscode"
58727
- ];
58728
- if (supported.includes(termProgram)) return true;
58729
- if (process.env.KITTY_WINDOW_ID) return true;
58730
- if (process.env.WT_SESSION) return true;
58731
- return false;
58732
- }
58733
- function detectKittyProtocol(termProgram) {
58734
- if (process.env.KITTY_WINDOW_ID) return true;
58735
- if (termProgram === "kitty") return true;
58736
- if (termProgram === "ghostty") return true;
58737
- if (termProgram === "foot") return true;
58738
- if (termProgram === "WezTerm") return true;
58739
- return false;
58740
- }
58741
- function detectSixel(termProgram) {
58742
- if (termProgram === "WezTerm") return true;
58743
- if (termProgram === "foot") return true;
58744
- if (termProgram === "contour") return true;
58745
- return false;
58746
- }
58747
- function getTerminalSize() {
58748
- return {
58749
- columns: process.stdout.columns ?? 80,
58750
- rows: process.stdout.rows ?? 24
58751
- };
58752
- }
58753
- function onResize(callback) {
58754
- const handler = () => {
58755
- const { columns, rows } = getTerminalSize();
58756
- callback(columns, rows);
58757
- };
58758
- process.stdout.on("resize", handler);
58759
- return () => process.stdout.removeListener("resize", handler);
58642
+ // src/db/index.ts
58643
+ import { join as join2 } from "path";
58644
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
58645
+ function getDbPath() {
58646
+ const dir = getConfigDir();
58647
+ if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
58648
+ return join2(dir, "coders.db");
58760
58649
  }
58761
- var init_terminal = __esm({
58762
- "src/ui/screen/terminal.ts"() {
58763
- "use strict";
58650
+ function getDb() {
58651
+ if (_db) return _db;
58652
+ const dbPath = getDbPath();
58653
+ try {
58654
+ const { Database } = __require("bun:sqlite");
58655
+ _db = new Database(dbPath);
58656
+ } catch {
58657
+ try {
58658
+ const BetterSqlite3 = __require("better-sqlite3");
58659
+ _db = new BetterSqlite3(dbPath);
58660
+ } catch {
58661
+ _db = createJsonFileDb();
58662
+ initSchema(_db);
58663
+ return _db;
58664
+ }
58764
58665
  }
58765
- });
58766
-
58767
- // src/core/slash-commands.ts
58768
- function registerSlashCommand(cmd) {
58769
- commands.set(cmd.name, cmd);
58770
- if (cmd.aliases) {
58771
- for (const alias of cmd.aliases) commands.set(alias, cmd);
58666
+ try {
58667
+ _db.exec("PRAGMA journal_mode=WAL");
58668
+ } catch {
58772
58669
  }
58773
- }
58774
- function getAllSlashCommands() {
58775
- const seen = /* @__PURE__ */ new Set();
58776
- const result = [];
58777
- for (const cmd of commands.values()) {
58778
- if (!seen.has(cmd.name)) {
58779
- seen.add(cmd.name);
58780
- result.push(cmd);
58781
- }
58670
+ try {
58671
+ _db.exec("PRAGMA foreign_keys=ON");
58672
+ } catch {
58782
58673
  }
58783
- return result;
58784
- }
58785
- function isSlashCommand(input) {
58786
- return input.startsWith("/") && commands.has(input.slice(1).split(/\s/)[0]);
58787
- }
58788
- async function executeSlashCommand(input) {
58789
- const parts = input.replace(/^\//, "").split(/\s+/);
58790
- const name = parts[0];
58791
- const args = parts.slice(1).join(" ");
58792
- const cmd = commands.get(name);
58793
- if (!cmd) return { output: `Unknown command: /${name}. Type /help for available commands.` };
58794
- return cmd.handler(args);
58674
+ initSchema(_db);
58675
+ return _db;
58795
58676
  }
58796
- function registerDefaults() {
58797
- registerSlashCommand({
58798
- name: "help",
58799
- aliases: ["h", "?"],
58800
- category: "core",
58801
- description: "Show available commands",
58802
- handler: () => {
58803
- const cmds = getAllSlashCommands().sort((a, b) => a.name.localeCompare(b.name));
58804
- const lines = cmds.map((c) => ` /${c.name.padEnd(16)} ${c.description}`);
58805
- return { output: `Available commands:
58806
- ${lines.join("\n")}` };
58807
- }
58808
- });
58809
- registerSlashCommand({
58810
- name: "clear",
58811
- category: "core",
58812
- description: "Clear conversation history",
58813
- handler: () => ({ action: "clear", output: "Conversation cleared." })
58814
- });
58815
- registerSlashCommand({
58816
- name: "compact",
58817
- category: "core",
58818
- description: "Compact conversation context",
58819
- handler: () => ({ action: "compact", output: "Context compacted." })
58820
- });
58821
- registerSlashCommand({
58822
- name: "exit",
58823
- aliases: ["quit", "q"],
58824
- category: "core",
58825
- description: "Exit coders",
58826
- handler: () => ({ action: "exit" })
58827
- });
58828
- registerSlashCommand({
58829
- name: "plan",
58830
- category: "core",
58831
- description: "View or edit the current plan",
58832
- handler: () => ({ output: "Plan mode \u2014 use EnterPlanMode tool to start planning." })
58833
- });
58834
- registerSlashCommand({
58835
- name: "model",
58836
- category: "mode",
58837
- description: "View or change the current model",
58838
- handler: (args) => {
58839
- if (args) return { action: "setModel", data: args, output: `Model set to: ${args}` };
58840
- return { output: "Current model \u2014 use /model <name> to change." };
58841
- }
58842
- });
58843
- registerSlashCommand({
58844
- name: "fast",
58845
- category: "mode",
58846
- description: "Toggle fast mode",
58847
- handler: () => ({ output: "Fast mode toggled." })
58848
- });
58849
- registerSlashCommand({
58850
- name: "verbose",
58851
- category: "mode",
58852
- description: "Toggle verbose output",
58853
- handler: () => ({ output: "Verbose mode toggled." })
58854
- });
58855
- registerSlashCommand({
58856
- name: "status",
58857
- category: "system",
58858
- description: "Show session status",
58859
- handler: () => ({ output: "Session status \u2014 not yet wired." })
58860
- });
58861
- registerSlashCommand({
58862
- name: "config",
58863
- category: "system",
58864
- description: "View or modify settings",
58865
- handler: (args) => ({ output: args ? `Config: ${args}` : "Use /config <key> [value]" })
58866
- });
58867
- registerSlashCommand({
58868
- name: "mcp",
58869
- category: "system",
58870
- description: "Show MCP server status",
58871
- handler: () => ({ output: "MCP servers \u2014 use 'coders mcp list' for details." })
58872
- });
58677
+ function initSchema(db) {
58678
+ db.exec(`
58679
+ -- Sessions
58680
+ CREATE TABLE IF NOT EXISTS sessions (
58681
+ id TEXT PRIMARY KEY,
58682
+ device_id TEXT NOT NULL,
58683
+ project_dir TEXT,
58684
+ original_cwd TEXT,
58685
+ model TEXT,
58686
+ app_version TEXT,
58687
+ build_time TEXT,
58688
+ fingerprint TEXT, -- JSON
58689
+ metadata TEXT, -- JSON
58690
+ created_at TEXT DEFAULT (datetime('now')),
58691
+ updated_at TEXT DEFAULT (datetime('now'))
58692
+ );
58693
+
58694
+ -- Messages (conversation history)
58695
+ CREATE TABLE IF NOT EXISTS messages (
58696
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58697
+ session_id TEXT NOT NULL REFERENCES sessions(id),
58698
+ role TEXT NOT NULL CHECK(role IN ('user','assistant','system')),
58699
+ content TEXT NOT NULL,
58700
+ tool_uses TEXT, -- JSON array of tool use displays
58701
+ thinking TEXT,
58702
+ duration_ms REAL,
58703
+ tokens_in INTEGER DEFAULT 0,
58704
+ tokens_out INTEGER DEFAULT 0,
58705
+ cost_usd REAL DEFAULT 0,
58706
+ created_at TEXT DEFAULT (datetime('now'))
58707
+ );
58708
+ CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
58709
+
58710
+ -- File history (tracks reads per session)
58711
+ CREATE TABLE IF NOT EXISTS file_history (
58712
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58713
+ session_id TEXT NOT NULL,
58714
+ file_path TEXT NOT NULL,
58715
+ content_hash TEXT,
58716
+ byte_size INTEGER,
58717
+ line_count INTEGER,
58718
+ read_at TEXT DEFAULT (datetime('now')),
58719
+ UNIQUE(session_id, file_path)
58720
+ );
58721
+
58722
+ -- File checkpoints (for /rewind)
58723
+ CREATE TABLE IF NOT EXISTS checkpoints (
58724
+ id TEXT PRIMARY KEY,
58725
+ session_id TEXT NOT NULL,
58726
+ file_path TEXT NOT NULL,
58727
+ original_content TEXT NOT NULL,
58728
+ edit_operation TEXT, -- JSON {old_string, new_string}
58729
+ created_at TEXT DEFAULT (datetime('now'))
58730
+ );
58731
+ CREATE INDEX IF NOT EXISTS idx_checkpoints_session_file ON checkpoints(session_id, file_path);
58732
+
58733
+ -- Tasks (replaces in-memory fallback for @hasna/todos)
58734
+ CREATE TABLE IF NOT EXISTS tasks (
58735
+ id TEXT PRIMARY KEY,
58736
+ subject TEXT NOT NULL,
58737
+ description TEXT DEFAULT '',
58738
+ status TEXT DEFAULT 'pending' CHECK(status IN ('pending','in_progress','completed','failed','cancelled')),
58739
+ active_form TEXT,
58740
+ owner TEXT,
58741
+ blocks TEXT DEFAULT '[]', -- JSON array of task IDs
58742
+ blocked_by TEXT DEFAULT '[]', -- JSON array of task IDs
58743
+ metadata TEXT DEFAULT '{}', -- JSON
58744
+ created_at TEXT DEFAULT (datetime('now')),
58745
+ updated_at TEXT DEFAULT (datetime('now'))
58746
+ );
58747
+
58748
+ -- Config (replaces JSON files)
58749
+ CREATE TABLE IF NOT EXISTS config (
58750
+ key TEXT PRIMARY KEY,
58751
+ value TEXT, -- JSON
58752
+ scope TEXT DEFAULT 'user' CHECK(scope IN ('user','project','local','global')),
58753
+ updated_at TEXT DEFAULT (datetime('now'))
58754
+ );
58755
+
58756
+ -- Memories (replaces in-memory fallback for @hasna/mementos)
58757
+ CREATE TABLE IF NOT EXISTS memories (
58758
+ id TEXT PRIMARY KEY,
58759
+ key TEXT UNIQUE NOT NULL,
58760
+ value TEXT NOT NULL,
58761
+ scope TEXT DEFAULT 'shared' CHECK(scope IN ('global','shared','private')),
58762
+ category TEXT DEFAULT 'knowledge',
58763
+ importance INTEGER DEFAULT 5 CHECK(importance BETWEEN 1 AND 10),
58764
+ tags TEXT DEFAULT '[]', -- JSON array
58765
+ version INTEGER DEFAULT 1,
58766
+ created_at TEXT DEFAULT (datetime('now')),
58767
+ updated_at TEXT DEFAULT (datetime('now'))
58768
+ );
58769
+
58770
+ -- Teams
58771
+ CREATE TABLE IF NOT EXISTS teams (
58772
+ name TEXT PRIMARY KEY,
58773
+ description TEXT,
58774
+ task_list_id TEXT,
58775
+ created_at TEXT DEFAULT (datetime('now'))
58776
+ );
58777
+
58778
+ -- Team members
58779
+ CREATE TABLE IF NOT EXISTS team_members (
58780
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58781
+ team_name TEXT NOT NULL REFERENCES teams(name),
58782
+ agent_name TEXT NOT NULL,
58783
+ role TEXT,
58784
+ status TEXT DEFAULT 'idle',
58785
+ current_task TEXT,
58786
+ UNIQUE(team_name, agent_name)
58787
+ );
58788
+
58789
+ -- Team messages
58790
+ CREATE TABLE IF NOT EXISTS team_messages (
58791
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58792
+ from_agent TEXT NOT NULL,
58793
+ to_agent TEXT NOT NULL,
58794
+ team_name TEXT,
58795
+ content TEXT NOT NULL,
58796
+ is_read INTEGER DEFAULT 0,
58797
+ is_blocking INTEGER DEFAULT 0,
58798
+ created_at TEXT DEFAULT (datetime('now'))
58799
+ );
58800
+ CREATE INDEX IF NOT EXISTS idx_team_msgs_to ON team_messages(to_agent, is_read);
58801
+
58802
+ -- Permissions (persisted allow/deny rules)
58803
+ CREATE TABLE IF NOT EXISTS permissions (
58804
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58805
+ tool_name TEXT,
58806
+ command_pattern TEXT,
58807
+ path_pattern TEXT,
58808
+ behavior TEXT NOT NULL CHECK(behavior IN ('allow','deny')),
58809
+ scope TEXT DEFAULT 'session',
58810
+ created_at TEXT DEFAULT (datetime('now'))
58811
+ );
58812
+
58813
+ -- MCP servers
58814
+ CREATE TABLE IF NOT EXISTS mcp_servers (
58815
+ name TEXT PRIMARY KEY,
58816
+ command TEXT,
58817
+ args TEXT, -- JSON array
58818
+ env TEXT, -- JSON object
58819
+ url TEXT,
58820
+ transport TEXT DEFAULT 'stdio',
58821
+ scope TEXT DEFAULT 'user',
58822
+ enabled INTEGER DEFAULT 1,
58823
+ created_at TEXT DEFAULT (datetime('now'))
58824
+ );
58825
+
58826
+ -- Metrics (per-turn tracking)
58827
+ CREATE TABLE IF NOT EXISTS metrics (
58828
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58829
+ session_id TEXT NOT NULL,
58830
+ turn_index INTEGER,
58831
+ tokens_in INTEGER DEFAULT 0,
58832
+ tokens_out INTEGER DEFAULT 0,
58833
+ cost_usd REAL DEFAULT 0,
58834
+ api_duration_ms REAL DEFAULT 0,
58835
+ tool_duration_ms REAL DEFAULT 0,
58836
+ hook_duration_ms REAL DEFAULT 0,
58837
+ tool_count INTEGER DEFAULT 0,
58838
+ model TEXT,
58839
+ created_at TEXT DEFAULT (datetime('now'))
58840
+ );
58841
+
58842
+ -- Audit log (for security \u2014 tracks all tool executions)
58843
+ CREATE TABLE IF NOT EXISTS audit_log (
58844
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58845
+ session_id TEXT,
58846
+ tool_name TEXT NOT NULL,
58847
+ input_summary TEXT,
58848
+ result_summary TEXT,
58849
+ exit_code INTEGER,
58850
+ duration_ms REAL,
58851
+ was_allowed INTEGER DEFAULT 1,
58852
+ created_at TEXT DEFAULT (datetime('now'))
58853
+ );
58854
+ `);
58855
+ }
58856
+ function dbRun(sql, params = []) {
58857
+ const db = getDb();
58858
+ try {
58859
+ const stmt = db.prepare(sql);
58860
+ return stmt.run(...params);
58861
+ } catch (e) {
58862
+ try {
58863
+ return db.run(sql, params);
58864
+ } catch {
58865
+ throw e;
58866
+ }
58867
+ }
58868
+ }
58869
+ function dbGet(sql, params = []) {
58870
+ const db = getDb();
58871
+ try {
58872
+ const stmt = db.prepare(sql);
58873
+ return stmt.get(...params);
58874
+ } catch {
58875
+ try {
58876
+ return db.query(sql).get(...params);
58877
+ } catch {
58878
+ return void 0;
58879
+ }
58880
+ }
58881
+ }
58882
+ function dbAll(sql, params = []) {
58883
+ const db = getDb();
58884
+ try {
58885
+ const stmt = db.prepare(sql);
58886
+ return stmt.all(...params);
58887
+ } catch {
58888
+ try {
58889
+ return db.query(sql).all(...params);
58890
+ } catch {
58891
+ return [];
58892
+ }
58893
+ }
58894
+ }
58895
+ function createJsonFileDb() {
58896
+ const storePath = join2(getConfigDir(), "coders-fallback.json");
58897
+ let store = { tables: {}, autoInc: {} };
58898
+ try {
58899
+ if (existsSync4(storePath)) {
58900
+ store = JSON.parse(readFileSync3(storePath, "utf-8"));
58901
+ if (!store.tables) store.tables = {};
58902
+ if (!store.autoInc) store.autoInc = {};
58903
+ }
58904
+ } catch {
58905
+ }
58906
+ function flush() {
58907
+ try {
58908
+ writeFileSync2(storePath, JSON.stringify(store), "utf-8");
58909
+ } catch {
58910
+ }
58911
+ }
58912
+ function ensureTable(name) {
58913
+ if (!store.tables[name]) {
58914
+ store.tables[name] = [];
58915
+ store.autoInc[name] = 0;
58916
+ }
58917
+ }
58918
+ function now() {
58919
+ return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
58920
+ }
58921
+ function parseInsert(sql, params) {
58922
+ const m = sql.match(/INSERT\s+(?:OR\s+\w+\s+)?INTO\s+(\w+)\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/i);
58923
+ if (!m) return { changes: 0, lastInsertRowid: 0 };
58924
+ const table = m[1];
58925
+ ensureTable(table);
58926
+ const cols = m[2].split(",").map((c) => c.trim());
58927
+ const valuePlaceholders = m[3].split(",").map((v) => v.trim());
58928
+ const row = {};
58929
+ let paramIdx = 0;
58930
+ for (let i = 0; i < cols.length; i++) {
58931
+ const ph = valuePlaceholders[i];
58932
+ if (ph === "?") {
58933
+ row[cols[i]] = params[paramIdx++];
58934
+ } else if (/^datetime\(/i.test(ph)) {
58935
+ row[cols[i]] = now();
58936
+ } else {
58937
+ row[cols[i]] = ph.replace(/^['"]|['"]$/g, "");
58938
+ }
58939
+ }
58940
+ if (!row["id"] && store.autoInc[table] !== void 0) {
58941
+ store.autoInc[table]++;
58942
+ row["id"] = store.autoInc[table];
58943
+ }
58944
+ store.tables[table].push(row);
58945
+ flush();
58946
+ return { changes: 1, lastInsertRowid: typeof row["id"] === "number" ? row["id"] : 0 };
58947
+ }
58948
+ function parseSelect(sql, params) {
58949
+ const m = sql.match(/SELECT\s+(.+?)\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(.+?))?(?:\s+LIMIT\s+(\d+))?$/i);
58950
+ if (!m) return [];
58951
+ const table = m[2];
58952
+ if (!store.tables[table]) return [];
58953
+ let rows = [...store.tables[table]];
58954
+ if (m[3]) {
58955
+ const whereParts = m[3].trim();
58956
+ const wm = whereParts.match(/(\w+)\s*=\s*\?/);
58957
+ if (wm && params.length > 0) {
58958
+ const col = wm[1];
58959
+ const val = params[0];
58960
+ rows = rows.filter((r) => r[col] === val);
58961
+ }
58962
+ }
58963
+ if (m[5]) {
58964
+ rows = rows.slice(0, parseInt(m[5], 10));
58965
+ }
58966
+ return rows;
58967
+ }
58968
+ function parseUpdate(sql, params) {
58969
+ const m = sql.match(/UPDATE\s+(\w+)\s+SET\s+(.+?)\s+WHERE\s+(.+)/i);
58970
+ if (!m) return { changes: 0 };
58971
+ const table = m[1];
58972
+ if (!store.tables[table]) return { changes: 0 };
58973
+ const setClauses = m[2].split(",").map((s) => s.trim());
58974
+ const whereClause = m[3].trim();
58975
+ const setParamCount = setClauses.filter((c) => c.includes("?")).length;
58976
+ const wm = whereClause.match(/(\w+)\s*=\s*\?/);
58977
+ const whereCol = wm ? wm[1] : null;
58978
+ const whereVal = wm ? params[setParamCount] : null;
58979
+ let changes = 0;
58980
+ for (const row of store.tables[table]) {
58981
+ if (whereCol && row[whereCol] !== whereVal) continue;
58982
+ let paramIdx = 0;
58983
+ for (const clause of setClauses) {
58984
+ const cm = clause.match(/(\w+)\s*=\s*(.+)/);
58985
+ if (!cm) continue;
58986
+ const col = cm[1];
58987
+ const val = cm[2].trim();
58988
+ if (val === "?") {
58989
+ row[col] = params[paramIdx++];
58990
+ } else if (/^datetime\(/i.test(val)) {
58991
+ row[col] = now();
58992
+ }
58993
+ }
58994
+ changes++;
58995
+ }
58996
+ if (changes > 0) flush();
58997
+ return { changes };
58998
+ }
58999
+ function parseDelete(sql, params) {
59000
+ const m = sql.match(/DELETE\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+))?/i);
59001
+ if (!m) return { changes: 0 };
59002
+ const table = m[1];
59003
+ if (!store.tables[table]) return { changes: 0 };
59004
+ if (!m[2]) {
59005
+ const count = store.tables[table].length;
59006
+ store.tables[table] = [];
59007
+ flush();
59008
+ return { changes: count };
59009
+ }
59010
+ const wm = m[2].match(/(\w+)\s*=\s*\?/);
59011
+ if (!wm) return { changes: 0 };
59012
+ const col = wm[1];
59013
+ const val = params[0];
59014
+ const before = store.tables[table].length;
59015
+ store.tables[table] = store.tables[table].filter((r) => r[col] !== val);
59016
+ const changes = before - store.tables[table].length;
59017
+ if (changes > 0) flush();
59018
+ return { changes };
59019
+ }
59020
+ function execSql(sql, params = []) {
59021
+ const trimmed = sql.trim();
59022
+ if (/^INSERT/i.test(trimmed)) return parseInsert(trimmed, params);
59023
+ if (/^SELECT/i.test(trimmed)) return parseSelect(trimmed, params);
59024
+ if (/^UPDATE/i.test(trimmed)) return parseUpdate(trimmed, params);
59025
+ if (/^DELETE/i.test(trimmed)) return parseDelete(trimmed, params);
59026
+ return { changes: 0 };
59027
+ }
59028
+ return {
59029
+ exec(sql) {
59030
+ const matches = sql.matchAll(/CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+(\w+)/gi);
59031
+ for (const m of matches) {
59032
+ ensureTable(m[1]);
59033
+ }
59034
+ },
59035
+ prepare(sql) {
59036
+ return {
59037
+ run(...params) {
59038
+ return execSql(sql, params);
59039
+ },
59040
+ get(...params) {
59041
+ const result = execSql(sql, params);
59042
+ if (Array.isArray(result)) return result[0];
59043
+ return void 0;
59044
+ },
59045
+ all(...params) {
59046
+ const result = execSql(sql, params);
59047
+ if (Array.isArray(result)) return result;
59048
+ return [];
59049
+ }
59050
+ };
59051
+ },
59052
+ // Bun-style API aliases
59053
+ run(sql, params = []) {
59054
+ return execSql(sql, params);
59055
+ },
59056
+ query(sql) {
59057
+ return {
59058
+ get(...params) {
59059
+ const result = execSql(sql, params);
59060
+ if (Array.isArray(result)) return result[0];
59061
+ return void 0;
59062
+ },
59063
+ all(...params) {
59064
+ const result = execSql(sql, params);
59065
+ if (Array.isArray(result)) return result;
59066
+ return [];
59067
+ }
59068
+ };
59069
+ },
59070
+ close() {
59071
+ flush();
59072
+ }
59073
+ };
59074
+ }
59075
+ var _db;
59076
+ var init_db = __esm({
59077
+ "src/db/index.ts"() {
59078
+ "use strict";
59079
+ init_paths();
59080
+ _db = null;
59081
+ }
59082
+ });
59083
+
59084
+ // src/ui/screen/terminal.ts
59085
+ var terminal_exports = {};
59086
+ __export(terminal_exports, {
59087
+ detectTerminal: () => detectTerminal,
59088
+ getTerminalSize: () => getTerminalSize,
59089
+ onResize: () => onResize
59090
+ });
59091
+ function detectTerminal() {
59092
+ const termProgram = process.env.TERM_PROGRAM ?? "";
59093
+ const term = process.env.TERM ?? "";
59094
+ const colorTerm = process.env.COLORTERM ?? "";
59095
+ const caps = {
59096
+ name: detectTerminalName(termProgram, term),
59097
+ colorDepth: detectColorDepth(termProgram, colorTerm, term),
59098
+ unicode: detectUnicode(),
59099
+ hyperlinks: detectHyperlinks(termProgram),
59100
+ kittyProtocol: detectKittyProtocol(termProgram),
59101
+ mouseSupport: true,
59102
+ // Most modern terminals support SGR mouse
59103
+ sixelGraphics: detectSixel(termProgram),
59104
+ iterm2Images: termProgram === "iTerm.app"
59105
+ };
59106
+ return caps;
59107
+ }
59108
+ function detectTerminalName(termProgram, term) {
59109
+ if (termProgram === "iTerm.app") return "iTerm2";
59110
+ if (termProgram === "WezTerm") return "WezTerm";
59111
+ if (termProgram === "vscode") return "VSCode";
59112
+ if (termProgram === "Alacritty") return "Alacritty";
59113
+ if (termProgram === "ghostty") return "Ghostty";
59114
+ if (termProgram === "contour") return "Contour";
59115
+ if (termProgram === "mintty") return "Mintty";
59116
+ if (process.env.KITTY_WINDOW_ID) return "Kitty";
59117
+ if (termProgram === "kitty") return "Kitty";
59118
+ if (term === "foot" || term === "foot-extra") return "foot";
59119
+ if (process.env.WARP_IS_LOCAL_SHELL_SESSION) return "Warp";
59120
+ if (termProgram === "Warp") return "Warp";
59121
+ if (process.env.WT_SESSION) return "Windows Terminal";
59122
+ if (process.env.ConEmuANSI || process.env.ConEmuPID) return "ConEmu";
59123
+ const vteVersion = process.env.VTE_VERSION;
59124
+ if (vteVersion) {
59125
+ const ver = parseInt(vteVersion, 10);
59126
+ if (ver >= 6800) return "VTE (modern)";
59127
+ return "VTE";
59128
+ }
59129
+ if (term.startsWith("xterm")) return "xterm";
59130
+ if (term.startsWith("screen")) return "screen";
59131
+ if (term.startsWith("tmux")) return "tmux";
59132
+ return "unknown";
59133
+ }
59134
+ function detectColorDepth(termProgram, colorTerm, term) {
59135
+ if (colorTerm === "truecolor" || colorTerm === "24bit") return 24;
59136
+ const truecolorTerminals = [
59137
+ "iTerm.app",
59138
+ "WezTerm",
59139
+ "Alacritty",
59140
+ "kitty",
59141
+ "ghostty",
59142
+ "contour",
59143
+ "foot"
59144
+ ];
59145
+ if (truecolorTerminals.includes(termProgram)) return 24;
59146
+ if (process.env.KITTY_WINDOW_ID) return 24;
59147
+ if (process.env.WT_SESSION) return 24;
59148
+ if (termProgram === "vscode") return 24;
59149
+ if (term.includes("256color")) return 8;
59150
+ if (colorTerm) return 8;
59151
+ if (term.includes("color") || term.startsWith("xterm")) return 4;
59152
+ if (term === "dumb" || !process.stdout.isTTY) return 1;
59153
+ return 4;
59154
+ }
59155
+ function detectUnicode() {
59156
+ const lang = process.env.LANG ?? process.env.LC_ALL ?? process.env.LC_CTYPE ?? "";
59157
+ return lang.toLowerCase().includes("utf");
59158
+ }
59159
+ function detectHyperlinks(termProgram) {
59160
+ const supported = [
59161
+ "iTerm.app",
59162
+ "WezTerm",
59163
+ "Alacritty",
59164
+ "kitty",
59165
+ "ghostty",
59166
+ "contour",
59167
+ "foot",
59168
+ "vscode"
59169
+ ];
59170
+ if (supported.includes(termProgram)) return true;
59171
+ if (process.env.KITTY_WINDOW_ID) return true;
59172
+ if (process.env.WT_SESSION) return true;
59173
+ return false;
59174
+ }
59175
+ function detectKittyProtocol(termProgram) {
59176
+ if (process.env.KITTY_WINDOW_ID) return true;
59177
+ if (termProgram === "kitty") return true;
59178
+ if (termProgram === "ghostty") return true;
59179
+ if (termProgram === "foot") return true;
59180
+ if (termProgram === "WezTerm") return true;
59181
+ return false;
59182
+ }
59183
+ function detectSixel(termProgram) {
59184
+ if (termProgram === "WezTerm") return true;
59185
+ if (termProgram === "foot") return true;
59186
+ if (termProgram === "contour") return true;
59187
+ return false;
59188
+ }
59189
+ function getTerminalSize() {
59190
+ return {
59191
+ columns: process.stdout.columns ?? 80,
59192
+ rows: process.stdout.rows ?? 24
59193
+ };
59194
+ }
59195
+ function onResize(callback) {
59196
+ const handler = () => {
59197
+ const { columns, rows } = getTerminalSize();
59198
+ callback(columns, rows);
59199
+ };
59200
+ process.stdout.on("resize", handler);
59201
+ return () => process.stdout.removeListener("resize", handler);
59202
+ }
59203
+ var init_terminal = __esm({
59204
+ "src/ui/screen/terminal.ts"() {
59205
+ "use strict";
59206
+ }
59207
+ });
59208
+
59209
+ // src/core/slash-commands.ts
59210
+ import { writeFileSync as writeFileSync3 } from "fs";
59211
+ function registerSlashCommand(cmd) {
59212
+ commands.set(cmd.name, cmd);
59213
+ if (cmd.aliases) {
59214
+ for (const alias of cmd.aliases) commands.set(alias, cmd);
59215
+ }
59216
+ }
59217
+ function getAllSlashCommands() {
59218
+ const seen = /* @__PURE__ */ new Set();
59219
+ const result = [];
59220
+ for (const cmd of commands.values()) {
59221
+ if (!seen.has(cmd.name)) {
59222
+ seen.add(cmd.name);
59223
+ result.push(cmd);
59224
+ }
59225
+ }
59226
+ return result;
59227
+ }
59228
+ function isSlashCommand(input) {
59229
+ return input.startsWith("/") && commands.has(input.slice(1).split(/\s/)[0]);
59230
+ }
59231
+ async function executeSlashCommand(input) {
59232
+ const parts = input.replace(/^\//, "").split(/\s+/);
59233
+ const name = parts[0];
59234
+ const args = parts.slice(1).join(" ");
59235
+ const cmd = commands.get(name);
59236
+ if (!cmd) return { output: `Unknown command: /${name}. Type /help for available commands.` };
59237
+ return cmd.handler(args);
59238
+ }
59239
+ function registerDefaults() {
59240
+ registerSlashCommand({
59241
+ name: "help",
59242
+ aliases: ["h", "?"],
59243
+ category: "core",
59244
+ description: "Show available commands",
59245
+ handler: () => {
59246
+ const cmds = getAllSlashCommands().sort((a, b) => a.name.localeCompare(b.name));
59247
+ const lines = cmds.map((c) => ` /${c.name.padEnd(16)} ${c.description}`);
59248
+ return { output: `Available commands:
59249
+ ${lines.join("\n")}` };
59250
+ }
59251
+ });
59252
+ registerSlashCommand({
59253
+ name: "clear",
59254
+ category: "core",
59255
+ description: "Clear conversation history",
59256
+ handler: () => ({ action: "clear", output: "Conversation cleared." })
59257
+ });
59258
+ registerSlashCommand({
59259
+ name: "compact",
59260
+ category: "core",
59261
+ description: "Compact conversation context",
59262
+ handler: () => ({ action: "compact", output: "Context compacted." })
59263
+ });
59264
+ registerSlashCommand({
59265
+ name: "exit",
59266
+ aliases: ["quit", "q"],
59267
+ category: "core",
59268
+ description: "Exit coders",
59269
+ handler: () => ({ action: "exit" })
59270
+ });
59271
+ registerSlashCommand({
59272
+ name: "plan",
59273
+ category: "core",
59274
+ description: "View or edit the current plan",
59275
+ handler: () => ({ output: "Plan mode \u2014 use EnterPlanMode tool to start planning." })
59276
+ });
59277
+ registerSlashCommand({
59278
+ name: "model",
59279
+ category: "mode",
59280
+ description: "View or change the current model",
59281
+ handler: (args) => {
59282
+ if (args) return { action: "setModel", data: args, output: `Model set to: ${args}` };
59283
+ return { output: "Current model \u2014 use /model <name> to change." };
59284
+ }
59285
+ });
59286
+ registerSlashCommand({
59287
+ name: "fast",
59288
+ category: "mode",
59289
+ description: "Toggle fast mode",
59290
+ handler: () => ({ output: "Fast mode toggled." })
59291
+ });
59292
+ registerSlashCommand({
59293
+ name: "verbose",
59294
+ category: "mode",
59295
+ description: "Toggle verbose output",
59296
+ handler: () => ({ output: "Verbose mode toggled." })
59297
+ });
59298
+ registerSlashCommand({
59299
+ name: "status",
59300
+ category: "system",
59301
+ description: "Show session status",
59302
+ handler: () => ({ output: "Session status \u2014 not yet wired." })
59303
+ });
59304
+ registerSlashCommand({
59305
+ name: "config",
59306
+ category: "system",
59307
+ description: "View or modify settings",
59308
+ handler: (args) => ({ output: args ? `Config: ${args}` : "Use /config <key> [value]" })
59309
+ });
59310
+ registerSlashCommand({
59311
+ name: "mcp",
59312
+ category: "system",
59313
+ description: "Show MCP server status",
59314
+ handler: () => ({ output: "MCP servers \u2014 use 'coders mcp list' for details." })
59315
+ });
58873
59316
  registerSlashCommand({
58874
59317
  name: "memory",
58875
59318
  category: "core",
@@ -58937,11 +59380,78 @@ ${lines.join("\n")}` };
58937
59380
  return { output: `Terminal: ${caps.name}, Color: ${caps.colorDepth}bit, Unicode: ${caps.unicode}` };
58938
59381
  }
58939
59382
  });
59383
+ registerSlashCommand({
59384
+ name: "rewind",
59385
+ category: "core",
59386
+ description: "List recent file checkpoints and restore one",
59387
+ handler: (args) => {
59388
+ const checkpoints = dbAll(
59389
+ "SELECT * FROM checkpoints ORDER BY created_at DESC LIMIT 10"
59390
+ );
59391
+ if (checkpoints.length === 0) {
59392
+ return { output: "No checkpoints found. Checkpoints are created when files are edited or overwritten." };
59393
+ }
59394
+ const choice = parseInt(args, 10);
59395
+ if (!isNaN(choice) && choice >= 1 && choice <= checkpoints.length) {
59396
+ const cp = checkpoints[choice - 1];
59397
+ try {
59398
+ writeFileSync3(cp.file_path, cp.original_content, "utf-8");
59399
+ const op = cp.edit_operation ? JSON.parse(cp.edit_operation) : null;
59400
+ const summary = op?.old_string ? `Reverted edit: "${truncate(op.old_string, 40)}" -> "${truncate(op.new_string, 40)}"` : "Restored original content";
59401
+ return { output: `Restored checkpoint #${choice}: ${cp.file_path}
59402
+ ${summary}` };
59403
+ } catch (e) {
59404
+ return { output: `Failed to restore checkpoint: ${e instanceof Error ? e.message : String(e)}` };
59405
+ }
59406
+ }
59407
+ const lines = checkpoints.map((cp, i) => {
59408
+ const op = cp.edit_operation ? JSON.parse(cp.edit_operation) : null;
59409
+ const summary = op?.old_string ? `"${truncate(op.old_string, 30)}" -> "${truncate(op.new_string, 30)}"` : op?.type === "write_overwrite" ? "file overwrite" : "unknown operation";
59410
+ return ` ${i + 1}. [${cp.created_at}] ${cp.file_path}
59411
+ ${summary}`;
59412
+ });
59413
+ return {
59414
+ output: `Recent checkpoints:
59415
+ ${lines.join("\n")}
59416
+
59417
+ Use /rewind <number> to restore a checkpoint.`
59418
+ };
59419
+ }
59420
+ });
59421
+ registerSlashCommand({
59422
+ name: "undo",
59423
+ category: "core",
59424
+ description: "Revert the last file edit from the most recent checkpoint",
59425
+ handler: () => {
59426
+ const cp = dbGet(
59427
+ "SELECT * FROM checkpoints ORDER BY created_at DESC LIMIT 1"
59428
+ );
59429
+ if (!cp) {
59430
+ return { output: "No checkpoints found. Nothing to undo." };
59431
+ }
59432
+ try {
59433
+ writeFileSync3(cp.file_path, cp.original_content, "utf-8");
59434
+ const op = cp.edit_operation ? JSON.parse(cp.edit_operation) : null;
59435
+ const summary = op?.old_string ? `Reverted: "${truncate(op.old_string, 50)}" -> "${truncate(op.new_string, 50)}"` : op?.type === "write_overwrite" ? "Restored file before overwrite" : "Restored original content";
59436
+ return { output: `Undo successful: ${cp.file_path}
59437
+ ${summary}
59438
+ [checkpoint: ${cp.id} at ${cp.created_at}]` };
59439
+ } catch (e) {
59440
+ return { output: `Failed to undo: ${e instanceof Error ? e.message : String(e)}` };
59441
+ }
59442
+ }
59443
+ });
59444
+ }
59445
+ function truncate(s, max) {
59446
+ if (!s) return "";
59447
+ const oneLine = s.replace(/\n/g, "\\n");
59448
+ return oneLine.length > max ? oneLine.slice(0, max) + "..." : oneLine;
58940
59449
  }
58941
59450
  var commands;
58942
59451
  var init_slash_commands = __esm({
58943
59452
  "src/core/slash-commands.ts"() {
58944
59453
  "use strict";
59454
+ init_db();
58945
59455
  commands = /* @__PURE__ */ new Map();
58946
59456
  registerDefaults();
58947
59457
  }
@@ -60378,1548 +60888,1144 @@ ${currentText}` : currentText;
60378
60888
  }
60379
60889
  blockquote({ tokens }) {
60380
60890
  const body = this.parser.parse(tokens);
60381
- return `<blockquote>
60382
- ${body}</blockquote>
60383
- `;
60384
- }
60385
- html({ text }) {
60386
- return text;
60387
- }
60388
- heading({ tokens, depth }) {
60389
- return `<h${depth}>${this.parser.parseInline(tokens)}</h${depth}>
60390
- `;
60391
- }
60392
- hr(token) {
60393
- return "<hr>\n";
60394
- }
60395
- list(token) {
60396
- const ordered = token.ordered;
60397
- const start = token.start;
60398
- let body = "";
60399
- for (let j = 0; j < token.items.length; j++) {
60400
- const item = token.items[j];
60401
- body += this.listitem(item);
60402
- }
60403
- const type = ordered ? "ol" : "ul";
60404
- const startAttr = ordered && start !== 1 ? ' start="' + start + '"' : "";
60405
- return "<" + type + startAttr + ">\n" + body + "</" + type + ">\n";
60406
- }
60407
- listitem(item) {
60408
- let itemBody = "";
60409
- if (item.task) {
60410
- const checkbox = this.checkbox({ checked: !!item.checked });
60411
- if (item.loose) {
60412
- if (item.tokens[0]?.type === "paragraph") {
60413
- item.tokens[0].text = checkbox + " " + item.tokens[0].text;
60414
- if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") {
60415
- item.tokens[0].tokens[0].text = checkbox + " " + escape22(item.tokens[0].tokens[0].text);
60416
- item.tokens[0].tokens[0].escaped = true;
60417
- }
60418
- } else {
60419
- item.tokens.unshift({
60420
- type: "text",
60421
- raw: checkbox + " ",
60422
- text: checkbox + " ",
60423
- escaped: true
60424
- });
60425
- }
60426
- } else {
60427
- itemBody += checkbox + " ";
60428
- }
60429
- }
60430
- itemBody += this.parser.parse(item.tokens, !!item.loose);
60431
- return `<li>${itemBody}</li>
60432
- `;
60433
- }
60434
- checkbox({ checked }) {
60435
- return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox">';
60436
- }
60437
- paragraph({ tokens }) {
60438
- return `<p>${this.parser.parseInline(tokens)}</p>
60439
- `;
60440
- }
60441
- table(token) {
60442
- let header = "";
60443
- let cell = "";
60444
- for (let j = 0; j < token.header.length; j++) {
60445
- cell += this.tablecell(token.header[j]);
60446
- }
60447
- header += this.tablerow({ text: cell });
60448
- let body = "";
60449
- for (let j = 0; j < token.rows.length; j++) {
60450
- const row = token.rows[j];
60451
- cell = "";
60452
- for (let k = 0; k < row.length; k++) {
60453
- cell += this.tablecell(row[k]);
60454
- }
60455
- body += this.tablerow({ text: cell });
60456
- }
60457
- if (body) body = `<tbody>${body}</tbody>`;
60458
- return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
60459
- }
60460
- tablerow({ text }) {
60461
- return `<tr>
60462
- ${text}</tr>
60463
- `;
60464
- }
60465
- tablecell(token) {
60466
- const content = this.parser.parseInline(token.tokens);
60467
- const type = token.header ? "th" : "td";
60468
- const tag2 = token.align ? `<${type} align="${token.align}">` : `<${type}>`;
60469
- return tag2 + content + `</${type}>
60470
- `;
60471
- }
60472
- /**
60473
- * span level renderer
60474
- */
60475
- strong({ tokens }) {
60476
- return `<strong>${this.parser.parseInline(tokens)}</strong>`;
60477
- }
60478
- em({ tokens }) {
60479
- return `<em>${this.parser.parseInline(tokens)}</em>`;
60480
- }
60481
- codespan({ text }) {
60482
- return `<code>${escape22(text, true)}</code>`;
60483
- }
60484
- br(token) {
60485
- return "<br>";
60486
- }
60487
- del({ tokens }) {
60488
- return `<del>${this.parser.parseInline(tokens)}</del>`;
60489
- }
60490
- link({ href, title, tokens }) {
60491
- const text = this.parser.parseInline(tokens);
60492
- const cleanHref = cleanUrl(href);
60493
- if (cleanHref === null) {
60494
- return text;
60495
- }
60496
- href = cleanHref;
60497
- let out = '<a href="' + href + '"';
60498
- if (title) {
60499
- out += ' title="' + escape22(title) + '"';
60500
- }
60501
- out += ">" + text + "</a>";
60502
- return out;
60503
- }
60504
- image({ href, title, text, tokens }) {
60505
- if (tokens) {
60506
- text = this.parser.parseInline(tokens, this.parser.textRenderer);
60507
- }
60508
- const cleanHref = cleanUrl(href);
60509
- if (cleanHref === null) {
60510
- return escape22(text);
60511
- }
60512
- href = cleanHref;
60513
- let out = `<img src="${href}" alt="${text}"`;
60514
- if (title) {
60515
- out += ` title="${escape22(title)}"`;
60516
- }
60517
- out += ">";
60518
- return out;
60519
- }
60520
- text(token) {
60521
- return "tokens" in token && token.tokens ? this.parser.parseInline(token.tokens) : "escaped" in token && token.escaped ? token.text : escape22(token.text);
60522
- }
60523
- };
60524
- _TextRenderer = class {
60525
- // no need for block level renderers
60526
- strong({ text }) {
60527
- return text;
60528
- }
60529
- em({ text }) {
60530
- return text;
60531
- }
60532
- codespan({ text }) {
60533
- return text;
60534
- }
60535
- del({ text }) {
60536
- return text;
60891
+ return `<blockquote>
60892
+ ${body}</blockquote>
60893
+ `;
60537
60894
  }
60538
60895
  html({ text }) {
60539
60896
  return text;
60540
60897
  }
60541
- text({ text }) {
60542
- return text;
60543
- }
60544
- link({ text }) {
60545
- return "" + text;
60546
- }
60547
- image({ text }) {
60548
- return "" + text;
60549
- }
60550
- br() {
60551
- return "";
60552
- }
60553
- };
60554
- _Parser = class __Parser {
60555
- options;
60556
- renderer;
60557
- textRenderer;
60558
- constructor(options2) {
60559
- this.options = options2 || _defaults;
60560
- this.options.renderer = this.options.renderer || new _Renderer();
60561
- this.renderer = this.options.renderer;
60562
- this.renderer.options = this.options;
60563
- this.renderer.parser = this;
60564
- this.textRenderer = new _TextRenderer();
60898
+ heading({ tokens, depth }) {
60899
+ return `<h${depth}>${this.parser.parseInline(tokens)}</h${depth}>
60900
+ `;
60565
60901
  }
60566
- /**
60567
- * Static Parse Method
60568
- */
60569
- static parse(tokens, options2) {
60570
- const parser2 = new __Parser(options2);
60571
- return parser2.parse(tokens);
60902
+ hr(token) {
60903
+ return "<hr>\n";
60572
60904
  }
60573
- /**
60574
- * Static Parse Inline Method
60575
- */
60576
- static parseInline(tokens, options2) {
60577
- const parser2 = new __Parser(options2);
60578
- return parser2.parseInline(tokens);
60905
+ list(token) {
60906
+ const ordered = token.ordered;
60907
+ const start = token.start;
60908
+ let body = "";
60909
+ for (let j = 0; j < token.items.length; j++) {
60910
+ const item = token.items[j];
60911
+ body += this.listitem(item);
60912
+ }
60913
+ const type = ordered ? "ol" : "ul";
60914
+ const startAttr = ordered && start !== 1 ? ' start="' + start + '"' : "";
60915
+ return "<" + type + startAttr + ">\n" + body + "</" + type + ">\n";
60579
60916
  }
60580
- /**
60581
- * Parse Loop
60582
- */
60583
- parse(tokens, top = true) {
60584
- let out = "";
60585
- for (let i = 0; i < tokens.length; i++) {
60586
- const anyToken = tokens[i];
60587
- if (this.options.extensions?.renderers?.[anyToken.type]) {
60588
- const genericToken = anyToken;
60589
- const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
60590
- if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(genericToken.type)) {
60591
- out += ret || "";
60592
- continue;
60593
- }
60594
- }
60595
- const token = anyToken;
60596
- switch (token.type) {
60597
- case "space": {
60598
- out += this.renderer.space(token);
60599
- continue;
60600
- }
60601
- case "hr": {
60602
- out += this.renderer.hr(token);
60603
- continue;
60604
- }
60605
- case "heading": {
60606
- out += this.renderer.heading(token);
60607
- continue;
60608
- }
60609
- case "code": {
60610
- out += this.renderer.code(token);
60611
- continue;
60612
- }
60613
- case "table": {
60614
- out += this.renderer.table(token);
60615
- continue;
60616
- }
60617
- case "blockquote": {
60618
- out += this.renderer.blockquote(token);
60619
- continue;
60620
- }
60621
- case "list": {
60622
- out += this.renderer.list(token);
60623
- continue;
60624
- }
60625
- case "html": {
60626
- out += this.renderer.html(token);
60627
- continue;
60628
- }
60629
- case "paragraph": {
60630
- out += this.renderer.paragraph(token);
60631
- continue;
60632
- }
60633
- case "text": {
60634
- let textToken = token;
60635
- let body = this.renderer.text(textToken);
60636
- while (i + 1 < tokens.length && tokens[i + 1].type === "text") {
60637
- textToken = tokens[++i];
60638
- body += "\n" + this.renderer.text(textToken);
60639
- }
60640
- if (top) {
60641
- out += this.renderer.paragraph({
60642
- type: "paragraph",
60643
- raw: body,
60644
- text: body,
60645
- tokens: [{ type: "text", raw: body, text: body, escaped: true }]
60646
- });
60647
- } else {
60648
- out += body;
60649
- }
60650
- continue;
60651
- }
60652
- default: {
60653
- const errMsg = 'Token with "' + token.type + '" type was not found.';
60654
- if (this.options.silent) {
60655
- console.error(errMsg);
60656
- return "";
60657
- } else {
60658
- throw new Error(errMsg);
60917
+ listitem(item) {
60918
+ let itemBody = "";
60919
+ if (item.task) {
60920
+ const checkbox = this.checkbox({ checked: !!item.checked });
60921
+ if (item.loose) {
60922
+ if (item.tokens[0]?.type === "paragraph") {
60923
+ item.tokens[0].text = checkbox + " " + item.tokens[0].text;
60924
+ if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") {
60925
+ item.tokens[0].tokens[0].text = checkbox + " " + escape22(item.tokens[0].tokens[0].text);
60926
+ item.tokens[0].tokens[0].escaped = true;
60659
60927
  }
60928
+ } else {
60929
+ item.tokens.unshift({
60930
+ type: "text",
60931
+ raw: checkbox + " ",
60932
+ text: checkbox + " ",
60933
+ escaped: true
60934
+ });
60660
60935
  }
60936
+ } else {
60937
+ itemBody += checkbox + " ";
60661
60938
  }
60662
60939
  }
60663
- return out;
60940
+ itemBody += this.parser.parse(item.tokens, !!item.loose);
60941
+ return `<li>${itemBody}</li>
60942
+ `;
60664
60943
  }
60665
- /**
60666
- * Parse Inline Tokens
60667
- */
60668
- parseInline(tokens, renderer2 = this.renderer) {
60669
- let out = "";
60670
- for (let i = 0; i < tokens.length; i++) {
60671
- const anyToken = tokens[i];
60672
- if (this.options.extensions?.renderers?.[anyToken.type]) {
60673
- const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken);
60674
- if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(anyToken.type)) {
60675
- out += ret || "";
60676
- continue;
60677
- }
60678
- }
60679
- const token = anyToken;
60680
- switch (token.type) {
60681
- case "escape": {
60682
- out += renderer2.text(token);
60683
- break;
60684
- }
60685
- case "html": {
60686
- out += renderer2.html(token);
60687
- break;
60688
- }
60689
- case "link": {
60690
- out += renderer2.link(token);
60691
- break;
60692
- }
60693
- case "image": {
60694
- out += renderer2.image(token);
60695
- break;
60696
- }
60697
- case "strong": {
60698
- out += renderer2.strong(token);
60699
- break;
60700
- }
60701
- case "em": {
60702
- out += renderer2.em(token);
60703
- break;
60704
- }
60705
- case "codespan": {
60706
- out += renderer2.codespan(token);
60707
- break;
60708
- }
60709
- case "br": {
60710
- out += renderer2.br(token);
60711
- break;
60712
- }
60713
- case "del": {
60714
- out += renderer2.del(token);
60715
- break;
60716
- }
60717
- case "text": {
60718
- out += renderer2.text(token);
60719
- break;
60720
- }
60721
- default: {
60722
- const errMsg = 'Token with "' + token.type + '" type was not found.';
60723
- if (this.options.silent) {
60724
- console.error(errMsg);
60725
- return "";
60726
- } else {
60727
- throw new Error(errMsg);
60728
- }
60729
- }
60944
+ checkbox({ checked }) {
60945
+ return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox">';
60946
+ }
60947
+ paragraph({ tokens }) {
60948
+ return `<p>${this.parser.parseInline(tokens)}</p>
60949
+ `;
60950
+ }
60951
+ table(token) {
60952
+ let header = "";
60953
+ let cell = "";
60954
+ for (let j = 0; j < token.header.length; j++) {
60955
+ cell += this.tablecell(token.header[j]);
60956
+ }
60957
+ header += this.tablerow({ text: cell });
60958
+ let body = "";
60959
+ for (let j = 0; j < token.rows.length; j++) {
60960
+ const row = token.rows[j];
60961
+ cell = "";
60962
+ for (let k = 0; k < row.length; k++) {
60963
+ cell += this.tablecell(row[k]);
60730
60964
  }
60965
+ body += this.tablerow({ text: cell });
60966
+ }
60967
+ if (body) body = `<tbody>${body}</tbody>`;
60968
+ return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
60969
+ }
60970
+ tablerow({ text }) {
60971
+ return `<tr>
60972
+ ${text}</tr>
60973
+ `;
60974
+ }
60975
+ tablecell(token) {
60976
+ const content = this.parser.parseInline(token.tokens);
60977
+ const type = token.header ? "th" : "td";
60978
+ const tag2 = token.align ? `<${type} align="${token.align}">` : `<${type}>`;
60979
+ return tag2 + content + `</${type}>
60980
+ `;
60981
+ }
60982
+ /**
60983
+ * span level renderer
60984
+ */
60985
+ strong({ tokens }) {
60986
+ return `<strong>${this.parser.parseInline(tokens)}</strong>`;
60987
+ }
60988
+ em({ tokens }) {
60989
+ return `<em>${this.parser.parseInline(tokens)}</em>`;
60990
+ }
60991
+ codespan({ text }) {
60992
+ return `<code>${escape22(text, true)}</code>`;
60993
+ }
60994
+ br(token) {
60995
+ return "<br>";
60996
+ }
60997
+ del({ tokens }) {
60998
+ return `<del>${this.parser.parseInline(tokens)}</del>`;
60999
+ }
61000
+ link({ href, title, tokens }) {
61001
+ const text = this.parser.parseInline(tokens);
61002
+ const cleanHref = cleanUrl(href);
61003
+ if (cleanHref === null) {
61004
+ return text;
61005
+ }
61006
+ href = cleanHref;
61007
+ let out = '<a href="' + href + '"';
61008
+ if (title) {
61009
+ out += ' title="' + escape22(title) + '"';
61010
+ }
61011
+ out += ">" + text + "</a>";
61012
+ return out;
61013
+ }
61014
+ image({ href, title, text, tokens }) {
61015
+ if (tokens) {
61016
+ text = this.parser.parseInline(tokens, this.parser.textRenderer);
61017
+ }
61018
+ const cleanHref = cleanUrl(href);
61019
+ if (cleanHref === null) {
61020
+ return escape22(text);
61021
+ }
61022
+ href = cleanHref;
61023
+ let out = `<img src="${href}" alt="${text}"`;
61024
+ if (title) {
61025
+ out += ` title="${escape22(title)}"`;
60731
61026
  }
61027
+ out += ">";
60732
61028
  return out;
60733
61029
  }
61030
+ text(token) {
61031
+ return "tokens" in token && token.tokens ? this.parser.parseInline(token.tokens) : "escaped" in token && token.escaped ? token.text : escape22(token.text);
61032
+ }
60734
61033
  };
60735
- _Hooks = class {
60736
- options;
60737
- block;
60738
- constructor(options2) {
60739
- this.options = options2 || _defaults;
61034
+ _TextRenderer = class {
61035
+ // no need for block level renderers
61036
+ strong({ text }) {
61037
+ return text;
60740
61038
  }
60741
- static passThroughHooks = /* @__PURE__ */ new Set([
60742
- "preprocess",
60743
- "postprocess",
60744
- "processAllTokens"
60745
- ]);
60746
- /**
60747
- * Process markdown before marked
60748
- */
60749
- preprocess(markdown) {
60750
- return markdown;
61039
+ em({ text }) {
61040
+ return text;
60751
61041
  }
60752
- /**
60753
- * Process HTML after marked is finished
60754
- */
60755
- postprocess(html2) {
60756
- return html2;
61042
+ codespan({ text }) {
61043
+ return text;
60757
61044
  }
60758
- /**
60759
- * Process all tokens before walk tokens
60760
- */
60761
- processAllTokens(tokens) {
60762
- return tokens;
61045
+ del({ text }) {
61046
+ return text;
60763
61047
  }
60764
- /**
60765
- * Provide function to tokenize markdown
60766
- */
60767
- provideLexer() {
60768
- return this.block ? _Lexer.lex : _Lexer.lexInline;
61048
+ html({ text }) {
61049
+ return text;
60769
61050
  }
60770
- /**
60771
- * Provide function to parse tokens
60772
- */
60773
- provideParser() {
60774
- return this.block ? _Parser.parse : _Parser.parseInline;
61051
+ text({ text }) {
61052
+ return text;
61053
+ }
61054
+ link({ text }) {
61055
+ return "" + text;
61056
+ }
61057
+ image({ text }) {
61058
+ return "" + text;
61059
+ }
61060
+ br() {
61061
+ return "";
60775
61062
  }
60776
61063
  };
60777
- Marked = class {
60778
- defaults = _getDefaults();
60779
- options = this.setOptions;
60780
- parse = this.parseMarkdown(true);
60781
- parseInline = this.parseMarkdown(false);
60782
- Parser = _Parser;
60783
- Renderer = _Renderer;
60784
- TextRenderer = _TextRenderer;
60785
- Lexer = _Lexer;
60786
- Tokenizer = _Tokenizer;
60787
- Hooks = _Hooks;
60788
- constructor(...args) {
60789
- this.use(...args);
61064
+ _Parser = class __Parser {
61065
+ options;
61066
+ renderer;
61067
+ textRenderer;
61068
+ constructor(options2) {
61069
+ this.options = options2 || _defaults;
61070
+ this.options.renderer = this.options.renderer || new _Renderer();
61071
+ this.renderer = this.options.renderer;
61072
+ this.renderer.options = this.options;
61073
+ this.renderer.parser = this;
61074
+ this.textRenderer = new _TextRenderer();
60790
61075
  }
60791
61076
  /**
60792
- * Run callback for every token
61077
+ * Static Parse Method
60793
61078
  */
60794
- walkTokens(tokens, callback) {
60795
- let values = [];
60796
- for (const token of tokens) {
60797
- values = values.concat(callback.call(this, token));
60798
- switch (token.type) {
60799
- case "table": {
60800
- const tableToken = token;
60801
- for (const cell of tableToken.header) {
60802
- values = values.concat(this.walkTokens(cell.tokens, callback));
60803
- }
60804
- for (const row of tableToken.rows) {
60805
- for (const cell of row) {
60806
- values = values.concat(this.walkTokens(cell.tokens, callback));
60807
- }
60808
- }
60809
- break;
60810
- }
60811
- case "list": {
60812
- const listToken = token;
60813
- values = values.concat(this.walkTokens(listToken.items, callback));
60814
- break;
60815
- }
60816
- default: {
60817
- const genericToken = token;
60818
- if (this.defaults.extensions?.childTokens?.[genericToken.type]) {
60819
- this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
60820
- const tokens2 = genericToken[childTokens].flat(Infinity);
60821
- values = values.concat(this.walkTokens(tokens2, callback));
60822
- });
60823
- } else if (genericToken.tokens) {
60824
- values = values.concat(this.walkTokens(genericToken.tokens, callback));
60825
- }
60826
- }
60827
- }
60828
- }
60829
- return values;
61079
+ static parse(tokens, options2) {
61080
+ const parser2 = new __Parser(options2);
61081
+ return parser2.parse(tokens);
60830
61082
  }
60831
- use(...args) {
60832
- const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
60833
- args.forEach((pack) => {
60834
- const opts = { ...pack };
60835
- opts.async = this.defaults.async || opts.async || false;
60836
- if (pack.extensions) {
60837
- pack.extensions.forEach((ext) => {
60838
- if (!ext.name) {
60839
- throw new Error("extension name required");
60840
- }
60841
- if ("renderer" in ext) {
60842
- const prevRenderer = extensions.renderers[ext.name];
60843
- if (prevRenderer) {
60844
- extensions.renderers[ext.name] = function(...args2) {
60845
- let ret = ext.renderer.apply(this, args2);
60846
- if (ret === false) {
60847
- ret = prevRenderer.apply(this, args2);
60848
- }
60849
- return ret;
60850
- };
60851
- } else {
60852
- extensions.renderers[ext.name] = ext.renderer;
60853
- }
60854
- }
60855
- if ("tokenizer" in ext) {
60856
- if (!ext.level || ext.level !== "block" && ext.level !== "inline") {
60857
- throw new Error("extension level must be 'block' or 'inline'");
60858
- }
60859
- const extLevel = extensions[ext.level];
60860
- if (extLevel) {
60861
- extLevel.unshift(ext.tokenizer);
60862
- } else {
60863
- extensions[ext.level] = [ext.tokenizer];
60864
- }
60865
- if (ext.start) {
60866
- if (ext.level === "block") {
60867
- if (extensions.startBlock) {
60868
- extensions.startBlock.push(ext.start);
60869
- } else {
60870
- extensions.startBlock = [ext.start];
60871
- }
60872
- } else if (ext.level === "inline") {
60873
- if (extensions.startInline) {
60874
- extensions.startInline.push(ext.start);
60875
- } else {
60876
- extensions.startInline = [ext.start];
60877
- }
60878
- }
60879
- }
60880
- }
60881
- if ("childTokens" in ext && ext.childTokens) {
60882
- extensions.childTokens[ext.name] = ext.childTokens;
60883
- }
60884
- });
60885
- opts.extensions = extensions;
60886
- }
60887
- if (pack.renderer) {
60888
- const renderer2 = this.defaults.renderer || new _Renderer(this.defaults);
60889
- for (const prop in pack.renderer) {
60890
- if (!(prop in renderer2)) {
60891
- throw new Error(`renderer '${prop}' does not exist`);
60892
- }
60893
- if (["options", "parser"].includes(prop)) {
60894
- continue;
60895
- }
60896
- const rendererProp = prop;
60897
- const rendererFunc = pack.renderer[rendererProp];
60898
- const prevRenderer = renderer2[rendererProp];
60899
- renderer2[rendererProp] = (...args2) => {
60900
- let ret = rendererFunc.apply(renderer2, args2);
60901
- if (ret === false) {
60902
- ret = prevRenderer.apply(renderer2, args2);
60903
- }
60904
- return ret || "";
60905
- };
61083
+ /**
61084
+ * Static Parse Inline Method
61085
+ */
61086
+ static parseInline(tokens, options2) {
61087
+ const parser2 = new __Parser(options2);
61088
+ return parser2.parseInline(tokens);
61089
+ }
61090
+ /**
61091
+ * Parse Loop
61092
+ */
61093
+ parse(tokens, top = true) {
61094
+ let out = "";
61095
+ for (let i = 0; i < tokens.length; i++) {
61096
+ const anyToken = tokens[i];
61097
+ if (this.options.extensions?.renderers?.[anyToken.type]) {
61098
+ const genericToken = anyToken;
61099
+ const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
61100
+ if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(genericToken.type)) {
61101
+ out += ret || "";
61102
+ continue;
60906
61103
  }
60907
- opts.renderer = renderer2;
60908
61104
  }
60909
- if (pack.tokenizer) {
60910
- const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
60911
- for (const prop in pack.tokenizer) {
60912
- if (!(prop in tokenizer)) {
60913
- throw new Error(`tokenizer '${prop}' does not exist`);
60914
- }
60915
- if (["options", "rules", "lexer"].includes(prop)) {
60916
- continue;
60917
- }
60918
- const tokenizerProp = prop;
60919
- const tokenizerFunc = pack.tokenizer[tokenizerProp];
60920
- const prevTokenizer = tokenizer[tokenizerProp];
60921
- tokenizer[tokenizerProp] = (...args2) => {
60922
- let ret = tokenizerFunc.apply(tokenizer, args2);
60923
- if (ret === false) {
60924
- ret = prevTokenizer.apply(tokenizer, args2);
60925
- }
60926
- return ret;
60927
- };
61105
+ const token = anyToken;
61106
+ switch (token.type) {
61107
+ case "space": {
61108
+ out += this.renderer.space(token);
61109
+ continue;
60928
61110
  }
60929
- opts.tokenizer = tokenizer;
60930
- }
60931
- if (pack.hooks) {
60932
- const hooks = this.defaults.hooks || new _Hooks();
60933
- for (const prop in pack.hooks) {
60934
- if (!(prop in hooks)) {
60935
- throw new Error(`hook '${prop}' does not exist`);
60936
- }
60937
- if (["options", "block"].includes(prop)) {
60938
- continue;
61111
+ case "hr": {
61112
+ out += this.renderer.hr(token);
61113
+ continue;
61114
+ }
61115
+ case "heading": {
61116
+ out += this.renderer.heading(token);
61117
+ continue;
61118
+ }
61119
+ case "code": {
61120
+ out += this.renderer.code(token);
61121
+ continue;
61122
+ }
61123
+ case "table": {
61124
+ out += this.renderer.table(token);
61125
+ continue;
61126
+ }
61127
+ case "blockquote": {
61128
+ out += this.renderer.blockquote(token);
61129
+ continue;
61130
+ }
61131
+ case "list": {
61132
+ out += this.renderer.list(token);
61133
+ continue;
61134
+ }
61135
+ case "html": {
61136
+ out += this.renderer.html(token);
61137
+ continue;
61138
+ }
61139
+ case "paragraph": {
61140
+ out += this.renderer.paragraph(token);
61141
+ continue;
61142
+ }
61143
+ case "text": {
61144
+ let textToken = token;
61145
+ let body = this.renderer.text(textToken);
61146
+ while (i + 1 < tokens.length && tokens[i + 1].type === "text") {
61147
+ textToken = tokens[++i];
61148
+ body += "\n" + this.renderer.text(textToken);
60939
61149
  }
60940
- const hooksProp = prop;
60941
- const hooksFunc = pack.hooks[hooksProp];
60942
- const prevHook = hooks[hooksProp];
60943
- if (_Hooks.passThroughHooks.has(prop)) {
60944
- hooks[hooksProp] = (arg) => {
60945
- if (this.defaults.async) {
60946
- return Promise.resolve(hooksFunc.call(hooks, arg)).then((ret2) => {
60947
- return prevHook.call(hooks, ret2);
60948
- });
60949
- }
60950
- const ret = hooksFunc.call(hooks, arg);
60951
- return prevHook.call(hooks, ret);
60952
- };
61150
+ if (top) {
61151
+ out += this.renderer.paragraph({
61152
+ type: "paragraph",
61153
+ raw: body,
61154
+ text: body,
61155
+ tokens: [{ type: "text", raw: body, text: body, escaped: true }]
61156
+ });
60953
61157
  } else {
60954
- hooks[hooksProp] = (...args2) => {
60955
- let ret = hooksFunc.apply(hooks, args2);
60956
- if (ret === false) {
60957
- ret = prevHook.apply(hooks, args2);
60958
- }
60959
- return ret;
60960
- };
61158
+ out += body;
60961
61159
  }
61160
+ continue;
60962
61161
  }
60963
- opts.hooks = hooks;
60964
- }
60965
- if (pack.walkTokens) {
60966
- const walkTokens2 = this.defaults.walkTokens;
60967
- const packWalktokens = pack.walkTokens;
60968
- opts.walkTokens = function(token) {
60969
- let values = [];
60970
- values.push(packWalktokens.call(this, token));
60971
- if (walkTokens2) {
60972
- values = values.concat(walkTokens2.call(this, token));
61162
+ default: {
61163
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
61164
+ if (this.options.silent) {
61165
+ console.error(errMsg);
61166
+ return "";
61167
+ } else {
61168
+ throw new Error(errMsg);
60973
61169
  }
60974
- return values;
60975
- };
61170
+ }
60976
61171
  }
60977
- this.defaults = { ...this.defaults, ...opts };
60978
- });
60979
- return this;
60980
- }
60981
- setOptions(opt) {
60982
- this.defaults = { ...this.defaults, ...opt };
60983
- return this;
60984
- }
60985
- lexer(src, options2) {
60986
- return _Lexer.lex(src, options2 ?? this.defaults);
60987
- }
60988
- parser(tokens, options2) {
60989
- return _Parser.parse(tokens, options2 ?? this.defaults);
61172
+ }
61173
+ return out;
60990
61174
  }
60991
- parseMarkdown(blockType) {
60992
- const parse2 = (src, options2) => {
60993
- const origOpt = { ...options2 };
60994
- const opt = { ...this.defaults, ...origOpt };
60995
- const throwError = this.onError(!!opt.silent, !!opt.async);
60996
- if (this.defaults.async === true && origOpt.async === false) {
60997
- return throwError(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
60998
- }
60999
- if (typeof src === "undefined" || src === null) {
61000
- return throwError(new Error("marked(): input parameter is undefined or null"));
61001
- }
61002
- if (typeof src !== "string") {
61003
- return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected"));
61004
- }
61005
- if (opt.hooks) {
61006
- opt.hooks.options = opt;
61007
- opt.hooks.block = blockType;
61008
- }
61009
- const lexer2 = opt.hooks ? opt.hooks.provideLexer() : blockType ? _Lexer.lex : _Lexer.lexInline;
61010
- const parser2 = opt.hooks ? opt.hooks.provideParser() : blockType ? _Parser.parse : _Parser.parseInline;
61011
- if (opt.async) {
61012
- return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer2(src2, opt)).then((tokens) => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser2(tokens, opt)).then((html2) => opt.hooks ? opt.hooks.postprocess(html2) : html2).catch(throwError);
61175
+ /**
61176
+ * Parse Inline Tokens
61177
+ */
61178
+ parseInline(tokens, renderer2 = this.renderer) {
61179
+ let out = "";
61180
+ for (let i = 0; i < tokens.length; i++) {
61181
+ const anyToken = tokens[i];
61182
+ if (this.options.extensions?.renderers?.[anyToken.type]) {
61183
+ const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken);
61184
+ if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(anyToken.type)) {
61185
+ out += ret || "";
61186
+ continue;
61187
+ }
61013
61188
  }
61014
- try {
61015
- if (opt.hooks) {
61016
- src = opt.hooks.preprocess(src);
61189
+ const token = anyToken;
61190
+ switch (token.type) {
61191
+ case "escape": {
61192
+ out += renderer2.text(token);
61193
+ break;
61017
61194
  }
61018
- let tokens = lexer2(src, opt);
61019
- if (opt.hooks) {
61020
- tokens = opt.hooks.processAllTokens(tokens);
61195
+ case "html": {
61196
+ out += renderer2.html(token);
61197
+ break;
61021
61198
  }
61022
- if (opt.walkTokens) {
61023
- this.walkTokens(tokens, opt.walkTokens);
61199
+ case "link": {
61200
+ out += renderer2.link(token);
61201
+ break;
61024
61202
  }
61025
- let html2 = parser2(tokens, opt);
61026
- if (opt.hooks) {
61027
- html2 = opt.hooks.postprocess(html2);
61203
+ case "image": {
61204
+ out += renderer2.image(token);
61205
+ break;
61028
61206
  }
61029
- return html2;
61030
- } catch (e) {
61031
- return throwError(e);
61032
- }
61033
- };
61034
- return parse2;
61035
- }
61036
- onError(silent, async) {
61037
- return (e) => {
61038
- e.message += "\nPlease report this to https://github.com/markedjs/marked.";
61039
- if (silent) {
61040
- const msg = "<p>An error occurred:</p><pre>" + escape22(e.message + "", true) + "</pre>";
61041
- if (async) {
61042
- return Promise.resolve(msg);
61207
+ case "strong": {
61208
+ out += renderer2.strong(token);
61209
+ break;
61210
+ }
61211
+ case "em": {
61212
+ out += renderer2.em(token);
61213
+ break;
61214
+ }
61215
+ case "codespan": {
61216
+ out += renderer2.codespan(token);
61217
+ break;
61218
+ }
61219
+ case "br": {
61220
+ out += renderer2.br(token);
61221
+ break;
61222
+ }
61223
+ case "del": {
61224
+ out += renderer2.del(token);
61225
+ break;
61226
+ }
61227
+ case "text": {
61228
+ out += renderer2.text(token);
61229
+ break;
61230
+ }
61231
+ default: {
61232
+ const errMsg = 'Token with "' + token.type + '" type was not found.';
61233
+ if (this.options.silent) {
61234
+ console.error(errMsg);
61235
+ return "";
61236
+ } else {
61237
+ throw new Error(errMsg);
61238
+ }
61043
61239
  }
61044
- return msg;
61045
- }
61046
- if (async) {
61047
- return Promise.reject(e);
61048
61240
  }
61049
- throw e;
61050
- };
61241
+ }
61242
+ return out;
61051
61243
  }
61052
61244
  };
61053
- markedInstance = new Marked();
61054
- marked.options = marked.setOptions = function(options2) {
61055
- markedInstance.setOptions(options2);
61056
- marked.defaults = markedInstance.defaults;
61057
- changeDefaults(marked.defaults);
61058
- return marked;
61059
- };
61060
- marked.getDefaults = _getDefaults;
61061
- marked.defaults = _defaults;
61062
- marked.use = function(...args) {
61063
- markedInstance.use(...args);
61064
- marked.defaults = markedInstance.defaults;
61065
- changeDefaults(marked.defaults);
61066
- return marked;
61067
- };
61068
- marked.walkTokens = function(tokens, callback) {
61069
- return markedInstance.walkTokens(tokens, callback);
61070
- };
61071
- marked.parseInline = markedInstance.parseInline;
61072
- marked.Parser = _Parser;
61073
- marked.parser = _Parser.parse;
61074
- marked.Renderer = _Renderer;
61075
- marked.TextRenderer = _TextRenderer;
61076
- marked.Lexer = _Lexer;
61077
- marked.lexer = _Lexer.lex;
61078
- marked.Tokenizer = _Tokenizer;
61079
- marked.Hooks = _Hooks;
61080
- marked.parse = marked;
61081
- options = marked.options;
61082
- setOptions = marked.setOptions;
61083
- use = marked.use;
61084
- walkTokens = marked.walkTokens;
61085
- parseInline = marked.parseInline;
61086
- parser = _Parser.parse;
61087
- lexer = _Lexer.lex;
61088
- }
61089
- });
61090
-
61091
- // src/ui/components/markdown.tsx
61092
- function renderMarkdown(markdown, maxWidth = 120) {
61093
- const lexer2 = new _Lexer();
61094
- const tokens = lexer2.lex(markdown);
61095
- return renderTokens(tokens, maxWidth);
61096
- }
61097
- function renderTokens(tokens, maxWidth) {
61098
- const lines = [];
61099
- for (const token of tokens) {
61100
- switch (token.type) {
61101
- case "heading":
61102
- lines.push(renderHeading(token));
61103
- lines.push("");
61104
- break;
61105
- case "paragraph":
61106
- lines.push(renderInline(token.text));
61107
- lines.push("");
61108
- break;
61109
- case "code":
61110
- lines.push(...renderCodeBlock(token, maxWidth));
61111
- lines.push("");
61112
- break;
61113
- case "list":
61114
- lines.push(...renderList(token));
61115
- lines.push("");
61116
- break;
61117
- case "blockquote":
61118
- lines.push(...renderBlockquote(token));
61119
- lines.push("");
61120
- break;
61121
- case "table":
61122
- lines.push(...renderTable(token, maxWidth));
61123
- lines.push("");
61124
- break;
61125
- case "hr":
61126
- lines.push(`${FG_GRAY}${"\u2500".repeat(Math.min(maxWidth, 60))}${RESET}`);
61127
- lines.push("");
61128
- break;
61129
- case "space":
61130
- lines.push("");
61131
- break;
61132
- case "html":
61133
- lines.push(renderInline(token.text.replace(/<[^>]+>/g, "")));
61134
- break;
61135
- default:
61136
- if ("text" in token) {
61137
- lines.push(renderInline(String(token.text)));
61138
- }
61139
- break;
61140
- }
61141
- }
61142
- return lines.join("\n");
61143
- }
61144
- function renderHeading(token) {
61145
- const prefix = token.depth <= 2 ? `${BOLD}${FG_CYAN}` : `${BOLD}${FG_BLUE}`;
61146
- const marker = "#".repeat(token.depth);
61147
- return `${prefix}${marker} ${renderInline(token.text)}${RESET}`;
61148
- }
61149
- function renderCodeBlock(token, maxWidth) {
61150
- const lines = [];
61151
- const lang = token.lang ?? "";
61152
- if (lang) {
61153
- lines.push(`${FG_GRAY}\u250C\u2500 ${lang} ${"\u2500".repeat(Math.max(0, Math.min(maxWidth, 60) - lang.length - 4))}${RESET}`);
61154
- } else {
61155
- lines.push(`${FG_GRAY}\u250C${"\u2500".repeat(Math.min(maxWidth, 60) - 1)}${RESET}`);
61156
- }
61157
- for (const line of token.text.split("\n")) {
61158
- const highlighted = lang ? highlightSyntax(line, lang) : `${FG_GREEN}${line}${RESET}`;
61159
- lines.push(`${FG_GRAY}\u2502${RESET} ${highlighted}`);
61160
- }
61161
- lines.push(`${FG_GRAY}\u2514${"\u2500".repeat(Math.min(maxWidth, 60) - 1)}${RESET}`);
61162
- return lines;
61163
- }
61164
- function renderList(token) {
61165
- const lines = [];
61166
- const ordered = token.ordered;
61167
- for (let i = 0; i < token.items.length; i++) {
61168
- const item = token.items[i];
61169
- const marker = ordered ? `${FG_YELLOW}${i + 1}.${RESET}` : `${FG_YELLOW}\u2022${RESET}`;
61170
- const text = renderInline(item.text);
61171
- lines.push(` ${marker} ${text}`);
61172
- if (item.tokens) {
61173
- for (const subToken of item.tokens) {
61174
- if (subToken.type === "list") {
61175
- const subLines = renderList(subToken);
61176
- lines.push(...subLines.map((l) => ` ${l}`));
61177
- }
61245
+ _Hooks = class {
61246
+ options;
61247
+ block;
61248
+ constructor(options2) {
61249
+ this.options = options2 || _defaults;
61250
+ }
61251
+ static passThroughHooks = /* @__PURE__ */ new Set([
61252
+ "preprocess",
61253
+ "postprocess",
61254
+ "processAllTokens"
61255
+ ]);
61256
+ /**
61257
+ * Process markdown before marked
61258
+ */
61259
+ preprocess(markdown) {
61260
+ return markdown;
61261
+ }
61262
+ /**
61263
+ * Process HTML after marked is finished
61264
+ */
61265
+ postprocess(html2) {
61266
+ return html2;
61267
+ }
61268
+ /**
61269
+ * Process all tokens before walk tokens
61270
+ */
61271
+ processAllTokens(tokens) {
61272
+ return tokens;
61273
+ }
61274
+ /**
61275
+ * Provide function to tokenize markdown
61276
+ */
61277
+ provideLexer() {
61278
+ return this.block ? _Lexer.lex : _Lexer.lexInline;
61279
+ }
61280
+ /**
61281
+ * Provide function to parse tokens
61282
+ */
61283
+ provideParser() {
61284
+ return this.block ? _Parser.parse : _Parser.parseInline;
61178
61285
  }
61179
- }
61180
- }
61181
- return lines;
61182
- }
61183
- function renderBlockquote(token) {
61184
- const inner = renderTokens(token.tokens, 100);
61185
- return inner.split("\n").map((line) => `${FG_GRAY}\u2502${RESET} ${DIM}${line}${RESET}`);
61186
- }
61187
- function renderTable(token, maxWidth) {
61188
- const lines = [];
61189
- const colWidths = token.header.map((h) => h.text.length);
61190
- for (const row of token.rows) {
61191
- for (let i = 0; i < row.length; i++) {
61192
- colWidths[i] = Math.max(colWidths[i] ?? 0, row[i].text.length);
61193
- }
61194
- }
61195
- const totalWidth = colWidths.reduce((a, b) => a + b, 0) + colWidths.length * 3 + 1;
61196
- if (totalWidth > maxWidth) {
61197
- const scale = maxWidth / totalWidth;
61198
- for (let i = 0; i < colWidths.length; i++) {
61199
- colWidths[i] = Math.max(3, Math.floor(colWidths[i] * scale));
61200
- }
61201
- }
61202
- const headerLine = token.header.map((h, i) => pad(h.text, colWidths[i])).join(` ${FG_GRAY}\u2502${RESET} `);
61203
- lines.push(`${BOLD}${headerLine}${RESET}`);
61204
- const sepLine = colWidths.map((w) => "\u2500".repeat(w)).join(`\u2500\u253C\u2500`);
61205
- lines.push(`${FG_GRAY}${sepLine}${RESET}`);
61206
- for (const row of token.rows) {
61207
- const rowLine = row.map((cell, i) => pad(cell.text, colWidths[i])).join(` ${FG_GRAY}\u2502${RESET} `);
61208
- lines.push(rowLine);
61209
- }
61210
- return lines;
61211
- }
61212
- function renderInline(text) {
61213
- return text.replace(/\*\*(.+?)\*\*/g, `${BOLD}$1${RESET}`).replace(/__(.+?)__/g, `${BOLD}$1${RESET}`).replace(/\*(.+?)\*/g, `${ITALIC}$1${RESET}`).replace(/_(.+?)_/g, `${ITALIC}$1${RESET}`).replace(/~~(.+?)~~/g, `${STRIKETHROUGH}$1${RESET}`).replace(/`([^`]+)`/g, `${BG_GRAY}${FG_GREEN} $1 ${RESET}`).replace(/\[([^\]]+)\]\(([^)]+)\)/g, `${UNDERLINE}${FG_BLUE}$1${RESET}${FG_GRAY} ($2)${RESET}`).replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"');
61214
- }
61215
- function highlightSyntax(line, lang) {
61216
- const keywords = {
61217
- typescript: ["import", "export", "from", "const", "let", "var", "function", "class", "interface", "type", "return", "if", "else", "for", "while", "async", "await", "new", "this", "extends", "implements"],
61218
- javascript: ["import", "export", "from", "const", "let", "var", "function", "class", "return", "if", "else", "for", "while", "async", "await", "new", "this"],
61219
- python: ["import", "from", "def", "class", "return", "if", "elif", "else", "for", "while", "with", "as", "try", "except", "finally", "raise", "yield", "async", "await", "self"],
61220
- rust: ["fn", "let", "mut", "pub", "struct", "enum", "impl", "trait", "use", "mod", "return", "if", "else", "for", "while", "match", "self", "super", "crate"],
61221
- go: ["func", "var", "const", "type", "struct", "interface", "return", "if", "else", "for", "range", "switch", "case", "package", "import", "defer", "go", "chan"]
61222
- };
61223
- const ts = keywords.typescript ?? [];
61224
- const kw = keywords[lang] ?? keywords[lang.replace(/x$/, "")] ?? ts;
61225
- let result = line;
61226
- result = result.replace(/(\/\/.*$)/gm, `${FG_GRAY}$1${RESET}`);
61227
- result = result.replace(/(#.*$)/gm, `${FG_GRAY}$1${RESET}`);
61228
- result = result.replace(/("[^"]*")/g, `${FG_GREEN}$1${RESET}`);
61229
- result = result.replace(/('[^']*')/g, `${FG_GREEN}$1${RESET}`);
61230
- result = result.replace(/(`[^`]*`)/g, `${FG_GREEN}$1${RESET}`);
61231
- for (const kwd of kw) {
61232
- result = result.replace(
61233
- new RegExp(`\\b(${kwd})\\b`, "g"),
61234
- `${FG_MAGENTA}$1${RESET}`
61235
- );
61236
- }
61237
- result = result.replace(/\b(\d+\.?\d*)\b/g, `${FG_YELLOW}$1${RESET}`);
61238
- return result;
61239
- }
61240
- function pad(text, width) {
61241
- if (text.length >= width) return text.slice(0, width);
61242
- return text + " ".repeat(width - text.length);
61243
- }
61244
- var ESC2, RESET, BOLD, DIM, ITALIC, UNDERLINE, STRIKETHROUGH, FG_CYAN, FG_YELLOW, FG_GREEN, FG_BLUE, FG_MAGENTA, FG_GRAY, BG_GRAY;
61245
- var init_markdown = __esm({
61246
- "src/ui/components/markdown.tsx"() {
61247
- "use strict";
61248
- init_marked_esm();
61249
- ESC2 = "\x1B[";
61250
- RESET = `${ESC2}0m`;
61251
- BOLD = `${ESC2}1m`;
61252
- DIM = `${ESC2}2m`;
61253
- ITALIC = `${ESC2}3m`;
61254
- UNDERLINE = `${ESC2}4m`;
61255
- STRIKETHROUGH = `${ESC2}9m`;
61256
- FG_CYAN = `${ESC2}36m`;
61257
- FG_YELLOW = `${ESC2}33m`;
61258
- FG_GREEN = `${ESC2}32m`;
61259
- FG_BLUE = `${ESC2}34m`;
61260
- FG_MAGENTA = `${ESC2}35m`;
61261
- FG_GRAY = `${ESC2}90m`;
61262
- BG_GRAY = `${ESC2}100m`;
61263
- }
61264
- });
61265
-
61266
- // src/api/index.ts
61267
- var init_api = __esm({
61268
- "src/api/index.ts"() {
61269
- "use strict";
61270
- init_client();
61271
- init_models();
61272
- init_streaming();
61273
- }
61274
- });
61275
-
61276
- // src/core/errors.ts
61277
- function errorToString(err) {
61278
- if (err instanceof Error) return err.message;
61279
- if (typeof err === "string") return err;
61280
- return String(err);
61281
- }
61282
- var init_errors2 = __esm({
61283
- "src/core/errors.ts"() {
61284
- "use strict";
61285
- }
61286
- });
61287
-
61288
- // src/core/agent-loop.ts
61289
- async function runAgentLoop(initialMessages, options2) {
61290
- const client = options2.client ?? getApiClient();
61291
- const messages = [...initialMessages];
61292
- const maxTurns = options2.maxTurns ?? DEFAULT_MAX_TURNS;
61293
- let totalInputTokens = 0;
61294
- let totalOutputTokens = 0;
61295
- let turnIndex = 0;
61296
- let aborted = false;
61297
- const toolDefs = buildToolDefinitions(options2.tools);
61298
- const toolMap = new Map(options2.tools.map((t) => [t.name, t]));
61299
- while (turnIndex < maxTurns) {
61300
- if (options2.signal?.aborted) {
61301
- aborted = true;
61302
- break;
61303
- }
61304
- options2.onProgress?.({ type: "turn_start", turnIndex });
61305
- const request = {
61306
- model: options2.model,
61307
- messages,
61308
- systemPrompt: options2.systemPrompt,
61309
- tools: toolDefs.length > 0 ? toolDefs : void 0,
61310
- thinkingConfig: options2.thinkingConfig,
61311
- maxTokens: options2.maxTokens,
61312
- stream: true,
61313
- signal: options2.signal,
61314
- querySource: options2.querySource
61315
61286
  };
61316
- options2.onProgress?.({ type: "streaming", turnIndex });
61317
- const contentBlocks = [];
61318
- let stopReason = null;
61319
- try {
61320
- for await (const item of client.streamMessage(request)) {
61321
- if (options2.signal?.aborted) {
61322
- aborted = true;
61323
- break;
61287
+ Marked = class {
61288
+ defaults = _getDefaults();
61289
+ options = this.setOptions;
61290
+ parse = this.parseMarkdown(true);
61291
+ parseInline = this.parseMarkdown(false);
61292
+ Parser = _Parser;
61293
+ Renderer = _Renderer;
61294
+ TextRenderer = _TextRenderer;
61295
+ Lexer = _Lexer;
61296
+ Tokenizer = _Tokenizer;
61297
+ Hooks = _Hooks;
61298
+ constructor(...args) {
61299
+ this.use(...args);
61300
+ }
61301
+ /**
61302
+ * Run callback for every token
61303
+ */
61304
+ walkTokens(tokens, callback) {
61305
+ let values = [];
61306
+ for (const token of tokens) {
61307
+ values = values.concat(callback.call(this, token));
61308
+ switch (token.type) {
61309
+ case "table": {
61310
+ const tableToken = token;
61311
+ for (const cell of tableToken.header) {
61312
+ values = values.concat(this.walkTokens(cell.tokens, callback));
61313
+ }
61314
+ for (const row of tableToken.rows) {
61315
+ for (const cell of row) {
61316
+ values = values.concat(this.walkTokens(cell.tokens, callback));
61317
+ }
61318
+ }
61319
+ break;
61320
+ }
61321
+ case "list": {
61322
+ const listToken = token;
61323
+ values = values.concat(this.walkTokens(listToken.items, callback));
61324
+ break;
61325
+ }
61326
+ default: {
61327
+ const genericToken = token;
61328
+ if (this.defaults.extensions?.childTokens?.[genericToken.type]) {
61329
+ this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
61330
+ const tokens2 = genericToken[childTokens].flat(Infinity);
61331
+ values = values.concat(this.walkTokens(tokens2, callback));
61332
+ });
61333
+ } else if (genericToken.tokens) {
61334
+ values = values.concat(this.walkTokens(genericToken.tokens, callback));
61335
+ }
61336
+ }
61337
+ }
61324
61338
  }
61325
- const { event, accumulated } = item;
61326
- if (event.type === "content_block_delta" && event.delta) {
61327
- if (event.delta.type === "text_delta") {
61328
- options2.onTextDelta?.(event.delta.text);
61329
- } else if (event.delta.type === "thinking_delta") {
61330
- options2.onThinkingDelta?.(event.delta.thinking);
61339
+ return values;
61340
+ }
61341
+ use(...args) {
61342
+ const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
61343
+ args.forEach((pack) => {
61344
+ const opts = { ...pack };
61345
+ opts.async = this.defaults.async || opts.async || false;
61346
+ if (pack.extensions) {
61347
+ pack.extensions.forEach((ext) => {
61348
+ if (!ext.name) {
61349
+ throw new Error("extension name required");
61350
+ }
61351
+ if ("renderer" in ext) {
61352
+ const prevRenderer = extensions.renderers[ext.name];
61353
+ if (prevRenderer) {
61354
+ extensions.renderers[ext.name] = function(...args2) {
61355
+ let ret = ext.renderer.apply(this, args2);
61356
+ if (ret === false) {
61357
+ ret = prevRenderer.apply(this, args2);
61358
+ }
61359
+ return ret;
61360
+ };
61361
+ } else {
61362
+ extensions.renderers[ext.name] = ext.renderer;
61363
+ }
61364
+ }
61365
+ if ("tokenizer" in ext) {
61366
+ if (!ext.level || ext.level !== "block" && ext.level !== "inline") {
61367
+ throw new Error("extension level must be 'block' or 'inline'");
61368
+ }
61369
+ const extLevel = extensions[ext.level];
61370
+ if (extLevel) {
61371
+ extLevel.unshift(ext.tokenizer);
61372
+ } else {
61373
+ extensions[ext.level] = [ext.tokenizer];
61374
+ }
61375
+ if (ext.start) {
61376
+ if (ext.level === "block") {
61377
+ if (extensions.startBlock) {
61378
+ extensions.startBlock.push(ext.start);
61379
+ } else {
61380
+ extensions.startBlock = [ext.start];
61381
+ }
61382
+ } else if (ext.level === "inline") {
61383
+ if (extensions.startInline) {
61384
+ extensions.startInline.push(ext.start);
61385
+ } else {
61386
+ extensions.startInline = [ext.start];
61387
+ }
61388
+ }
61389
+ }
61390
+ }
61391
+ if ("childTokens" in ext && ext.childTokens) {
61392
+ extensions.childTokens[ext.name] = ext.childTokens;
61393
+ }
61394
+ });
61395
+ opts.extensions = extensions;
61396
+ }
61397
+ if (pack.renderer) {
61398
+ const renderer2 = this.defaults.renderer || new _Renderer(this.defaults);
61399
+ for (const prop in pack.renderer) {
61400
+ if (!(prop in renderer2)) {
61401
+ throw new Error(`renderer '${prop}' does not exist`);
61402
+ }
61403
+ if (["options", "parser"].includes(prop)) {
61404
+ continue;
61405
+ }
61406
+ const rendererProp = prop;
61407
+ const rendererFunc = pack.renderer[rendererProp];
61408
+ const prevRenderer = renderer2[rendererProp];
61409
+ renderer2[rendererProp] = (...args2) => {
61410
+ let ret = rendererFunc.apply(renderer2, args2);
61411
+ if (ret === false) {
61412
+ ret = prevRenderer.apply(renderer2, args2);
61413
+ }
61414
+ return ret || "";
61415
+ };
61416
+ }
61417
+ opts.renderer = renderer2;
61418
+ }
61419
+ if (pack.tokenizer) {
61420
+ const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
61421
+ for (const prop in pack.tokenizer) {
61422
+ if (!(prop in tokenizer)) {
61423
+ throw new Error(`tokenizer '${prop}' does not exist`);
61424
+ }
61425
+ if (["options", "rules", "lexer"].includes(prop)) {
61426
+ continue;
61427
+ }
61428
+ const tokenizerProp = prop;
61429
+ const tokenizerFunc = pack.tokenizer[tokenizerProp];
61430
+ const prevTokenizer = tokenizer[tokenizerProp];
61431
+ tokenizer[tokenizerProp] = (...args2) => {
61432
+ let ret = tokenizerFunc.apply(tokenizer, args2);
61433
+ if (ret === false) {
61434
+ ret = prevTokenizer.apply(tokenizer, args2);
61435
+ }
61436
+ return ret;
61437
+ };
61438
+ }
61439
+ opts.tokenizer = tokenizer;
61440
+ }
61441
+ if (pack.hooks) {
61442
+ const hooks = this.defaults.hooks || new _Hooks();
61443
+ for (const prop in pack.hooks) {
61444
+ if (!(prop in hooks)) {
61445
+ throw new Error(`hook '${prop}' does not exist`);
61446
+ }
61447
+ if (["options", "block"].includes(prop)) {
61448
+ continue;
61449
+ }
61450
+ const hooksProp = prop;
61451
+ const hooksFunc = pack.hooks[hooksProp];
61452
+ const prevHook = hooks[hooksProp];
61453
+ if (_Hooks.passThroughHooks.has(prop)) {
61454
+ hooks[hooksProp] = (arg) => {
61455
+ if (this.defaults.async) {
61456
+ return Promise.resolve(hooksFunc.call(hooks, arg)).then((ret2) => {
61457
+ return prevHook.call(hooks, ret2);
61458
+ });
61459
+ }
61460
+ const ret = hooksFunc.call(hooks, arg);
61461
+ return prevHook.call(hooks, ret);
61462
+ };
61463
+ } else {
61464
+ hooks[hooksProp] = (...args2) => {
61465
+ let ret = hooksFunc.apply(hooks, args2);
61466
+ if (ret === false) {
61467
+ ret = prevHook.apply(hooks, args2);
61468
+ }
61469
+ return ret;
61470
+ };
61471
+ }
61472
+ }
61473
+ opts.hooks = hooks;
61474
+ }
61475
+ if (pack.walkTokens) {
61476
+ const walkTokens2 = this.defaults.walkTokens;
61477
+ const packWalktokens = pack.walkTokens;
61478
+ opts.walkTokens = function(token) {
61479
+ let values = [];
61480
+ values.push(packWalktokens.call(this, token));
61481
+ if (walkTokens2) {
61482
+ values = values.concat(walkTokens2.call(this, token));
61483
+ }
61484
+ return values;
61485
+ };
61486
+ }
61487
+ this.defaults = { ...this.defaults, ...opts };
61488
+ });
61489
+ return this;
61490
+ }
61491
+ setOptions(opt) {
61492
+ this.defaults = { ...this.defaults, ...opt };
61493
+ return this;
61494
+ }
61495
+ lexer(src, options2) {
61496
+ return _Lexer.lex(src, options2 ?? this.defaults);
61497
+ }
61498
+ parser(tokens, options2) {
61499
+ return _Parser.parse(tokens, options2 ?? this.defaults);
61500
+ }
61501
+ parseMarkdown(blockType) {
61502
+ const parse2 = (src, options2) => {
61503
+ const origOpt = { ...options2 };
61504
+ const opt = { ...this.defaults, ...origOpt };
61505
+ const throwError = this.onError(!!opt.silent, !!opt.async);
61506
+ if (this.defaults.async === true && origOpt.async === false) {
61507
+ return throwError(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
61331
61508
  }
61332
- }
61333
- if (event.type === "message_stop" || event.type === "message_delta") {
61334
- if (accumulated.content) {
61335
- contentBlocks.length = 0;
61336
- contentBlocks.push(...accumulated.content);
61509
+ if (typeof src === "undefined" || src === null) {
61510
+ return throwError(new Error("marked(): input parameter is undefined or null"));
61337
61511
  }
61338
- stopReason = accumulated.stopReason ?? null;
61339
- if (accumulated.usage) {
61340
- totalInputTokens += accumulated.usage.inputTokens;
61341
- totalOutputTokens += accumulated.usage.outputTokens;
61512
+ if (typeof src !== "string") {
61513
+ return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected"));
61342
61514
  }
61343
- }
61515
+ if (opt.hooks) {
61516
+ opt.hooks.options = opt;
61517
+ opt.hooks.block = blockType;
61518
+ }
61519
+ const lexer2 = opt.hooks ? opt.hooks.provideLexer() : blockType ? _Lexer.lex : _Lexer.lexInline;
61520
+ const parser2 = opt.hooks ? opt.hooks.provideParser() : blockType ? _Parser.parse : _Parser.parseInline;
61521
+ if (opt.async) {
61522
+ return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer2(src2, opt)).then((tokens) => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser2(tokens, opt)).then((html2) => opt.hooks ? opt.hooks.postprocess(html2) : html2).catch(throwError);
61523
+ }
61524
+ try {
61525
+ if (opt.hooks) {
61526
+ src = opt.hooks.preprocess(src);
61527
+ }
61528
+ let tokens = lexer2(src, opt);
61529
+ if (opt.hooks) {
61530
+ tokens = opt.hooks.processAllTokens(tokens);
61531
+ }
61532
+ if (opt.walkTokens) {
61533
+ this.walkTokens(tokens, opt.walkTokens);
61534
+ }
61535
+ let html2 = parser2(tokens, opt);
61536
+ if (opt.hooks) {
61537
+ html2 = opt.hooks.postprocess(html2);
61538
+ }
61539
+ return html2;
61540
+ } catch (e) {
61541
+ return throwError(e);
61542
+ }
61543
+ };
61544
+ return parse2;
61344
61545
  }
61345
- } catch (error) {
61346
- if (error.name === "AbortError") {
61347
- aborted = true;
61348
- break;
61546
+ onError(silent, async) {
61547
+ return (e) => {
61548
+ e.message += "\nPlease report this to https://github.com/markedjs/marked.";
61549
+ if (silent) {
61550
+ const msg = "<p>An error occurred:</p><pre>" + escape22(e.message + "", true) + "</pre>";
61551
+ if (async) {
61552
+ return Promise.resolve(msg);
61553
+ }
61554
+ return msg;
61555
+ }
61556
+ if (async) {
61557
+ return Promise.reject(e);
61558
+ }
61559
+ throw e;
61560
+ };
61349
61561
  }
61350
- throw error;
61351
- }
61352
- if (aborted) break;
61353
- const assistantMessage = {
61354
- role: "assistant",
61355
- content: contentBlocks
61356
61562
  };
61357
- messages.push(assistantMessage);
61358
- const toolUseBlocks = contentBlocks.filter(
61359
- (b) => b.type === "tool_use"
61360
- );
61361
- if (toolUseBlocks.length === 0 || stopReason === "end_turn") {
61362
- options2.onTurnComplete?.(turnIndex, assistantMessage);
61363
- options2.onProgress?.({ type: "turn_end", turnIndex, stopReason });
61364
- turnIndex++;
61365
- break;
61366
- }
61367
- const toolResults = await executeTools(
61368
- toolUseBlocks,
61369
- toolMap,
61370
- options2
61371
- );
61372
- const toolResultMessage = {
61373
- role: "user",
61374
- content: toolResults.map((r) => ({
61375
- type: "tool_result",
61376
- tool_use_id: r.toolUseId,
61377
- content: r.error ?? (typeof r.data === "string" ? r.data : JSON.stringify(r.data)),
61378
- is_error: r.isError
61379
- }))
61563
+ markedInstance = new Marked();
61564
+ marked.options = marked.setOptions = function(options2) {
61565
+ markedInstance.setOptions(options2);
61566
+ marked.defaults = markedInstance.defaults;
61567
+ changeDefaults(marked.defaults);
61568
+ return marked;
61380
61569
  };
61381
- messages.push(toolResultMessage);
61382
- options2.onTurnComplete?.(turnIndex, assistantMessage);
61383
- options2.onProgress?.({ type: "turn_end", turnIndex, stopReason });
61384
- turnIndex++;
61385
- }
61386
- options2.onProgress?.({ type: "loop_end", totalTurns: turnIndex });
61387
- return {
61388
- messages,
61389
- totalTurns: turnIndex,
61390
- aborted,
61391
- usage: { totalInputTokens, totalOutputTokens }
61392
- };
61393
- }
61394
- async function executeTools(toolUseBlocks, toolMap, options2) {
61395
- const results = [];
61396
- const concurrentTools = [];
61397
- const sequentialTools = [];
61398
- for (const block2 of toolUseBlocks) {
61399
- const handler = toolMap.get(block2.name);
61400
- if (!handler) {
61401
- results.push({
61402
- toolUseId: block2.id,
61403
- toolName: block2.name,
61404
- error: `Unknown tool: ${block2.name}`,
61405
- isError: true
61406
- });
61407
- continue;
61408
- }
61409
- if (handler.isConcurrencySafe) {
61410
- concurrentTools.push({ block: block2, handler });
61411
- } else {
61412
- sequentialTools.push({ block: block2, handler });
61413
- }
61414
- }
61415
- if (concurrentTools.length > 0) {
61416
- const concurrentResults = await Promise.all(
61417
- concurrentTools.map(
61418
- ({ block: block2, handler }) => executeSingleTool(block2, handler, options2)
61419
- )
61420
- );
61421
- results.push(...concurrentResults);
61422
- }
61423
- for (const { block: block2, handler } of sequentialTools) {
61424
- if (options2.signal?.aborted) break;
61425
- const result = await executeSingleTool(block2, handler, options2);
61426
- results.push(result);
61427
- }
61428
- return results;
61429
- }
61430
- async function executeSingleTool(block2, handler, options2) {
61431
- const { id: toolUseId, name: toolName, input } = block2;
61432
- options2.onProgress?.({ type: "tool_execution", toolName, toolUseId });
61433
- const parseFailed = block2._inputParseFailed;
61434
- if (parseFailed) {
61435
- const rawJson = block2._rawInputJson;
61436
- const error = `Tool input not fully received \u2014 JSON parsing failed for ${toolName}. Partial input (${rawJson?.length ?? 0} chars) could not be parsed. This is a streaming issue; retrying the request should resolve it.`;
61437
- options2.onToolUseRejected?.(toolName, toolUseId, error);
61438
- return { toolUseId, toolName, error, isError: true };
61439
- }
61440
- if (input && Object.keys(input).length === 0 && handler.inputSchema && Array.isArray(handler.inputSchema.required) && (handler.inputSchema.required ?? []).length > 0) {
61441
- const error = `Tool input not fully received \u2014 ${toolName} requires parameters (${(handler.inputSchema.required ?? []).join(", ")}) but received empty input {}. Skipping execution to prevent undefined behavior.`;
61442
- options2.onToolUseRejected?.(toolName, toolUseId, error);
61443
- return { toolUseId, toolName, error, isError: true };
61444
- }
61445
- options2.onToolUseStart?.(toolName, toolUseId, input);
61446
- try {
61447
- if (options2.onPermissionCheck) {
61448
- const permResult = await options2.onPermissionCheck(toolName, input);
61449
- if (permResult.behavior === "deny") {
61450
- const reason = permResult.message ?? "Permission denied";
61451
- options2.onToolUseRejected?.(toolName, toolUseId, reason);
61452
- return { toolUseId, toolName, error: reason, isError: true };
61453
- }
61454
- }
61455
- if (handler.validateInput) {
61456
- const validation = await handler.validateInput(input);
61457
- if (!validation.result) {
61458
- const error = validation.message ?? "Invalid input";
61459
- return { toolUseId, toolName, error, isError: true };
61460
- }
61461
- }
61462
- const result = await handler.call(input, {
61463
- abortSignal: options2.signal,
61464
- agentId: options2.agentId,
61465
- toolUseId
61466
- });
61467
- options2.onToolUseEnd?.(toolName, toolUseId, result);
61468
- if (result.isError || result.error) {
61469
- return { toolUseId, toolName, error: result.error, isError: true };
61470
- }
61471
- return { toolUseId, toolName, data: result.data };
61472
- } catch (error) {
61473
- const errorMsg = errorToString(error);
61474
- options2.onToolUseEnd?.(toolName, toolUseId, { error: errorMsg, isError: true });
61475
- return { toolUseId, toolName, error: errorMsg, isError: true };
61476
- }
61477
- }
61478
- function buildToolDefinitions(tools) {
61479
- return tools.map((t) => ({
61480
- name: t.name,
61481
- description: t.description,
61482
- input_schema: t.inputSchema
61483
- }));
61484
- }
61485
- var DEFAULT_MAX_TURNS;
61486
- var init_agent_loop = __esm({
61487
- "src/core/agent-loop.ts"() {
61488
- "use strict";
61489
- init_api();
61490
- init_errors2();
61491
- DEFAULT_MAX_TURNS = 100;
61492
- }
61493
- });
61494
-
61495
- // src/config/permissions.ts
61496
- function createDefaultPermissionContext(settings) {
61497
- const defaultMode = settings?.permissions?.defaultMode ?? "default";
61498
- return {
61499
- mode: defaultMode,
61500
- allowRules: settings?.permissions?.allow ?? [],
61501
- denyRules: settings?.permissions?.deny ?? []
61502
- };
61503
- }
61504
- var init_permissions = __esm({
61505
- "src/config/permissions.ts"() {
61506
- "use strict";
61570
+ marked.getDefaults = _getDefaults;
61571
+ marked.defaults = _defaults;
61572
+ marked.use = function(...args) {
61573
+ markedInstance.use(...args);
61574
+ marked.defaults = markedInstance.defaults;
61575
+ changeDefaults(marked.defaults);
61576
+ return marked;
61577
+ };
61578
+ marked.walkTokens = function(tokens, callback) {
61579
+ return markedInstance.walkTokens(tokens, callback);
61580
+ };
61581
+ marked.parseInline = markedInstance.parseInline;
61582
+ marked.Parser = _Parser;
61583
+ marked.parser = _Parser.parse;
61584
+ marked.Renderer = _Renderer;
61585
+ marked.TextRenderer = _TextRenderer;
61586
+ marked.Lexer = _Lexer;
61587
+ marked.lexer = _Lexer.lex;
61588
+ marked.Tokenizer = _Tokenizer;
61589
+ marked.Hooks = _Hooks;
61590
+ marked.parse = marked;
61591
+ options = marked.options;
61592
+ setOptions = marked.setOptions;
61593
+ use = marked.use;
61594
+ walkTokens = marked.walkTokens;
61595
+ parseInline = marked.parseInline;
61596
+ parser = _Parser.parse;
61597
+ lexer = _Lexer.lex;
61507
61598
  }
61508
61599
  });
61509
61600
 
61510
- // src/db/index.ts
61511
- import { join as join2 } from "path";
61512
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
61513
- function getDbPath() {
61514
- const dir = getConfigDir();
61515
- if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
61516
- return join2(dir, "coders.db");
61601
+ // src/ui/components/markdown.tsx
61602
+ function renderMarkdown(markdown, maxWidth = 120) {
61603
+ const lexer2 = new _Lexer();
61604
+ const tokens = lexer2.lex(markdown);
61605
+ return renderTokens(tokens, maxWidth);
61517
61606
  }
61518
- function getDb() {
61519
- if (_db) return _db;
61520
- const dbPath = getDbPath();
61521
- try {
61522
- const { Database } = __require("bun:sqlite");
61523
- _db = new Database(dbPath);
61524
- } catch {
61525
- try {
61526
- const BetterSqlite3 = __require("better-sqlite3");
61527
- _db = new BetterSqlite3(dbPath);
61528
- } catch {
61529
- _db = createJsonFileDb();
61530
- initSchema(_db);
61531
- return _db;
61607
+ function renderTokens(tokens, maxWidth) {
61608
+ const lines = [];
61609
+ for (const token of tokens) {
61610
+ switch (token.type) {
61611
+ case "heading":
61612
+ lines.push(renderHeading(token));
61613
+ lines.push("");
61614
+ break;
61615
+ case "paragraph":
61616
+ lines.push(renderInline(token.text));
61617
+ lines.push("");
61618
+ break;
61619
+ case "code":
61620
+ lines.push(...renderCodeBlock(token, maxWidth));
61621
+ lines.push("");
61622
+ break;
61623
+ case "list":
61624
+ lines.push(...renderList(token));
61625
+ lines.push("");
61626
+ break;
61627
+ case "blockquote":
61628
+ lines.push(...renderBlockquote(token));
61629
+ lines.push("");
61630
+ break;
61631
+ case "table":
61632
+ lines.push(...renderTable(token, maxWidth));
61633
+ lines.push("");
61634
+ break;
61635
+ case "hr":
61636
+ lines.push(`${FG_GRAY}${"\u2500".repeat(Math.min(maxWidth, 60))}${FG_DEFAULT}`);
61637
+ lines.push("");
61638
+ break;
61639
+ case "space":
61640
+ lines.push("");
61641
+ break;
61642
+ case "html":
61643
+ lines.push(renderInline(token.text.replace(/<[^>]+>/g, "")));
61644
+ break;
61645
+ default:
61646
+ if ("text" in token) {
61647
+ lines.push(renderInline(String(token.text)));
61648
+ }
61649
+ break;
61532
61650
  }
61533
61651
  }
61534
- try {
61535
- _db.exec("PRAGMA journal_mode=WAL");
61536
- } catch {
61652
+ return lines.join("\n");
61653
+ }
61654
+ function renderHeading(token) {
61655
+ const color = token.depth <= 2 ? FG_CYAN : FG_BLUE;
61656
+ const prefix = `${BOLD}${color}`;
61657
+ const marker = "#".repeat(token.depth);
61658
+ const inner = renderInlineWithRestore(token.text, prefix);
61659
+ return `${prefix}${marker} ${inner}${RESET}`;
61660
+ }
61661
+ function renderCodeBlock(token, maxWidth) {
61662
+ const lines = [];
61663
+ const lang = token.lang ?? "";
61664
+ if (lang) {
61665
+ lines.push(`${FG_GRAY}\u250C\u2500 ${lang} ${"\u2500".repeat(Math.max(0, Math.min(maxWidth, 60) - lang.length - 4))}${FG_DEFAULT}`);
61666
+ } else {
61667
+ lines.push(`${FG_GRAY}\u250C${"\u2500".repeat(Math.min(maxWidth, 60) - 1)}${FG_DEFAULT}`);
61537
61668
  }
61538
- try {
61539
- _db.exec("PRAGMA foreign_keys=ON");
61540
- } catch {
61669
+ for (const line of token.text.split("\n")) {
61670
+ const highlighted = lang ? highlightSyntax(line, lang) : `${FG_GREEN}${line}${FG_DEFAULT}`;
61671
+ lines.push(`${FG_GRAY}\u2502${FG_DEFAULT} ${highlighted}`);
61541
61672
  }
61542
- initSchema(_db);
61543
- return _db;
61673
+ lines.push(`${FG_GRAY}\u2514${"\u2500".repeat(Math.min(maxWidth, 60) - 1)}${FG_DEFAULT}`);
61674
+ return lines;
61544
61675
  }
61545
- function initSchema(db) {
61546
- db.exec(`
61547
- -- Sessions
61548
- CREATE TABLE IF NOT EXISTS sessions (
61549
- id TEXT PRIMARY KEY,
61550
- device_id TEXT NOT NULL,
61551
- project_dir TEXT,
61552
- original_cwd TEXT,
61553
- model TEXT,
61554
- app_version TEXT,
61555
- build_time TEXT,
61556
- fingerprint TEXT, -- JSON
61557
- metadata TEXT, -- JSON
61558
- created_at TEXT DEFAULT (datetime('now')),
61559
- updated_at TEXT DEFAULT (datetime('now'))
61560
- );
61561
-
61562
- -- Messages (conversation history)
61563
- CREATE TABLE IF NOT EXISTS messages (
61564
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61565
- session_id TEXT NOT NULL REFERENCES sessions(id),
61566
- role TEXT NOT NULL CHECK(role IN ('user','assistant','system')),
61567
- content TEXT NOT NULL,
61568
- tool_uses TEXT, -- JSON array of tool use displays
61569
- thinking TEXT,
61570
- duration_ms REAL,
61571
- tokens_in INTEGER DEFAULT 0,
61572
- tokens_out INTEGER DEFAULT 0,
61573
- cost_usd REAL DEFAULT 0,
61574
- created_at TEXT DEFAULT (datetime('now'))
61575
- );
61576
- CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
61577
-
61578
- -- File history (tracks reads per session)
61579
- CREATE TABLE IF NOT EXISTS file_history (
61580
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61581
- session_id TEXT NOT NULL,
61582
- file_path TEXT NOT NULL,
61583
- content_hash TEXT,
61584
- byte_size INTEGER,
61585
- line_count INTEGER,
61586
- read_at TEXT DEFAULT (datetime('now')),
61587
- UNIQUE(session_id, file_path)
61588
- );
61589
-
61590
- -- File checkpoints (for /rewind)
61591
- CREATE TABLE IF NOT EXISTS checkpoints (
61592
- id TEXT PRIMARY KEY,
61593
- session_id TEXT NOT NULL,
61594
- file_path TEXT NOT NULL,
61595
- original_content TEXT NOT NULL,
61596
- edit_operation TEXT, -- JSON {old_string, new_string}
61597
- created_at TEXT DEFAULT (datetime('now'))
61598
- );
61599
- CREATE INDEX IF NOT EXISTS idx_checkpoints_session_file ON checkpoints(session_id, file_path);
61600
-
61601
- -- Tasks (replaces in-memory fallback for @hasna/todos)
61602
- CREATE TABLE IF NOT EXISTS tasks (
61603
- id TEXT PRIMARY KEY,
61604
- subject TEXT NOT NULL,
61605
- description TEXT DEFAULT '',
61606
- status TEXT DEFAULT 'pending' CHECK(status IN ('pending','in_progress','completed','failed','cancelled')),
61607
- active_form TEXT,
61608
- owner TEXT,
61609
- blocks TEXT DEFAULT '[]', -- JSON array of task IDs
61610
- blocked_by TEXT DEFAULT '[]', -- JSON array of task IDs
61611
- metadata TEXT DEFAULT '{}', -- JSON
61612
- created_at TEXT DEFAULT (datetime('now')),
61613
- updated_at TEXT DEFAULT (datetime('now'))
61614
- );
61615
-
61616
- -- Config (replaces JSON files)
61617
- CREATE TABLE IF NOT EXISTS config (
61618
- key TEXT PRIMARY KEY,
61619
- value TEXT, -- JSON
61620
- scope TEXT DEFAULT 'user' CHECK(scope IN ('user','project','local','global')),
61621
- updated_at TEXT DEFAULT (datetime('now'))
61622
- );
61623
-
61624
- -- Memories (replaces in-memory fallback for @hasna/mementos)
61625
- CREATE TABLE IF NOT EXISTS memories (
61626
- id TEXT PRIMARY KEY,
61627
- key TEXT UNIQUE NOT NULL,
61628
- value TEXT NOT NULL,
61629
- scope TEXT DEFAULT 'shared' CHECK(scope IN ('global','shared','private')),
61630
- category TEXT DEFAULT 'knowledge',
61631
- importance INTEGER DEFAULT 5 CHECK(importance BETWEEN 1 AND 10),
61632
- tags TEXT DEFAULT '[]', -- JSON array
61633
- version INTEGER DEFAULT 1,
61634
- created_at TEXT DEFAULT (datetime('now')),
61635
- updated_at TEXT DEFAULT (datetime('now'))
61636
- );
61637
-
61638
- -- Teams
61639
- CREATE TABLE IF NOT EXISTS teams (
61640
- name TEXT PRIMARY KEY,
61641
- description TEXT,
61642
- task_list_id TEXT,
61643
- created_at TEXT DEFAULT (datetime('now'))
61644
- );
61645
-
61646
- -- Team members
61647
- CREATE TABLE IF NOT EXISTS team_members (
61648
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61649
- team_name TEXT NOT NULL REFERENCES teams(name),
61650
- agent_name TEXT NOT NULL,
61651
- role TEXT,
61652
- status TEXT DEFAULT 'idle',
61653
- current_task TEXT,
61654
- UNIQUE(team_name, agent_name)
61655
- );
61656
-
61657
- -- Team messages
61658
- CREATE TABLE IF NOT EXISTS team_messages (
61659
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61660
- from_agent TEXT NOT NULL,
61661
- to_agent TEXT NOT NULL,
61662
- team_name TEXT,
61663
- content TEXT NOT NULL,
61664
- is_read INTEGER DEFAULT 0,
61665
- is_blocking INTEGER DEFAULT 0,
61666
- created_at TEXT DEFAULT (datetime('now'))
61667
- );
61668
- CREATE INDEX IF NOT EXISTS idx_team_msgs_to ON team_messages(to_agent, is_read);
61669
-
61670
- -- Permissions (persisted allow/deny rules)
61671
- CREATE TABLE IF NOT EXISTS permissions (
61672
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61673
- tool_name TEXT,
61674
- command_pattern TEXT,
61675
- path_pattern TEXT,
61676
- behavior TEXT NOT NULL CHECK(behavior IN ('allow','deny')),
61677
- scope TEXT DEFAULT 'session',
61678
- created_at TEXT DEFAULT (datetime('now'))
61679
- );
61680
-
61681
- -- MCP servers
61682
- CREATE TABLE IF NOT EXISTS mcp_servers (
61683
- name TEXT PRIMARY KEY,
61684
- command TEXT,
61685
- args TEXT, -- JSON array
61686
- env TEXT, -- JSON object
61687
- url TEXT,
61688
- transport TEXT DEFAULT 'stdio',
61689
- scope TEXT DEFAULT 'user',
61690
- enabled INTEGER DEFAULT 1,
61691
- created_at TEXT DEFAULT (datetime('now'))
61676
+ function renderList(token) {
61677
+ const lines = [];
61678
+ const ordered = token.ordered;
61679
+ for (let i = 0; i < token.items.length; i++) {
61680
+ const item = token.items[i];
61681
+ const marker = ordered ? `${FG_YELLOW}${i + 1}.${FG_DEFAULT}` : `${FG_YELLOW}\u2022${FG_DEFAULT}`;
61682
+ const text = renderInline(item.text);
61683
+ lines.push(` ${marker} ${text}`);
61684
+ if (item.tokens) {
61685
+ for (const subToken of item.tokens) {
61686
+ if (subToken.type === "list") {
61687
+ const subLines = renderList(subToken);
61688
+ lines.push(...subLines.map((l) => ` ${l}`));
61689
+ }
61690
+ }
61691
+ }
61692
+ }
61693
+ return lines;
61694
+ }
61695
+ function renderBlockquote(token) {
61696
+ const inner = renderTokens(token.tokens, 100);
61697
+ return inner.split("\n").map((line) => `${FG_GRAY}\u2502${FG_DEFAULT} ${DIM}${line}${DIM_OFF}`);
61698
+ }
61699
+ function renderTable(token, maxWidth) {
61700
+ const lines = [];
61701
+ const colWidths = token.header.map((h) => h.text.length);
61702
+ for (const row of token.rows) {
61703
+ for (let i = 0; i < row.length; i++) {
61704
+ colWidths[i] = Math.max(colWidths[i] ?? 0, row[i].text.length);
61705
+ }
61706
+ }
61707
+ const totalWidth = colWidths.reduce((a, b) => a + b, 0) + colWidths.length * 3 + 1;
61708
+ if (totalWidth > maxWidth) {
61709
+ const scale = maxWidth / totalWidth;
61710
+ for (let i = 0; i < colWidths.length; i++) {
61711
+ colWidths[i] = Math.max(3, Math.floor(colWidths[i] * scale));
61712
+ }
61713
+ }
61714
+ const headerLine = token.header.map((h, i) => pad(h.text, colWidths[i])).join(` ${FG_GRAY}\u2502${FG_DEFAULT} `);
61715
+ lines.push(`${BOLD}${headerLine}${BOLD_OFF}`);
61716
+ const sepLine = colWidths.map((w) => "\u2500".repeat(w)).join(`\u2500\u253C\u2500`);
61717
+ lines.push(`${FG_GRAY}${sepLine}${FG_DEFAULT}`);
61718
+ for (const row of token.rows) {
61719
+ const rowLine = row.map((cell, i) => pad(cell.text, colWidths[i])).join(` ${FG_GRAY}\u2502${FG_DEFAULT} `);
61720
+ lines.push(rowLine);
61721
+ }
61722
+ return lines;
61723
+ }
61724
+ function renderInline(text) {
61725
+ return renderInlineWithRestore(text, "");
61726
+ }
61727
+ function renderInlineWithRestore(text, restore) {
61728
+ return text.replace(/\*\*(.+?)\*\*/g, `${BOLD}$1${BOLD_OFF}${restore}`).replace(/__(.+?)__/g, `${BOLD}$1${BOLD_OFF}${restore}`).replace(/\*(.+?)\*/g, `${ITALIC}$1${ITALIC_OFF}${restore}`).replace(/_(.+?)_/g, `${ITALIC}$1${ITALIC_OFF}${restore}`).replace(/~~(.+?)~~/g, `${STRIKETHROUGH}$1${STRIKE_OFF}${restore}`).replace(/`([^`]+)`/g, `${BG_GRAY}${FG_GREEN} $1 ${FG_DEFAULT}${BG_DEFAULT}${restore}`).replace(/\[([^\]]+)\]\(([^)]+)\)/g, `${UNDERLINE}${FG_BLUE}$1${UNDERLINE_OFF}${FG_DEFAULT}${FG_GRAY} ($2)${FG_DEFAULT}${restore}`).replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"');
61729
+ }
61730
+ function highlightSyntax(line, lang) {
61731
+ const keywords = {
61732
+ typescript: ["import", "export", "from", "const", "let", "var", "function", "class", "interface", "type", "return", "if", "else", "for", "while", "async", "await", "new", "this", "extends", "implements"],
61733
+ javascript: ["import", "export", "from", "const", "let", "var", "function", "class", "return", "if", "else", "for", "while", "async", "await", "new", "this"],
61734
+ python: ["import", "from", "def", "class", "return", "if", "elif", "else", "for", "while", "with", "as", "try", "except", "finally", "raise", "yield", "async", "await", "self"],
61735
+ rust: ["fn", "let", "mut", "pub", "struct", "enum", "impl", "trait", "use", "mod", "return", "if", "else", "for", "while", "match", "self", "super", "crate"],
61736
+ go: ["func", "var", "const", "type", "struct", "interface", "return", "if", "else", "for", "range", "switch", "case", "package", "import", "defer", "go", "chan"]
61737
+ };
61738
+ const ts = keywords.typescript ?? [];
61739
+ const kw = keywords[lang] ?? keywords[lang.replace(/x$/, "")] ?? ts;
61740
+ let result = line;
61741
+ result = result.replace(/(\/\/.*$)/gm, `${FG_GRAY}$1${FG_DEFAULT}`);
61742
+ result = result.replace(/(#.*$)/gm, `${FG_GRAY}$1${FG_DEFAULT}`);
61743
+ result = result.replace(/("[^"]*")/g, `${FG_GREEN}$1${FG_DEFAULT}`);
61744
+ result = result.replace(/('[^']*')/g, `${FG_GREEN}$1${FG_DEFAULT}`);
61745
+ result = result.replace(/(`[^`]*`)/g, `${FG_GREEN}$1${FG_DEFAULT}`);
61746
+ for (const kwd of kw) {
61747
+ result = result.replace(
61748
+ new RegExp(`\\b(${kwd})\\b`, "g"),
61749
+ `${FG_MAGENTA}$1${FG_DEFAULT}`
61692
61750
  );
61751
+ }
61752
+ result = result.replace(/\b(\d+\.?\d*)\b/g, `${FG_YELLOW}$1${FG_DEFAULT}`);
61753
+ return result;
61754
+ }
61755
+ function pad(text, width) {
61756
+ if (text.length >= width) return text.slice(0, width);
61757
+ return text + " ".repeat(width - text.length);
61758
+ }
61759
+ var ESC2, RESET, BOLD, BOLD_OFF, DIM, DIM_OFF, ITALIC, ITALIC_OFF, UNDERLINE, UNDERLINE_OFF, STRIKETHROUGH, STRIKE_OFF, FG_CYAN, FG_YELLOW, FG_GREEN, FG_BLUE, FG_MAGENTA, FG_GRAY, FG_DEFAULT, BG_GRAY, BG_DEFAULT;
61760
+ var init_markdown = __esm({
61761
+ "src/ui/components/markdown.tsx"() {
61762
+ "use strict";
61763
+ init_marked_esm();
61764
+ ESC2 = "\x1B[";
61765
+ RESET = `${ESC2}0m`;
61766
+ BOLD = `${ESC2}1m`;
61767
+ BOLD_OFF = `${ESC2}22m`;
61768
+ DIM = `${ESC2}2m`;
61769
+ DIM_OFF = `${ESC2}22m`;
61770
+ ITALIC = `${ESC2}3m`;
61771
+ ITALIC_OFF = `${ESC2}23m`;
61772
+ UNDERLINE = `${ESC2}4m`;
61773
+ UNDERLINE_OFF = `${ESC2}24m`;
61774
+ STRIKETHROUGH = `${ESC2}9m`;
61775
+ STRIKE_OFF = `${ESC2}29m`;
61776
+ FG_CYAN = `${ESC2}36m`;
61777
+ FG_YELLOW = `${ESC2}33m`;
61778
+ FG_GREEN = `${ESC2}32m`;
61779
+ FG_BLUE = `${ESC2}34m`;
61780
+ FG_MAGENTA = `${ESC2}35m`;
61781
+ FG_GRAY = `${ESC2}90m`;
61782
+ FG_DEFAULT = `${ESC2}39m`;
61783
+ BG_GRAY = `${ESC2}100m`;
61784
+ BG_DEFAULT = `${ESC2}49m`;
61785
+ }
61786
+ });
61693
61787
 
61694
- -- Metrics (per-turn tracking)
61695
- CREATE TABLE IF NOT EXISTS metrics (
61696
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61697
- session_id TEXT NOT NULL,
61698
- turn_index INTEGER,
61699
- tokens_in INTEGER DEFAULT 0,
61700
- tokens_out INTEGER DEFAULT 0,
61701
- cost_usd REAL DEFAULT 0,
61702
- api_duration_ms REAL DEFAULT 0,
61703
- tool_duration_ms REAL DEFAULT 0,
61704
- hook_duration_ms REAL DEFAULT 0,
61705
- tool_count INTEGER DEFAULT 0,
61706
- model TEXT,
61707
- created_at TEXT DEFAULT (datetime('now'))
61708
- );
61788
+ // src/api/index.ts
61789
+ var init_api = __esm({
61790
+ "src/api/index.ts"() {
61791
+ "use strict";
61792
+ init_client();
61793
+ init_models();
61794
+ init_streaming();
61795
+ }
61796
+ });
61709
61797
 
61710
- -- Audit log (for security \u2014 tracks all tool executions)
61711
- CREATE TABLE IF NOT EXISTS audit_log (
61712
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61713
- session_id TEXT,
61714
- tool_name TEXT NOT NULL,
61715
- input_summary TEXT,
61716
- result_summary TEXT,
61717
- exit_code INTEGER,
61718
- duration_ms REAL,
61719
- was_allowed INTEGER DEFAULT 1,
61720
- created_at TEXT DEFAULT (datetime('now'))
61721
- );
61722
- `);
61798
+ // src/core/errors.ts
61799
+ function errorToString(err) {
61800
+ if (err instanceof Error) return err.message;
61801
+ if (typeof err === "string") return err;
61802
+ return String(err);
61723
61803
  }
61724
- function dbRun(sql, params = []) {
61725
- const db = getDb();
61726
- try {
61727
- const stmt = db.prepare(sql);
61728
- return stmt.run(...params);
61729
- } catch (e) {
61804
+ var init_errors2 = __esm({
61805
+ "src/core/errors.ts"() {
61806
+ "use strict";
61807
+ }
61808
+ });
61809
+
61810
+ // src/core/agent-loop.ts
61811
+ async function runAgentLoop(initialMessages, options2) {
61812
+ const client = options2.client ?? getApiClient();
61813
+ const messages = [...initialMessages];
61814
+ const maxTurns = options2.maxTurns ?? DEFAULT_MAX_TURNS;
61815
+ let totalInputTokens = 0;
61816
+ let totalOutputTokens = 0;
61817
+ let turnIndex = 0;
61818
+ let aborted = false;
61819
+ const toolDefs = buildToolDefinitions(options2.tools);
61820
+ const toolMap = new Map(options2.tools.map((t) => [t.name, t]));
61821
+ while (turnIndex < maxTurns) {
61822
+ if (options2.signal?.aborted) {
61823
+ aborted = true;
61824
+ break;
61825
+ }
61826
+ options2.onProgress?.({ type: "turn_start", turnIndex });
61827
+ const request = {
61828
+ model: options2.model,
61829
+ messages,
61830
+ systemPrompt: options2.systemPrompt,
61831
+ tools: toolDefs.length > 0 ? toolDefs : void 0,
61832
+ thinkingConfig: options2.thinkingConfig,
61833
+ maxTokens: options2.maxTokens,
61834
+ stream: true,
61835
+ signal: options2.signal,
61836
+ querySource: options2.querySource
61837
+ };
61838
+ options2.onProgress?.({ type: "streaming", turnIndex });
61839
+ const contentBlocks = [];
61840
+ let stopReason = null;
61730
61841
  try {
61731
- return db.run(sql, params);
61732
- } catch {
61733
- throw e;
61842
+ for await (const item of client.streamMessage(request)) {
61843
+ if (options2.signal?.aborted) {
61844
+ aborted = true;
61845
+ break;
61846
+ }
61847
+ const { event, accumulated } = item;
61848
+ if (event.type === "content_block_delta" && event.delta) {
61849
+ if (event.delta.type === "text_delta") {
61850
+ options2.onTextDelta?.(event.delta.text);
61851
+ } else if (event.delta.type === "thinking_delta") {
61852
+ options2.onThinkingDelta?.(event.delta.thinking);
61853
+ }
61854
+ }
61855
+ if (event.type === "message_stop" || event.type === "message_delta") {
61856
+ if (accumulated.content) {
61857
+ contentBlocks.length = 0;
61858
+ contentBlocks.push(...accumulated.content);
61859
+ }
61860
+ stopReason = accumulated.stopReason ?? null;
61861
+ if (accumulated.usage) {
61862
+ totalInputTokens += accumulated.usage.inputTokens;
61863
+ totalOutputTokens += accumulated.usage.outputTokens;
61864
+ }
61865
+ }
61866
+ }
61867
+ } catch (error) {
61868
+ if (error.name === "AbortError") {
61869
+ aborted = true;
61870
+ break;
61871
+ }
61872
+ throw error;
61873
+ }
61874
+ if (aborted) break;
61875
+ const assistantMessage = {
61876
+ role: "assistant",
61877
+ content: contentBlocks
61878
+ };
61879
+ messages.push(assistantMessage);
61880
+ const toolUseBlocks = contentBlocks.filter(
61881
+ (b) => b.type === "tool_use"
61882
+ );
61883
+ if (toolUseBlocks.length === 0 || stopReason === "end_turn") {
61884
+ options2.onTurnComplete?.(turnIndex, assistantMessage);
61885
+ options2.onProgress?.({ type: "turn_end", turnIndex, stopReason });
61886
+ turnIndex++;
61887
+ break;
61734
61888
  }
61889
+ const toolResults = await executeTools(
61890
+ toolUseBlocks,
61891
+ toolMap,
61892
+ options2
61893
+ );
61894
+ const toolResultMessage = {
61895
+ role: "user",
61896
+ content: toolResults.map((r) => ({
61897
+ type: "tool_result",
61898
+ tool_use_id: r.toolUseId,
61899
+ content: r.error ?? (typeof r.data === "string" ? r.data : JSON.stringify(r.data)),
61900
+ is_error: r.isError
61901
+ }))
61902
+ };
61903
+ messages.push(toolResultMessage);
61904
+ options2.onTurnComplete?.(turnIndex, assistantMessage);
61905
+ options2.onProgress?.({ type: "turn_end", turnIndex, stopReason });
61906
+ turnIndex++;
61735
61907
  }
61908
+ options2.onProgress?.({ type: "loop_end", totalTurns: turnIndex });
61909
+ return {
61910
+ messages,
61911
+ totalTurns: turnIndex,
61912
+ aborted,
61913
+ usage: { totalInputTokens, totalOutputTokens }
61914
+ };
61736
61915
  }
61737
- function createJsonFileDb() {
61738
- const storePath = join2(getConfigDir(), "coders-fallback.json");
61739
- let store = { tables: {}, autoInc: {} };
61740
- try {
61741
- if (existsSync4(storePath)) {
61742
- store = JSON.parse(readFileSync3(storePath, "utf-8"));
61743
- if (!store.tables) store.tables = {};
61744
- if (!store.autoInc) store.autoInc = {};
61916
+ async function executeTools(toolUseBlocks, toolMap, options2) {
61917
+ const results = [];
61918
+ const concurrentTools = [];
61919
+ const sequentialTools = [];
61920
+ for (const block2 of toolUseBlocks) {
61921
+ const handler = toolMap.get(block2.name);
61922
+ if (!handler) {
61923
+ results.push({
61924
+ toolUseId: block2.id,
61925
+ toolName: block2.name,
61926
+ error: `Unknown tool: ${block2.name}`,
61927
+ isError: true
61928
+ });
61929
+ continue;
61745
61930
  }
61746
- } catch {
61747
- }
61748
- function flush() {
61749
- try {
61750
- writeFileSync2(storePath, JSON.stringify(store), "utf-8");
61751
- } catch {
61931
+ if (handler.isConcurrencySafe) {
61932
+ concurrentTools.push({ block: block2, handler });
61933
+ } else {
61934
+ sequentialTools.push({ block: block2, handler });
61752
61935
  }
61753
61936
  }
61754
- function ensureTable(name) {
61755
- if (!store.tables[name]) {
61756
- store.tables[name] = [];
61757
- store.autoInc[name] = 0;
61758
- }
61937
+ if (concurrentTools.length > 0) {
61938
+ const concurrentResults = await Promise.all(
61939
+ concurrentTools.map(
61940
+ ({ block: block2, handler }) => executeSingleTool(block2, handler, options2)
61941
+ )
61942
+ );
61943
+ results.push(...concurrentResults);
61759
61944
  }
61760
- function now() {
61761
- return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
61945
+ for (const { block: block2, handler } of sequentialTools) {
61946
+ if (options2.signal?.aborted) break;
61947
+ const result = await executeSingleTool(block2, handler, options2);
61948
+ results.push(result);
61762
61949
  }
61763
- function parseInsert(sql, params) {
61764
- const m = sql.match(/INSERT\s+(?:OR\s+\w+\s+)?INTO\s+(\w+)\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/i);
61765
- if (!m) return { changes: 0, lastInsertRowid: 0 };
61766
- const table = m[1];
61767
- ensureTable(table);
61768
- const cols = m[2].split(",").map((c) => c.trim());
61769
- const valuePlaceholders = m[3].split(",").map((v) => v.trim());
61770
- const row = {};
61771
- let paramIdx = 0;
61772
- for (let i = 0; i < cols.length; i++) {
61773
- const ph = valuePlaceholders[i];
61774
- if (ph === "?") {
61775
- row[cols[i]] = params[paramIdx++];
61776
- } else if (/^datetime\(/i.test(ph)) {
61777
- row[cols[i]] = now();
61778
- } else {
61779
- row[cols[i]] = ph.replace(/^['"]|['"]$/g, "");
61780
- }
61781
- }
61782
- if (!row["id"] && store.autoInc[table] !== void 0) {
61783
- store.autoInc[table]++;
61784
- row["id"] = store.autoInc[table];
61785
- }
61786
- store.tables[table].push(row);
61787
- flush();
61788
- return { changes: 1, lastInsertRowid: typeof row["id"] === "number" ? row["id"] : 0 };
61950
+ return results;
61951
+ }
61952
+ async function executeSingleTool(block2, handler, options2) {
61953
+ const { id: toolUseId, name: toolName, input } = block2;
61954
+ options2.onProgress?.({ type: "tool_execution", toolName, toolUseId });
61955
+ const parseFailed = block2._inputParseFailed;
61956
+ if (parseFailed) {
61957
+ const rawJson = block2._rawInputJson;
61958
+ const error = `Tool input not fully received \u2014 JSON parsing failed for ${toolName}. Partial input (${rawJson?.length ?? 0} chars) could not be parsed. This is a streaming issue; retrying the request should resolve it.`;
61959
+ options2.onToolUseRejected?.(toolName, toolUseId, error);
61960
+ return { toolUseId, toolName, error, isError: true };
61789
61961
  }
61790
- function parseSelect(sql, params) {
61791
- const m = sql.match(/SELECT\s+(.+?)\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(.+?))?(?:\s+LIMIT\s+(\d+))?$/i);
61792
- if (!m) return [];
61793
- const table = m[2];
61794
- if (!store.tables[table]) return [];
61795
- let rows = [...store.tables[table]];
61796
- if (m[3]) {
61797
- const whereParts = m[3].trim();
61798
- const wm = whereParts.match(/(\w+)\s*=\s*\?/);
61799
- if (wm && params.length > 0) {
61800
- const col = wm[1];
61801
- const val = params[0];
61802
- rows = rows.filter((r) => r[col] === val);
61962
+ if (input && Object.keys(input).length === 0 && handler.inputSchema && Array.isArray(handler.inputSchema.required) && (handler.inputSchema.required ?? []).length > 0) {
61963
+ const error = `Tool input not fully received \u2014 ${toolName} requires parameters (${(handler.inputSchema.required ?? []).join(", ")}) but received empty input {}. Skipping execution to prevent undefined behavior.`;
61964
+ options2.onToolUseRejected?.(toolName, toolUseId, error);
61965
+ return { toolUseId, toolName, error, isError: true };
61966
+ }
61967
+ options2.onToolUseStart?.(toolName, toolUseId, input);
61968
+ try {
61969
+ if (options2.onPermissionCheck) {
61970
+ const permResult = await options2.onPermissionCheck(toolName, input);
61971
+ if (permResult.behavior === "deny") {
61972
+ const reason = permResult.message ?? "Permission denied";
61973
+ options2.onToolUseRejected?.(toolName, toolUseId, reason);
61974
+ return { toolUseId, toolName, error: reason, isError: true };
61803
61975
  }
61804
61976
  }
61805
- if (m[5]) {
61806
- rows = rows.slice(0, parseInt(m[5], 10));
61807
- }
61808
- return rows;
61809
- }
61810
- function parseUpdate(sql, params) {
61811
- const m = sql.match(/UPDATE\s+(\w+)\s+SET\s+(.+?)\s+WHERE\s+(.+)/i);
61812
- if (!m) return { changes: 0 };
61813
- const table = m[1];
61814
- if (!store.tables[table]) return { changes: 0 };
61815
- const setClauses = m[2].split(",").map((s) => s.trim());
61816
- const whereClause = m[3].trim();
61817
- const setParamCount = setClauses.filter((c) => c.includes("?")).length;
61818
- const wm = whereClause.match(/(\w+)\s*=\s*\?/);
61819
- const whereCol = wm ? wm[1] : null;
61820
- const whereVal = wm ? params[setParamCount] : null;
61821
- let changes = 0;
61822
- for (const row of store.tables[table]) {
61823
- if (whereCol && row[whereCol] !== whereVal) continue;
61824
- let paramIdx = 0;
61825
- for (const clause of setClauses) {
61826
- const cm = clause.match(/(\w+)\s*=\s*(.+)/);
61827
- if (!cm) continue;
61828
- const col = cm[1];
61829
- const val = cm[2].trim();
61830
- if (val === "?") {
61831
- row[col] = params[paramIdx++];
61832
- } else if (/^datetime\(/i.test(val)) {
61833
- row[col] = now();
61834
- }
61977
+ if (handler.validateInput) {
61978
+ const validation = await handler.validateInput(input);
61979
+ if (!validation.result) {
61980
+ const error = validation.message ?? "Invalid input";
61981
+ return { toolUseId, toolName, error, isError: true };
61835
61982
  }
61836
- changes++;
61837
61983
  }
61838
- if (changes > 0) flush();
61839
- return { changes };
61840
- }
61841
- function parseDelete(sql, params) {
61842
- const m = sql.match(/DELETE\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+))?/i);
61843
- if (!m) return { changes: 0 };
61844
- const table = m[1];
61845
- if (!store.tables[table]) return { changes: 0 };
61846
- if (!m[2]) {
61847
- const count = store.tables[table].length;
61848
- store.tables[table] = [];
61849
- flush();
61850
- return { changes: count };
61984
+ const result = await handler.call(input, {
61985
+ abortSignal: options2.signal,
61986
+ agentId: options2.agentId,
61987
+ toolUseId
61988
+ });
61989
+ options2.onToolUseEnd?.(toolName, toolUseId, result);
61990
+ if (result.isError || result.error) {
61991
+ return { toolUseId, toolName, error: result.error, isError: true };
61851
61992
  }
61852
- const wm = m[2].match(/(\w+)\s*=\s*\?/);
61853
- if (!wm) return { changes: 0 };
61854
- const col = wm[1];
61855
- const val = params[0];
61856
- const before = store.tables[table].length;
61857
- store.tables[table] = store.tables[table].filter((r) => r[col] !== val);
61858
- const changes = before - store.tables[table].length;
61859
- if (changes > 0) flush();
61860
- return { changes };
61993
+ return { toolUseId, toolName, data: result.data };
61994
+ } catch (error) {
61995
+ const errorMsg = errorToString(error);
61996
+ options2.onToolUseEnd?.(toolName, toolUseId, { error: errorMsg, isError: true });
61997
+ return { toolUseId, toolName, error: errorMsg, isError: true };
61861
61998
  }
61862
- function execSql(sql, params = []) {
61863
- const trimmed = sql.trim();
61864
- if (/^INSERT/i.test(trimmed)) return parseInsert(trimmed, params);
61865
- if (/^SELECT/i.test(trimmed)) return parseSelect(trimmed, params);
61866
- if (/^UPDATE/i.test(trimmed)) return parseUpdate(trimmed, params);
61867
- if (/^DELETE/i.test(trimmed)) return parseDelete(trimmed, params);
61868
- return { changes: 0 };
61999
+ }
62000
+ function buildToolDefinitions(tools) {
62001
+ return tools.map((t) => ({
62002
+ name: t.name,
62003
+ description: t.description,
62004
+ input_schema: t.inputSchema
62005
+ }));
62006
+ }
62007
+ var DEFAULT_MAX_TURNS;
62008
+ var init_agent_loop = __esm({
62009
+ "src/core/agent-loop.ts"() {
62010
+ "use strict";
62011
+ init_api();
62012
+ init_errors2();
62013
+ DEFAULT_MAX_TURNS = 100;
61869
62014
  }
62015
+ });
62016
+
62017
+ // src/config/permissions.ts
62018
+ function createDefaultPermissionContext(settings) {
62019
+ const defaultMode = settings?.permissions?.defaultMode ?? "default";
61870
62020
  return {
61871
- exec(sql) {
61872
- const matches = sql.matchAll(/CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+(\w+)/gi);
61873
- for (const m of matches) {
61874
- ensureTable(m[1]);
61875
- }
61876
- },
61877
- prepare(sql) {
61878
- return {
61879
- run(...params) {
61880
- return execSql(sql, params);
61881
- },
61882
- get(...params) {
61883
- const result = execSql(sql, params);
61884
- if (Array.isArray(result)) return result[0];
61885
- return void 0;
61886
- },
61887
- all(...params) {
61888
- const result = execSql(sql, params);
61889
- if (Array.isArray(result)) return result;
61890
- return [];
61891
- }
61892
- };
61893
- },
61894
- // Bun-style API aliases
61895
- run(sql, params = []) {
61896
- return execSql(sql, params);
61897
- },
61898
- query(sql) {
61899
- return {
61900
- get(...params) {
61901
- const result = execSql(sql, params);
61902
- if (Array.isArray(result)) return result[0];
61903
- return void 0;
61904
- },
61905
- all(...params) {
61906
- const result = execSql(sql, params);
61907
- if (Array.isArray(result)) return result;
61908
- return [];
61909
- }
61910
- };
61911
- },
61912
- close() {
61913
- flush();
61914
- }
62021
+ mode: defaultMode,
62022
+ allowRules: settings?.permissions?.allow ?? [],
62023
+ denyRules: settings?.permissions?.deny ?? []
61915
62024
  };
61916
62025
  }
61917
- var _db;
61918
- var init_db = __esm({
61919
- "src/db/index.ts"() {
62026
+ var init_permissions = __esm({
62027
+ "src/config/permissions.ts"() {
61920
62028
  "use strict";
61921
- init_paths();
61922
- _db = null;
61923
62029
  }
61924
62030
  });
61925
62031
 
@@ -62210,7 +62316,7 @@ function getShell() {
62210
62316
  }
62211
62317
  return process.env.SHELL ?? "/bin/bash";
62212
62318
  }
62213
- function truncate(str, maxLen) {
62319
+ function truncate2(str, maxLen) {
62214
62320
  if (str.length <= maxLen) return str;
62215
62321
  return str.slice(0, maxLen - 3) + "...";
62216
62322
  }
@@ -62455,7 +62561,7 @@ var init_bash = __esm({
62455
62561
  return input.command;
62456
62562
  },
62457
62563
  getActivityDescription(input) {
62458
- return input.description ?? `Running: ${truncate(input.command, 60)}`;
62564
+ return input.description ?? `Running: ${truncate2(input.command, 60)}`;
62459
62565
  },
62460
62566
  async validateInput(input) {
62461
62567
  if (!input.command || !input.command.trim()) {
@@ -62481,7 +62587,7 @@ var init_bash = __esm({
62481
62587
  }
62482
62588
  return {
62483
62589
  behavior: "passthrough",
62484
- message: `Run command: ${truncate(cmd, 100)}`
62590
+ message: `Run command: ${truncate2(cmd, 100)}`
62485
62591
  };
62486
62592
  },
62487
62593
  async call(input, context) {
@@ -62858,7 +62964,7 @@ Usage:
62858
62964
  });
62859
62965
 
62860
62966
  // src/tools/builtin/edit.ts
62861
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync7 } from "fs";
62967
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync7 } from "fs";
62862
62968
  import { resolve as resolve3, isAbsolute as isAbsolute2 } from "path";
62863
62969
  import { randomUUID } from "crypto";
62864
62970
  function resolvePath2(filePath) {
@@ -63068,7 +63174,7 @@ var init_edit = __esm({
63068
63174
  );
63069
63175
  } catch {
63070
63176
  }
63071
- writeFileSync3(resolved, newContent, "utf-8");
63177
+ writeFileSync4(resolved, newContent, "utf-8");
63072
63178
  markFileAsRead(resolved);
63073
63179
  const gitDiff = generateUnifiedDiff(originalContent, newContent, input.file_path);
63074
63180
  return {
@@ -63106,8 +63212,9 @@ Usage:
63106
63212
  });
63107
63213
 
63108
63214
  // src/tools/builtin/write.ts
63109
- import { writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
63215
+ import { writeFileSync as writeFileSync5, readFileSync as readFileSync7, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
63110
63216
  import { dirname as dirname3, resolve as resolve4, isAbsolute as isAbsolute3 } from "path";
63217
+ import { randomUUID as randomUUID2 } from "crypto";
63111
63218
  function resolvePath3(filePath) {
63112
63219
  if (isAbsolute3(filePath)) return filePath;
63113
63220
  return resolve4(process.cwd(), filePath);
@@ -63119,6 +63226,7 @@ var init_write = __esm({
63119
63226
  init_zod();
63120
63227
  init_constants();
63121
63228
  init_read();
63229
+ init_db();
63122
63230
  WriteInputSchema = external_exports.strictObject({
63123
63231
  file_path: external_exports.string().describe("The absolute path to the file to write"),
63124
63232
  content: external_exports.string().describe("The content to write to the file")
@@ -63182,7 +63290,18 @@ var init_write = __esm({
63182
63290
  if (!existsSync8(dir)) {
63183
63291
  mkdirSync4(dir, { recursive: true });
63184
63292
  }
63185
- writeFileSync4(resolved, input.content, "utf-8");
63293
+ if (!created) {
63294
+ try {
63295
+ const originalContent = readFileSync7(resolved, "utf-8");
63296
+ const cpId = randomUUID2().slice(0, 8);
63297
+ dbRun(
63298
+ "INSERT INTO checkpoints (id, session_id, file_path, original_content, edit_operation) VALUES (?, ?, ?, ?, ?)",
63299
+ [cpId, "current", resolved, originalContent, JSON.stringify({ type: "write_overwrite" })]
63300
+ );
63301
+ } catch {
63302
+ }
63303
+ }
63304
+ writeFileSync5(resolved, input.content, "utf-8");
63186
63305
  markFileAsRead(resolved);
63187
63306
  return {
63188
63307
  data: {
@@ -70270,6 +70389,11 @@ function App2({ model, mode, initialPrompt }) {
70270
70389
  const activeToolsRef = import_react22.default.useRef([]);
70271
70390
  activeToolsRef.current = activeTools;
70272
70391
  const rows = stdout?.rows ?? 24;
70392
+ const [slashSelected, setSlashSelected] = (0, import_react22.useState)(0);
70393
+ const allCommands = getAllSlashCommands();
70394
+ const showSlashMenu = input.startsWith("/") && !busy;
70395
+ const slashFilter = input.slice(1).toLowerCase();
70396
+ const filteredCommands = showSlashMenu ? allCommands.filter((c) => c.name.toLowerCase().startsWith(slashFilter)).slice(0, 8) : [];
70273
70397
  const [permissionPending, setPermissionPending] = (0, import_react22.useState)(null);
70274
70398
  const requestPermission = (0, import_react22.useCallback)((toolName, summary) => {
70275
70399
  return new Promise((resolve7) => {
@@ -70401,12 +70525,39 @@ function App2({ model, mode, initialPrompt }) {
70401
70525
  }
70402
70526
  return;
70403
70527
  }
70528
+ if (showSlashMenu && filteredCommands.length > 0) {
70529
+ if (key.downArrow || key.tab && !key.shift) {
70530
+ setSlashSelected((s) => Math.min(s + 1, filteredCommands.length - 1));
70531
+ return;
70532
+ }
70533
+ if (key.upArrow || key.tab && key.shift) {
70534
+ setSlashSelected((s) => Math.max(s - 1, 0));
70535
+ return;
70536
+ }
70537
+ if (key.return) {
70538
+ const cmd = filteredCommands[slashSelected];
70539
+ if (cmd) {
70540
+ setInput("");
70541
+ setSlashSelected(0);
70542
+ submit(`/${cmd.name}`);
70543
+ return;
70544
+ }
70545
+ }
70546
+ if (key.escape) {
70547
+ setInput("");
70548
+ setSlashSelected(0);
70549
+ return;
70550
+ }
70551
+ }
70404
70552
  if (key.return) {
70405
70553
  const t = input;
70406
70554
  setInput("");
70555
+ setSlashSelected(0);
70407
70556
  submit(t);
70408
- } else if (key.backspace || key.delete) setInput((p) => p.slice(0, -1));
70409
- else if (key.ctrl && ch === "c") exit();
70557
+ } else if (key.backspace || key.delete) {
70558
+ setInput((p) => p.slice(0, -1));
70559
+ setSlashSelected(0);
70560
+ } else if (key.ctrl && ch === "c") exit();
70410
70561
  else if (key.ctrl && ch === "d") exit();
70411
70562
  else if (key.ctrl && ch === "l") {
70412
70563
  setMsgs([]);
@@ -70442,6 +70593,17 @@ function App2({ model, mode, initialPrompt }) {
70442
70593
  input.startsWith("/") ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "magenta", children: input }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { children: input }),
70443
70594
  !busy && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: "\u258E" })
70444
70595
  ] }),
70596
+ showSlashMenu && filteredCommands.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexDirection: "column", paddingLeft: 2, children: filteredCommands.map((cmd, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { children: [
70597
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: i === slashSelected ? "cyan" : void 0, bold: i === slashSelected, children: i === slashSelected ? "\u25B8 " : " " }),
70598
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: i === slashSelected ? "cyan" : "blue", children: [
70599
+ "/",
70600
+ cmd.name.padEnd(16)
70601
+ ] }),
70602
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
70603
+ " ",
70604
+ cmd.description
70605
+ ] })
70606
+ ] }, cmd.name)) }),
70445
70607
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: sep }),
70446
70608
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBar, { model, mode, cost, tokens })
70447
70609
  ] })
@@ -70740,8 +70902,8 @@ async function bootstrap() {
70740
70902
  var VERSION, BUILD_TIME, PACKAGE_NAME2, ISSUES_URL2, startupTimestamps, originalCwd, RESET_TERMINAL, cleanupHandlers, earlyInput, earlyInputCapturing;
70741
70903
  var init_index = __esm({
70742
70904
  "src/cli/index.ts"() {
70743
- VERSION = "0.0.15";
70744
- BUILD_TIME = "2026-03-20T11:11:38.468Z";
70905
+ VERSION = "0.1.0";
70906
+ BUILD_TIME = "2026-03-20T12:44:32.414Z";
70745
70907
  PACKAGE_NAME2 = "@hasna/coders";
70746
70908
  ISSUES_URL2 = "https://github.com/hasnaxyz/open-coders/issues";
70747
70909
  startupTimestamps = {};