latticesql 4.2.3 → 4.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli.js +229 -29
- package/dist/desktop-entry.js +76390 -0
- package/dist/index.cjs +250 -46
- package/dist/index.d.cts +76 -1
- package/dist/index.d.ts +76 -1
- package/dist/index.js +230 -28
- package/docs/desktop.md +75 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -138,6 +138,8 @@ npm install latticesql
|
|
|
138
138
|
|
|
139
139
|
Requires **Node.js 18+**. The default backend is SQLite (`better-sqlite3`) — no external database process needed.
|
|
140
140
|
|
|
141
|
+
> **Prefer a desktop app?** Download a native, double-click build of the GUI (no terminal) for macOS or Windows from [latticesql.com/install](https://latticesql.com/install) — it runs the same GUI server. See [docs/desktop.md](docs/desktop.md).
|
|
142
|
+
|
|
141
143
|
To use the Postgres backend (for Supabase, Neon, RDS, or any other Postgres-compatible database), install the optional dependency:
|
|
142
144
|
|
|
143
145
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -1494,17 +1494,179 @@ var init_sqlite = __esm({
|
|
|
1494
1494
|
}
|
|
1495
1495
|
});
|
|
1496
1496
|
|
|
1497
|
+
// src/db/sqlite-deno.ts
|
|
1498
|
+
import { createRequire as createRequire2 } from "module";
|
|
1499
|
+
function runtimeRequire2() {
|
|
1500
|
+
const importMetaUrl = import.meta.url;
|
|
1501
|
+
return importMetaUrl ? createRequire2(importMetaUrl) : __require;
|
|
1502
|
+
}
|
|
1503
|
+
function loadNodeSqlite() {
|
|
1504
|
+
if (_ctor2) return _ctor2;
|
|
1505
|
+
const mod = runtimeRequire2()("node:sqlite");
|
|
1506
|
+
if (!mod.DatabaseSync) {
|
|
1507
|
+
throw new Error(
|
|
1508
|
+
"node:sqlite is unavailable in this runtime \u2014 cannot open the Deno SQLite adapter"
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
_ctor2 = mod.DatabaseSync;
|
|
1512
|
+
return _ctor2;
|
|
1513
|
+
}
|
|
1514
|
+
var _ctor2, DenoSqliteAdapter;
|
|
1515
|
+
var init_sqlite_deno = __esm({
|
|
1516
|
+
"src/db/sqlite-deno.ts"() {
|
|
1517
|
+
"use strict";
|
|
1518
|
+
_ctor2 = null;
|
|
1519
|
+
DenoSqliteAdapter = class {
|
|
1520
|
+
dialect = "sqlite";
|
|
1521
|
+
_db = null;
|
|
1522
|
+
_path;
|
|
1523
|
+
_wal;
|
|
1524
|
+
_busyTimeout;
|
|
1525
|
+
constructor(path3, options) {
|
|
1526
|
+
this._path = path3;
|
|
1527
|
+
this._wal = options?.wal ?? true;
|
|
1528
|
+
this._busyTimeout = options?.busyTimeout ?? 5e3;
|
|
1529
|
+
}
|
|
1530
|
+
get db() {
|
|
1531
|
+
if (!this._db) throw new Error("DenoSqliteAdapter: not open \u2014 call open() first");
|
|
1532
|
+
return this._db;
|
|
1533
|
+
}
|
|
1534
|
+
open() {
|
|
1535
|
+
const Ctor = loadNodeSqlite();
|
|
1536
|
+
this._db = new Ctor(this._path);
|
|
1537
|
+
this._db.exec(`PRAGMA busy_timeout = ${this._busyTimeout.toString()}`);
|
|
1538
|
+
if (this._wal) {
|
|
1539
|
+
this._db.exec("PRAGMA journal_mode = WAL");
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
close() {
|
|
1543
|
+
this._db?.close();
|
|
1544
|
+
this._db = null;
|
|
1545
|
+
}
|
|
1546
|
+
run(sql, params = []) {
|
|
1547
|
+
this.db.prepare(sql).run(...params);
|
|
1548
|
+
}
|
|
1549
|
+
get(sql, params = []) {
|
|
1550
|
+
return this.db.prepare(sql).get(...params);
|
|
1551
|
+
}
|
|
1552
|
+
all(sql, params = []) {
|
|
1553
|
+
return this.db.prepare(sql).all(...params);
|
|
1554
|
+
}
|
|
1555
|
+
prepare(sql) {
|
|
1556
|
+
const stmt = this.db.prepare(sql);
|
|
1557
|
+
return {
|
|
1558
|
+
run: (...params) => {
|
|
1559
|
+
const info = stmt.run(...params);
|
|
1560
|
+
return {
|
|
1561
|
+
changes: Number(info.changes),
|
|
1562
|
+
lastInsertRowid: info.lastInsertRowid
|
|
1563
|
+
};
|
|
1564
|
+
},
|
|
1565
|
+
get: (...params) => stmt.get(...params),
|
|
1566
|
+
all: (...params) => stmt.all(...params)
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
introspectColumns(table) {
|
|
1570
|
+
const rows = this.all(`PRAGMA table_info("${table}")`);
|
|
1571
|
+
return rows.map((r6) => r6.name);
|
|
1572
|
+
}
|
|
1573
|
+
/** Mirror of SQLiteAdapter.addColumn — SQLite ALTER quirks are binding-agnostic. */
|
|
1574
|
+
addColumn(table, column, typeSpec) {
|
|
1575
|
+
const upperType = typeSpec.toUpperCase();
|
|
1576
|
+
if (upperType.includes("PRIMARY KEY")) return;
|
|
1577
|
+
const hasNonConstantDefault = upperType.includes("CURRENT_TIMESTAMP") || /DATETIME\s*\(\s*'NOW'\s*\)/i.test(typeSpec) || upperType.includes("RANDOM()");
|
|
1578
|
+
if (hasNonConstantDefault) {
|
|
1579
|
+
const safeType = typeSpec.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+\(?\s*CURRENT_TIMESTAMP\s*\)?/gi, "").replace(/\bDEFAULT\s+\(?\s*datetime\([^)]*\)\s*\)?/gi, "").replace(/\bDEFAULT\s+\(?\s*RANDOM\(\)\s*\)?/gi, "").replace(/\s+/g, " ").trim();
|
|
1580
|
+
this.run(`ALTER TABLE "${table}" ADD COLUMN "${column}" ${safeType || "TEXT"}`);
|
|
1581
|
+
this.run(`UPDATE "${table}" SET "${column}" = CURRENT_TIMESTAMP WHERE "${column}" IS NULL`);
|
|
1582
|
+
} else {
|
|
1583
|
+
this.run(`ALTER TABLE "${table}" ADD COLUMN "${column}" ${typeSpec}`);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* O(1) watch-loop change-probe — same composition as SQLiteAdapter, but
|
|
1588
|
+
* `data_version` is read with a plain prepared statement because node:sqlite
|
|
1589
|
+
* has no `.pragma(name, { simple: true })` scalar helper.
|
|
1590
|
+
*/
|
|
1591
|
+
changeProbe() {
|
|
1592
|
+
const dataVersion = this.db.prepare("PRAGMA data_version").get().data_version;
|
|
1593
|
+
const totalChanges = this.db.prepare("SELECT total_changes() AS n").get().n;
|
|
1594
|
+
return `${String(dataVersion)}:${String(totalChanges)}`;
|
|
1595
|
+
}
|
|
1596
|
+
// ── Async surface (sync under the hood; mirrors SQLiteAdapter) ──────────
|
|
1597
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1598
|
+
async runAsync(sql, params) {
|
|
1599
|
+
this.run(sql, params);
|
|
1600
|
+
}
|
|
1601
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1602
|
+
async getAsync(sql, params) {
|
|
1603
|
+
return this.get(sql, params);
|
|
1604
|
+
}
|
|
1605
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1606
|
+
async allAsync(sql, params) {
|
|
1607
|
+
return this.all(sql, params);
|
|
1608
|
+
}
|
|
1609
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1610
|
+
async introspectColumnsAsync(table) {
|
|
1611
|
+
return this.introspectColumns(table);
|
|
1612
|
+
}
|
|
1613
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1614
|
+
async introspectAllColumns(tables) {
|
|
1615
|
+
const map = /* @__PURE__ */ new Map();
|
|
1616
|
+
for (const t8 of tables) {
|
|
1617
|
+
try {
|
|
1618
|
+
const cols = this.introspectColumns(t8);
|
|
1619
|
+
if (cols.length > 0) map.set(t8, new Set(cols));
|
|
1620
|
+
} catch {
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
return map;
|
|
1624
|
+
}
|
|
1625
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1626
|
+
async addColumnAsync(table, column, typeSpec) {
|
|
1627
|
+
this.addColumn(table, column, typeSpec);
|
|
1628
|
+
}
|
|
1629
|
+
/** BEGIN/COMMIT around an awaited fn; ROLLBACK on throw. Mirror of SQLiteAdapter. */
|
|
1630
|
+
async withClient(fn) {
|
|
1631
|
+
const dbRef = this.db;
|
|
1632
|
+
const getSync = this.get.bind(this);
|
|
1633
|
+
const allSync = this.all.bind(this);
|
|
1634
|
+
const tx = {
|
|
1635
|
+
run: (sql, params) => {
|
|
1636
|
+
const info = dbRef.prepare(sql).run(...params ?? []);
|
|
1637
|
+
return Promise.resolve({ changes: Number(info.changes) });
|
|
1638
|
+
},
|
|
1639
|
+
get: (sql, params) => Promise.resolve(getSync(sql, params ?? [])),
|
|
1640
|
+
all: (sql, params) => Promise.resolve(allSync(sql, params ?? []))
|
|
1641
|
+
};
|
|
1642
|
+
this.run("BEGIN");
|
|
1643
|
+
try {
|
|
1644
|
+
const result = await fn(tx);
|
|
1645
|
+
this.run("COMMIT");
|
|
1646
|
+
return result;
|
|
1647
|
+
} catch (err) {
|
|
1648
|
+
try {
|
|
1649
|
+
this.run("ROLLBACK");
|
|
1650
|
+
} catch {
|
|
1651
|
+
}
|
|
1652
|
+
throw err;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
|
|
1497
1659
|
// src/db/postgres.ts
|
|
1498
1660
|
import path2 from "path";
|
|
1499
1661
|
import { fileURLToPath } from "url";
|
|
1500
|
-
import { createRequire as
|
|
1662
|
+
import { createRequire as createRequire3 } from "module";
|
|
1501
1663
|
function moduleContext() {
|
|
1502
1664
|
if (_moduleContext) return _moduleContext;
|
|
1503
1665
|
const importMetaUrl = import.meta.url;
|
|
1504
1666
|
if (importMetaUrl) {
|
|
1505
1667
|
_moduleContext = {
|
|
1506
1668
|
dir: path2.dirname(fileURLToPath(importMetaUrl)),
|
|
1507
|
-
require:
|
|
1669
|
+
require: createRequire3(importMetaUrl)
|
|
1508
1670
|
};
|
|
1509
1671
|
} else {
|
|
1510
1672
|
_moduleContext = { dir: __dirname, require: __require };
|
|
@@ -9693,6 +9855,9 @@ function buildAdapter(dbPath, options) {
|
|
|
9693
9855
|
const adapterOpts = {};
|
|
9694
9856
|
if (options.wal !== void 0) adapterOpts.wal = options.wal;
|
|
9695
9857
|
if (options.busyTimeout !== void 0) adapterOpts.busyTimeout = options.busyTimeout;
|
|
9858
|
+
if (typeof globalThis.Deno !== "undefined") {
|
|
9859
|
+
return new DenoSqliteAdapter(sqlitePath, adapterOpts);
|
|
9860
|
+
}
|
|
9696
9861
|
return new SQLiteAdapter(sqlitePath, adapterOpts);
|
|
9697
9862
|
}
|
|
9698
9863
|
function _resolveTemplateName(render) {
|
|
@@ -9712,6 +9877,7 @@ var init_lattice = __esm({
|
|
|
9712
9877
|
init_render_cursor();
|
|
9713
9878
|
init_adapter();
|
|
9714
9879
|
init_sqlite();
|
|
9880
|
+
init_sqlite_deno();
|
|
9715
9881
|
init_postgres();
|
|
9716
9882
|
init_pk();
|
|
9717
9883
|
init_manager();
|
|
@@ -13884,9 +14050,6 @@ async function resolveClaudeAuth(db) {
|
|
|
13884
14050
|
const apiKey = await resolveAnthropicKey(db);
|
|
13885
14051
|
return apiKey ? { apiKey } : null;
|
|
13886
14052
|
}
|
|
13887
|
-
async function hasClaudeAuth(db) {
|
|
13888
|
-
return Boolean(await readMachineCredential(db, CLAUDE_OAUTH_KIND)) || await hasCredential(db, "anthropic", "ANTHROPIC_API_KEY");
|
|
13889
|
-
}
|
|
13890
14053
|
async function claudeAuthKind(db) {
|
|
13891
14054
|
if (await readMachineCredential(db, CLAUDE_OAUTH_KIND)) return "oauth";
|
|
13892
14055
|
if (await hasCredential(db, "anthropic", "ANTHROPIC_API_KEY")) return "key";
|
|
@@ -13914,7 +14077,6 @@ async function dispatchAssistantRoute(req, res, ctx) {
|
|
|
13914
14077
|
hasAnthropicKey,
|
|
13915
14078
|
hasOpenaiKey,
|
|
13916
14079
|
hasElevenlabsKey,
|
|
13917
|
-
hasClaudeAuth: await hasClaudeAuth(db),
|
|
13918
14080
|
claudeAuthKind: await claudeAuthKind(db),
|
|
13919
14081
|
hasVoiceKey: voice !== null,
|
|
13920
14082
|
sttProvider: voice?.provider ?? null,
|
|
@@ -14042,13 +14204,17 @@ async function dispatchAssistantRoute(req, res, ctx) {
|
|
|
14042
14204
|
const verifier = generatePkceVerifier();
|
|
14043
14205
|
const state2 = generateState();
|
|
14044
14206
|
const cookieOpts = "HttpOnly; Path=/; Max-Age=600; SameSite=Lax";
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
|
|
14048
|
-
|
|
14049
|
-
|
|
14050
|
-
|
|
14051
|
-
|
|
14207
|
+
const setCookie = [
|
|
14208
|
+
`lat_oauth_verifier=${verifier}; ${cookieOpts}`,
|
|
14209
|
+
`lat_oauth_state=${state2}; ${cookieOpts}`
|
|
14210
|
+
];
|
|
14211
|
+
const authorizeUrl = buildAuthorizeUrl(cfg, state2, pkceChallengeFor(verifier));
|
|
14212
|
+
if ((req.headers.accept ?? "").includes("application/json")) {
|
|
14213
|
+
res.writeHead(200, { "Content-Type": "application/json", "Set-Cookie": setCookie });
|
|
14214
|
+
res.end(JSON.stringify({ authorizeUrl }));
|
|
14215
|
+
return true;
|
|
14216
|
+
}
|
|
14217
|
+
res.writeHead(302, { Location: authorizeUrl, "Set-Cookie": setCookie });
|
|
14052
14218
|
res.end();
|
|
14053
14219
|
return true;
|
|
14054
14220
|
}
|
|
@@ -16115,7 +16281,7 @@ var init_extract = __esm({
|
|
|
16115
16281
|
});
|
|
16116
16282
|
|
|
16117
16283
|
// src/ai/llm-client.ts
|
|
16118
|
-
import { createRequire as
|
|
16284
|
+
import { createRequire as createRequire5 } from "module";
|
|
16119
16285
|
var DEFAULT_MODEL;
|
|
16120
16286
|
var init_llm_client = __esm({
|
|
16121
16287
|
"src/ai/llm-client.ts"() {
|
|
@@ -16669,7 +16835,7 @@ var init_url_safety = __esm({
|
|
|
16669
16835
|
import { JSDOM } from "jsdom";
|
|
16670
16836
|
import { Readability } from "@mozilla/readability";
|
|
16671
16837
|
import { basename as basename5 } from "path";
|
|
16672
|
-
import { createRequire as
|
|
16838
|
+
import { createRequire as createRequire6 } from "module";
|
|
16673
16839
|
async function crawlUrl(rawUrl, opts = {}) {
|
|
16674
16840
|
const u2 = await assertSafeUrl(rawUrl, opts.allowPrivate ?? false);
|
|
16675
16841
|
const fetchImpl = opts.fetcher ?? fetch;
|
|
@@ -16916,7 +17082,7 @@ async function renderViaPlaywright(url, timeoutMs, warnIfMissing = false) {
|
|
|
16916
17082
|
let chromium;
|
|
16917
17083
|
try {
|
|
16918
17084
|
const importMetaUrl = import.meta.url;
|
|
16919
|
-
const req = importMetaUrl ?
|
|
17085
|
+
const req = importMetaUrl ? createRequire6(importMetaUrl) : __require;
|
|
16920
17086
|
const pw = req("playwright");
|
|
16921
17087
|
chromium = pw.chromium;
|
|
16922
17088
|
} catch {
|
|
@@ -17847,7 +18013,7 @@ var init_tools = __esm({
|
|
|
17847
18013
|
});
|
|
17848
18014
|
|
|
17849
18015
|
// src/gui/ai/chat.ts
|
|
17850
|
-
import { createRequire as
|
|
18016
|
+
import { createRequire as createRequire7 } from "module";
|
|
17851
18017
|
function capToolResult(s2) {
|
|
17852
18018
|
if (s2.length <= MAX_TOOL_RESULT_CHARS) return s2;
|
|
17853
18019
|
if (s2.length > MAX_TOOL_RESULT_SKIP)
|
|
@@ -18080,7 +18246,7 @@ async function* runChat(opts) {
|
|
|
18080
18246
|
function loadSdk() {
|
|
18081
18247
|
if (!_sdk) {
|
|
18082
18248
|
const importMetaUrl = import.meta.url;
|
|
18083
|
-
const req = importMetaUrl ?
|
|
18249
|
+
const req = importMetaUrl ? createRequire7(importMetaUrl) : __require;
|
|
18084
18250
|
try {
|
|
18085
18251
|
_sdk = req("@anthropic-ai/sdk");
|
|
18086
18252
|
} catch (err) {
|
|
@@ -58435,12 +58601,12 @@ init_postgres();
|
|
|
58435
58601
|
|
|
58436
58602
|
// src/gui/realtime.ts
|
|
58437
58603
|
import { EventEmitter } from "events";
|
|
58438
|
-
import { createRequire as
|
|
58604
|
+
import { createRequire as createRequire4 } from "module";
|
|
58439
58605
|
var _pgModule = null;
|
|
58440
58606
|
function loadPg() {
|
|
58441
58607
|
if (_pgModule) return _pgModule;
|
|
58442
58608
|
const importMetaUrl = import.meta.url;
|
|
58443
|
-
const requireFromHere = importMetaUrl ?
|
|
58609
|
+
const requireFromHere = importMetaUrl ? createRequire4(importMetaUrl) : (
|
|
58444
58610
|
// CJS fallback — Node provides `require` on every CJS module scope.
|
|
58445
58611
|
__require
|
|
58446
58612
|
);
|
|
@@ -61799,6 +61965,20 @@ var displayConfigJs = `
|
|
|
61799
61965
|
});
|
|
61800
61966
|
}
|
|
61801
61967
|
|
|
61968
|
+
// SINGLE SOURCE OF TRUTH for the assistant's Claude connection state, derived
|
|
61969
|
+
// from /api/assistant/config's claudeAuthKind (oauth | key | null). EVERY
|
|
61970
|
+
// place that shows "Connected with Claude" / opens the API-key panel / gates
|
|
61971
|
+
// on "the assistant has auth" MUST go through this \u2014 never re-derive from raw
|
|
61972
|
+
// fields, or the signals disagree (a stray "or hasAnthropicKey" once made
|
|
61973
|
+
// onboarding show "Connected with Claude" for an API-key-only setup while the
|
|
61974
|
+
// settings panel showed not-connected).
|
|
61975
|
+
// .oauth -> a Claude SUBSCRIPTION is connected ("Connected with Claude")
|
|
61976
|
+
// .any -> some working auth exists (subscription OR API key)
|
|
61977
|
+
function claudeAuth(cfg) {
|
|
61978
|
+
var kind = (cfg && cfg.claudeAuthKind) || null; // 'oauth' | 'key' | null
|
|
61979
|
+
return { kind: kind, oauth: kind === 'oauth', any: kind != null };
|
|
61980
|
+
}
|
|
61981
|
+
|
|
61802
61982
|
// Disable a button + show an inline spinner for the duration of an
|
|
61803
61983
|
// async action so a slow server round-trip can't be double-clicked.
|
|
61804
61984
|
// The fn arg should return a Promise; the button is restored on settle.
|
|
@@ -62589,7 +62769,12 @@ var offlineEditQueueJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
|
|
|
62589
62769
|
if (eventStreamClosed) return;
|
|
62590
62770
|
// Unexpected drop: show the disconnect on the pill and auto-reconnect with
|
|
62591
62771
|
// backoff (the server replays state + render snapshot on reconnect).
|
|
62592
|
-
|
|
62772
|
+
// Preserve the KNOWN mode (cloudMode is the single source of truth, set
|
|
62773
|
+
// from the server's realtime-state message) \u2014 never hardcode 'cloud',
|
|
62774
|
+
// which on a LOCAL (SQLite) workspace would flip cloudMode=true and divert
|
|
62775
|
+
// writes into the offline queue with a bogus "will sync when cloud
|
|
62776
|
+
// reconnects" toast against a workspace that has no cloud.
|
|
62777
|
+
setStatusPill(cloudMode ? 'cloud' : 'local', 'disconnected');
|
|
62593
62778
|
scheduleEventStreamReconnect();
|
|
62594
62779
|
};
|
|
62595
62780
|
}
|
|
@@ -66497,7 +66682,7 @@ var rowContextJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
|
|
|
66497
66682
|
var cfg = res[1];
|
|
66498
66683
|
st.name = (id && id.display_name) || '';
|
|
66499
66684
|
st.email = (id && id.email) || '';
|
|
66500
|
-
st.connected =
|
|
66685
|
+
st.connected = claudeAuth(cfg).oauth;
|
|
66501
66686
|
if (!st.wsName && st.name) st.wsName = st.name + "'s Workspace";
|
|
66502
66687
|
render();
|
|
66503
66688
|
});
|
|
@@ -67158,7 +67343,7 @@ var dataModelJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
67158
67343
|
'</p>' +
|
|
67159
67344
|
// Connect-with-Claude is the primary path (use your subscription, no
|
|
67160
67345
|
// API key). A pasted API key is demoted to an "Advanced" disclosure.
|
|
67161
|
-
(cfg.
|
|
67346
|
+
(claudeAuth(cfg).oauth
|
|
67162
67347
|
? '<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">' +
|
|
67163
67348
|
'<span class="feed-source" style="background:var(--accent-soft);color:var(--accent)">Connected with Claude</span>' +
|
|
67164
67349
|
'<button id="asst-oauth-disconnect" class="btn">Disconnect</button>' +
|
|
@@ -67180,7 +67365,7 @@ var dataModelJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
|
67180
67365
|
'</div>' +
|
|
67181
67366
|
'<div id="connect-claude-msg" style="margin-top:6px;font-size:12px;color:var(--text-muted)"></div>' +
|
|
67182
67367
|
'</div>') +
|
|
67183
|
-
'<details style="margin-bottom:12px"' + (cfg.
|
|
67368
|
+
'<details style="margin-bottom:12px"' + (claudeAuth(cfg).kind === 'key' ? ' open' : '') + '>' +
|
|
67184
67369
|
'<summary style="cursor:pointer;font-size:12px;color:var(--text-muted)">Advanced \u2014 use an API key instead</summary>' +
|
|
67185
67370
|
'<div style="margin-top:8px">' +
|
|
67186
67371
|
rowHtml('asst-anthropic', 'Claude API token (chat)', !!cfg.hasAnthropicKey, 'sk-ant-\u2026') +
|
|
@@ -69172,7 +69357,7 @@ var createDatabaseWizardJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\
|
|
|
69172
69357
|
function renderComposer() {
|
|
69173
69358
|
var host = document.getElementById('rail-composer'); if (!host) return;
|
|
69174
69359
|
fetchJson('/api/assistant/config').then(function (cfg) {
|
|
69175
|
-
if (cfg
|
|
69360
|
+
if (claudeAuth(cfg).any) {
|
|
69176
69361
|
var micHtml = cfg.hasVoiceKey
|
|
69177
69362
|
? '<button class="composer-mic" id="chat-mic" title="Record voice">\u{1F399}</button>'
|
|
69178
69363
|
: '';
|
|
@@ -72097,7 +72282,7 @@ import { basename as basename11, extname as extname2, resolve as resolve11, join
|
|
|
72097
72282
|
|
|
72098
72283
|
// src/ai/vision.ts
|
|
72099
72284
|
init_llm_client();
|
|
72100
|
-
import { createRequire as
|
|
72285
|
+
import { createRequire as createRequire8 } from "module";
|
|
72101
72286
|
import { readFile as readFile8 } from "fs/promises";
|
|
72102
72287
|
var DEFAULT_PROMPT = "Describe this image for a knowledge base in 2-4 factual sentences: what it shows, any visible text, and notable details. No preamble.";
|
|
72103
72288
|
var MAX_DIM = 1568;
|
|
@@ -72159,7 +72344,7 @@ function buildVisionAnthropicConfig(auth) {
|
|
|
72159
72344
|
function defaultSender(auth) {
|
|
72160
72345
|
return async (input) => {
|
|
72161
72346
|
const importMetaUrl = import.meta.url;
|
|
72162
|
-
const req = importMetaUrl ?
|
|
72347
|
+
const req = importMetaUrl ? createRequire8(importMetaUrl) : __require;
|
|
72163
72348
|
const sdk = req("@anthropic-ai/sdk");
|
|
72164
72349
|
const Anthropic = sdk.Anthropic ?? sdk.default;
|
|
72165
72350
|
if (!Anthropic) throw new Error("Could not resolve Anthropic from '@anthropic-ai/sdk'");
|
|
@@ -72186,7 +72371,7 @@ function defaultSender(auth) {
|
|
|
72186
72371
|
function defaultPdfSender(auth) {
|
|
72187
72372
|
return async (input) => {
|
|
72188
72373
|
const importMetaUrl = import.meta.url;
|
|
72189
|
-
const req = importMetaUrl ?
|
|
72374
|
+
const req = importMetaUrl ? createRequire8(importMetaUrl) : __require;
|
|
72190
72375
|
const sdk = req("@anthropic-ai/sdk");
|
|
72191
72376
|
const Anthropic = sdk.Anthropic ?? sdk.default;
|
|
72192
72377
|
if (!Anthropic) throw new Error("Could not resolve Anthropic from '@anthropic-ai/sdk'");
|
|
@@ -75871,6 +76056,7 @@ async function startGuiServer(options) {
|
|
|
75871
76056
|
}
|
|
75872
76057
|
const autoRender = options.autoRender ?? false;
|
|
75873
76058
|
const guiVersion = options.version ?? "";
|
|
76059
|
+
const desktopOpenExternal = options.desktopOpenExternal;
|
|
75874
76060
|
const sessionId = crypto.randomUUID();
|
|
75875
76061
|
let updateService = null;
|
|
75876
76062
|
let activeRef = bootConfigPath && bootOutputDir ? await openConfig(bootConfigPath, bootOutputDir, autoRender, options.realtimeWatchdogMs) : null;
|
|
@@ -76053,6 +76239,20 @@ async function startGuiServer(options) {
|
|
|
76053
76239
|
sendJson(res, { version: guiVersion });
|
|
76054
76240
|
return;
|
|
76055
76241
|
}
|
|
76242
|
+
if (method === "GET" && pathname === "/api/desktop/open") {
|
|
76243
|
+
if (!desktopOpenExternal) {
|
|
76244
|
+
sendJson(res, { error: "not found" }, 404);
|
|
76245
|
+
return;
|
|
76246
|
+
}
|
|
76247
|
+
const target = new URL(req.url ?? "", "http://localhost").searchParams.get("url");
|
|
76248
|
+
if (!target || !/^https?:\/\//i.test(target)) {
|
|
76249
|
+
sendJson(res, { error: "url must be http(s)" }, 400);
|
|
76250
|
+
return;
|
|
76251
|
+
}
|
|
76252
|
+
desktopOpenExternal(target);
|
|
76253
|
+
sendJson(res, { ok: true });
|
|
76254
|
+
return;
|
|
76255
|
+
}
|
|
76056
76256
|
if (method === "GET" && pathname === "/api/update/status") {
|
|
76057
76257
|
sendJson(
|
|
76058
76258
|
res,
|
|
@@ -76738,7 +76938,7 @@ function printHelp() {
|
|
|
76738
76938
|
);
|
|
76739
76939
|
}
|
|
76740
76940
|
function getVersion() {
|
|
76741
|
-
if (true) return "4.2.
|
|
76941
|
+
if (true) return "4.2.4";
|
|
76742
76942
|
try {
|
|
76743
76943
|
const pkgPath = new URL("../package.json", import.meta.url).pathname;
|
|
76744
76944
|
const pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
|