volute 0.24.0 → 0.25.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 (40) hide show
  1. package/dist/api.d.ts +113 -4
  2. package/dist/{chunk-4TJ72QQ3.js → chunk-BOTQ25QT.js} +1 -1
  3. package/dist/{chunk-P3W36ZGD.js → chunk-DG7TO7EE.js} +30 -2
  4. package/dist/{chunk-OOW675I3.js → chunk-PMX4EIJK.js} +39 -20
  5. package/dist/{chunk-NOBRGACV.js → chunk-SHSWYG2J.js} +1 -1
  6. package/dist/{chunk-XLC342FO.js → chunk-SIAG3QMM.js} +14 -1
  7. package/dist/cli.js +6 -6
  8. package/dist/{cloud-sync-DIU3OCPV.js → cloud-sync-PPBBJDY6.js} +3 -3
  9. package/dist/{daemon-restart-YMPEATQH.js → daemon-restart-FDNOZEAD.js} +1 -1
  10. package/dist/daemon.js +453 -239
  11. package/dist/{import-FRDPQPJ2.js → import-TH26J76F.js} +2 -2
  12. package/dist/{message-delivery-S7BCNV6Y.js → message-delivery-XMGV3FUM.js} +3 -3
  13. package/dist/{mind-KPLCRKQA.js → mind-YVWAHL2A.js} +2 -2
  14. package/dist/{mind-manager-ZNRIYEK3.js → mind-manager-4NDNAYAB.js} +1 -1
  15. package/dist/{package-S5YF25XV.js → package-3HF5MXU2.js} +2 -1
  16. package/dist/{pages-TWR6U7DS.js → pages-Y6DRWUOJ.js} +1 -1
  17. package/dist/{publish-BZNHKUUK.js → publish-EEKTZBHW.js} +1 -1
  18. package/dist/{skill-BQOFACEI.js → skill-T3EMR6IR.js} +10 -2
  19. package/dist/skills/imagegen/SKILL.md +37 -0
  20. package/dist/skills/imagegen/references/INSTALL.md +13 -0
  21. package/dist/skills/imagegen/scripts/imagegen.ts +136 -0
  22. package/dist/skills/resonance/SKILL.md +73 -0
  23. package/dist/skills/resonance/assets/default-config.json +21 -0
  24. package/dist/skills/resonance/references/INSTALL.md +23 -0
  25. package/dist/skills/resonance/scripts/resonance.ts +1250 -0
  26. package/dist/skills/volute-mind/SKILL.md +23 -3
  27. package/dist/{sleep-manager-XXSWQQLE.js → sleep-manager-RKTFZPD3.js} +3 -3
  28. package/dist/{sprout-CGSW4CF5.js → sprout-QJVGJDSH.js} +1 -1
  29. package/dist/{up-OMHACRJL.js → up-CJ26KQLN.js} +1 -1
  30. package/dist/{version-notify-SZ75QRGO.js → version-notify-AZQMC32A.js} +3 -3
  31. package/dist/web-assets/assets/index-CGPSVu19.js +69 -0
  32. package/dist/web-assets/assets/index-V_rNDsM8.css +1 -0
  33. package/dist/web-assets/favicon.png +0 -0
  34. package/dist/web-assets/index.html +5 -4
  35. package/dist/web-assets/logo.png +0 -0
  36. package/package.json +2 -1
  37. package/templates/_base/home/public/.gitkeep +0 -0
  38. package/dist/web-assets/assets/index-Bx9WDoaQ.js +0 -69
  39. package/dist/web-assets/assets/index-Clz8OhmJ.css +0 -1
  40. /package/dist/{chunk-TQDITGES.js → chunk-ZSH4G2P5.js} +0 -0
@@ -6,8 +6,8 @@ import {
6
6
  parseNameFromIdentity,
7
7
  run,
8
8
  sessionMatchesWorkspace
9
- } from "./chunk-4TJ72QQ3.js";
10
- import "./chunk-XLC342FO.js";
9
+ } from "./chunk-BOTQ25QT.js";
10
+ import "./chunk-SIAG3QMM.js";
11
11
  import "./chunk-PHU4DEAJ.js";
12
12
  import "./chunk-D424ZQGI.js";
13
13
  import "./chunk-B2CPS4QU.js";
@@ -3,12 +3,12 @@ import {
3
3
  deliverMessage,
4
4
  extractTextContent,
5
5
  recordInbound
6
- } from "./chunk-OOW675I3.js";
6
+ } from "./chunk-PMX4EIJK.js";
7
7
  import "./chunk-HFCBO2GL.js";
8
8
  import "./chunk-E7GOKNOT.js";
9
9
  import "./chunk-BFK6SOEJ.js";
10
- import "./chunk-NOBRGACV.js";
11
- import "./chunk-XLC342FO.js";
10
+ import "./chunk-SHSWYG2J.js";
11
+ import "./chunk-SIAG3QMM.js";
12
12
  import "./chunk-PHU4DEAJ.js";
13
13
  import "./chunk-33XAVCS4.js";
14
14
  import "./chunk-YUIHSKR6.js";
@@ -41,7 +41,7 @@ async function run(args) {
41
41
  await import("./upgrade-7RUIXGOO.js").then((m) => m.run(args.slice(1)));
42
42
  break;
43
43
  case "import":
44
- await import("./import-FRDPQPJ2.js").then((m) => m.run(args.slice(1)));
44
+ await import("./import-TH26J76F.js").then((m) => m.run(args.slice(1)));
45
45
  break;
46
46
  case "export":
47
47
  await import("./export-IKFAPRAO.js").then((m) => m.run(args.slice(1)));
@@ -56,7 +56,7 @@ async function run(args) {
56
56
  await import("./seed-6FEKB3YC.js").then((m) => m.run(args.slice(1)));
57
57
  break;
58
58
  case "sprout":
59
- await import("./sprout-CGSW4CF5.js").then((m) => m.run(args.slice(1)));
59
+ await import("./sprout-QJVGJDSH.js").then((m) => m.run(args.slice(1)));
60
60
  break;
61
61
  case "sleep":
62
62
  await import("./mind-sleep-GHPTSAYN.js").then((m) => m.run(args.slice(1)));
@@ -3,7 +3,7 @@ import {
3
3
  MindManager,
4
4
  getMindManager,
5
5
  initMindManager
6
- } from "./chunk-NOBRGACV.js";
6
+ } from "./chunk-SHSWYG2J.js";
7
7
  import "./chunk-PHU4DEAJ.js";
8
8
  import "./chunk-33XAVCS4.js";
9
9
  import "./chunk-YUIHSKR6.js";
@@ -4,7 +4,7 @@ import "./chunk-K3NQKI34.js";
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "volute",
7
- version: "0.24.0",
7
+ version: "0.25.0",
8
8
  description: "CLI for creating and managing self-modifying AI minds powered by the Claude Agent SDK",
9
9
  type: "module",
10
10
  license: "MIT",
@@ -86,6 +86,7 @@ var package_default = {
86
86
  dompurify: "^3.3.1",
87
87
  "drizzle-kit": "^0.31.8",
88
88
  lefthook: "^2.1.0",
89
+ libsql: "^0.5.22",
89
90
  marked: "^17.0.1",
90
91
  svelte: "^5.53.0",
91
92
  tsup: "^8.0.0",
@@ -6,7 +6,7 @@ async function run(args) {
6
6
  const subcommand = args[0];
7
7
  switch (subcommand) {
8
8
  case "publish":
9
- await import("./publish-BZNHKUUK.js").then((m) => m.run(args.slice(1)));
9
+ await import("./publish-EEKTZBHW.js").then((m) => m.run(args.slice(1)));
10
10
  break;
11
11
  case "status":
12
12
  await import("./status-LV34BG6G.js").then((m) => m.run(args.slice(1)));
@@ -42,7 +42,7 @@ async function run(args) {
42
42
  pagesDir = resolve(sharedDir(), "pages");
43
43
  } else if (flags.mind || process.env.VOLUTE_MIND) {
44
44
  mindName = resolveMindName(flags);
45
- pagesDir = resolve(mindDir(mindName), "home", "pages");
45
+ pagesDir = resolve(mindDir(mindName), "home", "public", "pages");
46
46
  } else {
47
47
  mindName = "system";
48
48
  pagesDir = resolve(sharedDir(), "pages");
@@ -146,11 +146,19 @@ async function installSkill(args) {
146
146
  body: JSON.stringify({ skillId })
147
147
  });
148
148
  if (!res.ok) {
149
- const body = await res.json().catch(() => ({ error: "Unknown error" }));
150
- console.error(`Error: ${body.error}`);
149
+ const body2 = await res.json().catch(() => ({ error: "Unknown error" }));
150
+ console.error(`Error: ${body2.error}`);
151
151
  process.exit(1);
152
152
  }
153
+ const body = await res.json().catch(() => ({}));
153
154
  console.log(`Installed skill "${skillId}" into ${mindName}.`);
155
+ if (body.npmInstalled?.length) {
156
+ console.log(`Installed npm dependencies: ${body.npmInstalled.join(", ")}`);
157
+ }
158
+ if (body.installNotes) {
159
+ console.log("");
160
+ console.log(body.installNotes);
161
+ }
154
162
  }
155
163
  async function updateSkill(args) {
156
164
  const { positional, flags } = parseArgs(args, {
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: Image Generation
3
+ description: Generate images via the Replicate API. Use for "generate image", "create image", "image generation", "text to image", "search image models".
4
+ metadata:
5
+ npm-dependencies: replicate
6
+ ---
7
+
8
+ # Image Generation
9
+
10
+ Generate images from text prompts using models on Replicate. Images are saved to `home/images/`.
11
+
12
+ ## Commands
13
+
14
+ ```bash
15
+ npx tsx .claude/skills/imagegen/scripts/imagegen.ts <command>
16
+ ```
17
+
18
+ | Command | Description |
19
+ |---------|-------------|
20
+ | `generate "prompt" [--model M] [--filename F]` | Generate an image from a text prompt. Default model: `prunaai/z-image-turbo`. |
21
+ | `models "query"` | Search Replicate for text-to-image models. |
22
+
23
+ ## Examples
24
+
25
+ ```bash
26
+ # Generate an image with the default model
27
+ npx tsx .claude/skills/imagegen/scripts/imagegen.ts generate "a sunset over the ocean"
28
+
29
+ # Use a specific model
30
+ npx tsx .claude/skills/imagegen/scripts/imagegen.ts generate "a cat in space" --model black-forest-labs/flux-schnell
31
+
32
+ # Specify a filename
33
+ npx tsx .claude/skills/imagegen/scripts/imagegen.ts generate "mountain landscape" --filename mountains
34
+
35
+ # Search for models
36
+ npx tsx .claude/skills/imagegen/scripts/imagegen.ts models "text to image"
37
+ ```
@@ -0,0 +1,13 @@
1
+ # Image Generation — Post-Install Setup
2
+
3
+ Set your Replicate API token:
4
+
5
+ ```bash
6
+ volute env set REPLICATE_API_TOKEN <your-token>
7
+ ```
8
+
9
+ Then generate images:
10
+
11
+ ```bash
12
+ npx tsx .claude/skills/imagegen/scripts/imagegen.ts generate "a sunset over the ocean"
13
+ ```
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env tsx
2
+
3
+ /**
4
+ * imagegen.ts — image generation via Replicate API
5
+ *
6
+ * Usage:
7
+ * imagegen generate "prompt" [--model M] [--filename F] # generate an image
8
+ * imagegen models "query" # search for models
9
+ */
10
+
11
+ import { mkdirSync } from "node:fs";
12
+ import { writeFile } from "node:fs/promises";
13
+ import { createRequire } from "node:module";
14
+ import { join, resolve } from "node:path";
15
+
16
+ const replicateRequire = createRequire(import.meta.url);
17
+
18
+ function getHomePath(): string {
19
+ const mindDir = process.env.VOLUTE_MIND_DIR;
20
+ if (!mindDir) throw new Error("VOLUTE_MIND_DIR not set");
21
+ return join(mindDir, "home");
22
+ }
23
+
24
+ function slugify(text: string): string {
25
+ return text
26
+ .toLowerCase()
27
+ .replace(/[^a-z0-9]+/g, "-")
28
+ .replace(/^-|-$/g, "")
29
+ .slice(0, 60);
30
+ }
31
+
32
+ function getFlag(args: string[], flag: string): string | undefined {
33
+ const idx = args.indexOf(flag);
34
+ if (idx !== -1 && args[idx + 1]) return args[idx + 1];
35
+ return undefined;
36
+ }
37
+
38
+ async function generate(args: string[]): Promise<void> {
39
+ const prompt = args[0];
40
+ if (!prompt) {
41
+ console.log('Usage: imagegen generate "prompt" [--model M] [--filename F]');
42
+ process.exit(1);
43
+ }
44
+
45
+ if (!process.env.REPLICATE_API_TOKEN) {
46
+ console.error(
47
+ "REPLICATE_API_TOKEN not set. Run: volute env set REPLICATE_API_TOKEN <your-token>",
48
+ );
49
+ process.exit(1);
50
+ }
51
+
52
+ const model = getFlag(args, "--model") || "prunaai/z-image-turbo";
53
+ const filename = getFlag(args, "--filename") || slugify(prompt) || `image-${Date.now()}`;
54
+
55
+ const Replicate = replicateRequire("replicate");
56
+ const replicate = new Replicate();
57
+
58
+ console.log(`generating image with ${model}...`);
59
+ const output = await replicate.run(model, { input: { prompt } });
60
+
61
+ // Output can be a single FileOutput or an array of them
62
+ const file = Array.isArray(output) ? output[0] : output;
63
+ if (!file) {
64
+ console.error(`error: model ${model} returned no output`);
65
+ process.exit(1);
66
+ }
67
+
68
+ const imagesDir = join(getHomePath(), "images");
69
+ mkdirSync(imagesDir, { recursive: true });
70
+
71
+ const filePath = join(imagesDir, `${filename}.png`);
72
+ await writeFile(filePath, file);
73
+ console.log(`saved: ${filePath}`);
74
+ }
75
+
76
+ async function models(args: string[]): Promise<void> {
77
+ const query = args[0];
78
+ if (!query) {
79
+ console.log('Usage: imagegen models "query"');
80
+ process.exit(1);
81
+ }
82
+
83
+ if (!process.env.REPLICATE_API_TOKEN) {
84
+ console.error(
85
+ "REPLICATE_API_TOKEN not set. Run: volute env set REPLICATE_API_TOKEN <your-token>",
86
+ );
87
+ process.exit(1);
88
+ }
89
+
90
+ const Replicate = replicateRequire("replicate");
91
+ const replicate = new Replicate();
92
+
93
+ const response = await replicate.models.search(query);
94
+ const results = response.results.slice(0, 10);
95
+
96
+ if (results.length === 0) {
97
+ console.log("no models found.");
98
+ return;
99
+ }
100
+
101
+ for (const m of results) {
102
+ const desc = m.description ? ` — ${m.description.slice(0, 100)}` : "";
103
+ console.log(`${m.owner}/${m.name}${desc}`);
104
+ }
105
+ }
106
+
107
+ async function main() {
108
+ const args = process.argv.slice(2);
109
+ const cmd = args[0];
110
+
111
+ if (!cmd) {
112
+ console.log("Usage: imagegen <generate|models> [args]");
113
+ process.exit(0);
114
+ }
115
+
116
+ if (cmd === "generate") {
117
+ await generate(args.slice(1));
118
+ } else if (cmd === "models") {
119
+ await models(args.slice(1));
120
+ } else {
121
+ console.error(`unknown command: ${cmd}`);
122
+ process.exit(1);
123
+ }
124
+ }
125
+
126
+ const isDirectRun =
127
+ process.argv[1] !== undefined &&
128
+ (import.meta.url === `file://${process.argv[1]}` ||
129
+ import.meta.url === `file://${resolve(process.argv[1])}`);
130
+
131
+ if (isDirectRun) {
132
+ main().catch((err) => {
133
+ console.error(err);
134
+ process.exit(1);
135
+ });
136
+ }
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: Resonance
3
+ description: Semantic memory engine — ingest text, search via full-text and/or vector similarity, find cross-memory connections, with strength/decay dynamics. Use for "resonance", "semantic search", "full-text search", "memory connections", "ingest memories", "decay", "resonance report".
4
+ metadata:
5
+ npm-dependencies: libsql
6
+ ---
7
+
8
+ # Resonance — Semantic Memory Engine
9
+
10
+ Not an archive — a memory. Stores text chunks with full-text indexing and optional vector embeddings. Finds what echoes across time, tracks which memories keep surfacing, lets unused ones drift deeper.
11
+
12
+ ## When to use
13
+
14
+ - **During consolidation**: Run `resonance report` to find cross-day connections. Use these to inform what strengthens in MEMORY.md.
15
+ - **When writing**: After writing something significant, search for echoes: `resonance search "the theme you're exploring"`.
16
+ - **After writing journals/notes**: Run `resonance ingest <file>` to add new content.
17
+ - **Periodically**: Run `resonance ingest-all` to catch any new files.
18
+ - **Nightly**: Decay runs automatically if the nightly schedule was set up during install.
19
+
20
+ ## Commands
21
+
22
+ ```bash
23
+ npx tsx .claude/skills/resonance/scripts/resonance.ts <command>
24
+ ```
25
+
26
+ | Command | Description |
27
+ |---------|-------------|
28
+ | `install` | First-time setup: copies config, creates schedule, runs initial ingestion. API key optional — works with FTS only. |
29
+ | `ingest <file>` | Ingest a single file (with embeddings if API key set, FTS-only otherwise) |
30
+ | `ingest-all` | Ingest all configured memory files |
31
+ | `search "query" [--limit N] [--fts] [--vector]` | Find memories. Default: hybrid (vector + FTS). `--fts`: keyword only. `--vector`: semantic only. Read-only — does not affect memory strength. |
32
+ | `recall <id> [id2 ...]` | Explicitly boost memories that were genuinely useful. Increases strength and recall count. |
33
+ | `random [--limit N] [--min-strength F] [--max-strength F]` | Pull random memories. Use for dreams, associative connections, or serendipitous rediscovery. |
34
+ | `report [--against <file>]` | Find cross-memory connections (defaults to today's journal) |
35
+ | `stats` | Database statistics |
36
+ | `decay` | Run decay pass (reduces strength of unrecalled memories) |
37
+
38
+ ## Architecture
39
+
40
+ - **Storage**: libSQL database at `.mind/resonance.db` with native vector support (F32_BLOB) and FTS5 full-text index
41
+ - **Search modes**: Hybrid (default, combines both), `--fts` (keyword match, instant, no API key needed), `--vector` (semantic similarity via embeddings)
42
+ - **Embeddings**: Optional. Configurable provider (default: OpenRouter, `openai/text-embedding-3-small`, 1536 dimensions). Without an API key, everything works except vector search.
43
+ - **Similarity**: Cosine distance computed natively by libSQL (`vector_distance_cos`)
44
+ - **Chunking**: Markdown section-aware — splits on any heading level (`#` through `######`), with word-level sub-chunking for long sections. Skips trivially short chunks (< 15 words).
45
+ - **Strength**: Each memory has a strength value (0.1-1.0). Recalled memories get stronger (resonance boost). Unrecalled memories decay over time.
46
+ - **Resonance frequency**: Tracks how many times each memory has been surfaced by search.
47
+
48
+ ## Design principles
49
+
50
+ - **Connections, not facts.** "What else felt like this?" not "what happened on March 6."
51
+ - **Good resonance, not total recall.** Funes memorized everything and couldn't generalize.
52
+ - **Forgetting is cognition.** Memories decay. The decay is a feature.
53
+ - **Strength as texture.** A memory recalled five times feels different from one never touched.
54
+
55
+ ## Configuration
56
+
57
+ The default config is copied to `.config/resonance.json` during install. Edit it to customize. Fields are merged with built-in defaults.
58
+
59
+ | Section | Field | Default | Description |
60
+ |---------|-------|---------|-------------|
61
+ | `embedding` | `provider` | `"openrouter"` | Embedding API provider |
62
+ | `embedding` | `url` | OpenRouter URL | API endpoint |
63
+ | `embedding` | `model` | `"openai/text-embedding-3-small"` | Embedding model |
64
+ | `embedding` | `dimensions` | `1536` | Vector dimensions |
65
+ | `embedding` | `apiKeyEnvVar` | `"OPENROUTER_API_KEY"` | Env var name for API key |
66
+ | `ingestion` | `dirs` | `["memory/journal", "memory/reading", "memory/topics"]` | Directories to scan |
67
+ | `ingestion` | `files` | `["MEMORY.md"]` | Individual files to ingest |
68
+ | `ingestion` | `chunkSize` | `512` | Words per chunk |
69
+ | `ingestion` | `chunkOverlap` | `64` | Overlap words between chunks |
70
+ | `ingestion` | `ignorePatterns` | `[]` | Regex patterns for lines to skip during ingestion |
71
+ | `dynamics` | `decayRate` | `0.02` | Strength lost per day without recall |
72
+ | `dynamics` | `minStrength` | `0.1` | Floor — memories never fully disappear |
73
+ | `dynamics` | `resonanceBoost` | `0.05` | Strength gained per recall |
@@ -0,0 +1,21 @@
1
+ {
2
+ "embedding": {
3
+ "provider": "openrouter",
4
+ "url": "https://openrouter.ai/api/v1/embeddings",
5
+ "model": "openai/text-embedding-3-small",
6
+ "dimensions": 1536,
7
+ "apiKeyEnvVar": "OPENROUTER_API_KEY"
8
+ },
9
+ "ingestion": {
10
+ "dirs": ["memory/journal", "memory/reading", "memory/topics"],
11
+ "files": ["MEMORY.md"],
12
+ "chunkSize": 512,
13
+ "chunkOverlap": 64,
14
+ "ignorePatterns": []
15
+ },
16
+ "dynamics": {
17
+ "decayRate": 0.02,
18
+ "minStrength": 0.1,
19
+ "resonanceBoost": 0.05
20
+ }
21
+ }
@@ -0,0 +1,23 @@
1
+ # Resonance — Post-Install Setup
2
+
3
+ Run the install command to set up the database, create a nightly schedule, and run initial ingestion:
4
+
5
+ ```bash
6
+ npx tsx .claude/skills/resonance/scripts/resonance.ts install
7
+ ```
8
+
9
+ This works immediately — no API key required. Full-text search is available right away.
10
+
11
+ To also enable **vector search** (semantic similarity), set an embedding API key:
12
+
13
+ ```bash
14
+ volute env set OPENROUTER_API_KEY <your-key>
15
+ ```
16
+
17
+ Then re-run `ingest-all` to generate embeddings for existing memories:
18
+
19
+ ```bash
20
+ npx tsx .claude/skills/resonance/scripts/resonance.ts ingest-all
21
+ ```
22
+
23
+ Without an API key, `search` uses full-text matching. With one, it uses hybrid (vector + FTS) by default.