stacks-ai 0.1.2 → 0.2.5

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.
@@ -0,0 +1,9 @@
1
+ import{g}from"./index-CHhe65ps.js";import{c as h,o as y,a as m}from"./index-D0ZoqtYh.js";const r={},p=t=>{const e={anthropic:"anthropic-api-key",openai:"openai-api-key",google:"gemini-api-key"},a=localStorage.getItem(e[t]);return a||{anthropic:r==null?void 0:r.VITE_ANTHROPIC_API_KEY,openai:r==null?void 0:r.VITE_OPENAI_API_KEY,google:r==null?void 0:r.VITE_GEMINI_API_KEY}[t]||""},u=async t=>{const a=await(await fetch(t)).blob();return new Promise((o,l)=>{const n=new FileReader;n.onloadend=()=>{const c=n.result,[,s]=c.split(",");o({data:s,mimeType:a.type})},n.onerror=l,n.readAsDataURL(a)})},P=async(t,e)=>{const a=(e==null?void 0:e.provider)||localStorage.getItem("ai-provider")||"google",o=p(a);if(!o)throw new Error(`${a} API key not configured. Please add your API key in Settings → Providers.`);const{data:l,mimeType:n}=await u(t),c=localStorage.getItem("image-analysis-model");let s;switch(a){case"anthropic":s=m((e==null?void 0:e.model)||c||"claude-sonnet-4-5-20250929",{apiKey:o});break;case"openai":s=y((e==null?void 0:e.model)||c||"gpt-4o",{apiKey:o});break;case"google":{s=h({apiKey:o})((e==null?void 0:e.model)||c||"gemini-2.0-flash-exp");break}default:throw new Error(`Unknown provider: ${a}`)}const d=(await g({model:s,messages:[{role:"user",content:[{type:"image",image:`data:${n};base64,${l}`},{type:"text",text:`Analyze this image and provide:
2
+ 1. A one-sentence description of what you see
3
+ 2. The 6 most dominant colors as hex codes
4
+
5
+ Format your response as JSON:
6
+ {
7
+ "description": "Your one-sentence description",
8
+ "colors": ["#hex1", "#hex2", "#hex3", "#hex4", "#hex5", "#hex6"]
9
+ }`}]}]})).text.match(/\{[\s\S]*\}/);return d?JSON.parse(d[0]):{description:"Unable to analyze image",colors:[]}};export{P as analyzeImageWithVision};
package/dist/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
6
  <title>Stacks</title>
7
- <script type="module" crossorigin src="./assets/index-dFjja42D.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-Q3CD-OmM.css">
7
+ <script type="module" crossorigin src="./assets/index-DRYEX6gr.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-BWvx7AMq.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root" style="width: 100%; height: 100%;"></div>
package/dist/mcp/proxy.js CHANGED
@@ -7,22 +7,26 @@
7
7
  */
8
8
  import { WebSocketServer } from "ws";
9
9
  import { spawn } from "child_process";
10
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
10
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from "fs";
11
11
  import { homedir } from "os";
12
12
  import { join } from "path";
13
- // Config paths
14
13
  const configDir = join(homedir(), ".stacks");
14
+ const legacyConfigDir = join(homedir(), ".spatial");
15
15
  const configPath = join(configDir, "mcp-proxy-config.json");
16
+ const legacyConfigPath = join(legacyConfigDir, "mcp-proxy-config.json");
16
17
  // Default config
17
18
  const DEFAULT_CONFIG = {
18
19
  port: 3099,
19
20
  servers: {}
20
21
  };
21
- // Load/save config
22
22
  function loadConfig() {
23
23
  if (!existsSync(configDir)) {
24
24
  mkdirSync(configDir, { recursive: true });
25
25
  }
26
+ if (existsSync(legacyConfigPath) && !existsSync(configPath)) {
27
+ copyFileSync(legacyConfigPath, configPath);
28
+ console.log("Migrated MCP config from ~/.spatial to ~/.stacks");
29
+ }
26
30
  if (!existsSync(configPath)) {
27
31
  writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
28
32
  return DEFAULT_CONFIG;
@@ -3,15 +3,22 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
5
  import Database from "better-sqlite3";
6
- import { existsSync, mkdirSync } from "fs";
6
+ import { existsSync, mkdirSync, copyFileSync } from "fs";
7
7
  import { homedir } from "os";
8
8
  import { join } from "path";
9
- // Database setup
10
- const dataDir = join(homedir(), ".stacks");
11
- if (!existsSync(dataDir)) {
12
- mkdirSync(dataDir, { recursive: true });
9
+ const newDataDir = join(homedir(), ".stacks");
10
+ const legacyDataDir = join(homedir(), ".spatial");
11
+ const legacyDbPath = join(legacyDataDir, "canvas.db");
12
+ const newDbPath = join(newDataDir, "canvas.db");
13
+ if (!existsSync(newDataDir)) {
14
+ mkdirSync(newDataDir, { recursive: true });
13
15
  }
14
- const db = new Database(join(dataDir, "canvas.db"));
16
+ if (existsSync(legacyDbPath) && !existsSync(newDbPath)) {
17
+ copyFileSync(legacyDbPath, newDbPath);
18
+ console.error("Migrated database from ~/.spatial to ~/.stacks");
19
+ }
20
+ const dataDir = newDataDir;
21
+ const db = new Database(newDbPath);
15
22
  // Initialize schema
16
23
  db.exec(`
17
24
  CREATE TABLE IF NOT EXISTS spaces (
package/electron/main.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const { app, BrowserWindow } = require('electron')
1
+ const { app, BrowserWindow, nativeImage } = require('electron')
2
2
  const { spawn } = require('child_process')
3
3
  const path = require('path')
4
4
  const net = require('net')
@@ -6,6 +6,9 @@ const fs = require('fs')
6
6
 
7
7
  // Set app name for macOS menu
8
8
  app.name = 'Stacks'
9
+ if (process.platform === 'darwin') {
10
+ app.setName('Stacks')
11
+ }
9
12
 
10
13
  const isDev = process.env.NODE_ENV === 'development'
11
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stacks-ai",
3
- "version": "0.1.2",
3
+ "version": "0.2.5",
4
4
  "description": "Stacks - AI-powered infinite canvas for notes, images, and creative organization",
5
5
  "author": "Jason Kneen",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- import{s as g}from"./index-C1agmKFP.js";import{c as s,o as c,a as y}from"./index-C8w_QbzK.js";const t={},i=e=>{const r={anthropic:"anthropic-api-key",openai:"openai-api-key",google:"gemini-api-key"}[e],o=localStorage.getItem(r);return console.log(`[aiProvider] Getting API key for ${e}:`,{keyName:r,hasKey:!!o,keyLength:(o==null?void 0:o.length)||0,keyPreview:o?`${o.substring(0,10)}...`:"none"}),o||{anthropic:t==null?void 0:t.VITE_ANTHROPIC_API_KEY,openai:t==null?void 0:t.VITE_OPENAI_API_KEY,google:t==null?void 0:t.VITE_GEMINI_API_KEY}[e]||""},h=e=>{const a=e.apiKey||i(e.provider);if(console.log("[aiProvider] getLanguageModel called:",{provider:e.provider,model:e.model,hasApiKey:!!a,apiKeyLength:(a==null?void 0:a.length)||0,configApiKey:!!e.apiKey}),!a)throw new Error(`${e.provider} API key not configured. Please add your API key in Settings → Providers.`);switch(e.provider){case"anthropic":return y(e.model||"claude-sonnet-4-5-20250929",{apiKey:a});case"openai":return c(e.model||"gpt-4o",{apiKey:a});case"google":return s({apiKey:a})(e.model||"gemini-2.0-flash-exp");default:throw new Error(`Unknown provider: ${e.provider}`)}},I=async(e,a,r)=>{const o=(r==null?void 0:r.provider)||"google",l=h({provider:o,model:r==null?void 0:r.model}),n=await g({model:l,system:r==null?void 0:r.systemPrompt,prompt:e});for await(const d of n.textStream)a(d)};export{I as generateTextStream,h as getLanguageModel};