@sesamespace/hivemind 0.8.12 → 0.10.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.
- package/README.md +2 -1
- package/config/default.toml +18 -0
- package/dist/{chunk-NCJW2AOK.js → chunk-BHCDOHSK.js} +3 -3
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/{chunk-OVRYYS5I.js → chunk-DPLCEMEC.js} +2 -2
- package/dist/{chunk-XQZU3ULO.js → chunk-FBQBBAPZ.js} +2 -2
- package/dist/{chunk-XBJGLZ7V.js → chunk-FK6WYXRM.js} +79 -2
- package/dist/chunk-FK6WYXRM.js.map +1 -0
- package/dist/{chunk-LJHJGDKY.js → chunk-ICSJNKI6.js} +62 -2
- package/dist/chunk-ICSJNKI6.js.map +1 -0
- package/dist/{chunk-HDYEAKN5.js → chunk-IXBIAX76.js} +4 -34
- package/dist/chunk-IXBIAX76.js.map +1 -0
- package/dist/{chunk-OG6GPQDK.js → chunk-M3A2WRXM.js} +1765 -189
- package/dist/chunk-M3A2WRXM.js.map +1 -0
- package/dist/commands/fleet.js +4 -3
- package/dist/commands/init.js +4 -3
- package/dist/commands/service.js +1 -0
- package/dist/commands/start.js +4 -3
- package/dist/commands/upgrade.js +2 -1
- package/dist/commands/watchdog.js +4 -3
- package/dist/dashboard.html +873 -131
- package/dist/index.js +14 -5
- package/dist/main.js +376 -7
- package/dist/main.js.map +1 -1
- package/dist/start.js +2 -1
- package/dist/start.js.map +1 -1
- package/install.sh +162 -0
- package/package.json +24 -23
- package/packages/memory/Cargo.lock +6480 -0
- package/packages/memory/Cargo.toml +21 -0
- package/packages/memory/src/src/context.rs +179 -0
- package/packages/memory/src/src/embeddings.rs +51 -0
- package/packages/memory/src/src/main.rs +887 -0
- package/packages/memory/src/src/promotion.rs +808 -0
- package/packages/memory/src/src/scoring.rs +142 -0
- package/packages/memory/src/src/store.rs +460 -0
- package/packages/memory/src/src/tasks.rs +321 -0
- package/.pnpmrc.json +0 -1
- package/DASHBOARD-PLAN.md +0 -206
- package/MEMORY-ENHANCEMENT-PLAN.md +0 -211
- package/TOOL-USE-DESIGN.md +0 -173
- package/dist/chunk-HDYEAKN5.js.map +0 -1
- package/dist/chunk-LJHJGDKY.js.map +0 -1
- package/dist/chunk-OG6GPQDK.js.map +0 -1
- package/dist/chunk-XBJGLZ7V.js.map +0 -1
- package/docs/TOOL-PARITY-PLAN.md +0 -191
- package/src/memory/dashboard-integration.ts +0 -295
- package/src/memory/index.ts +0 -187
- package/src/memory/performance-test.ts +0 -208
- package/src/memory/processors/agent-sync.ts +0 -312
- package/src/memory/processors/command-learner.ts +0 -298
- package/src/memory/processors/memory-api-client.ts +0 -105
- package/src/memory/processors/message-flow-integration.ts +0 -168
- package/src/memory/processors/research-digester.ts +0 -204
- package/test-caitlin-access.md +0 -11
- /package/dist/{chunk-NCJW2AOK.js.map → chunk-BHCDOHSK.js.map} +0 -0
- /package/dist/{chunk-OVRYYS5I.js.map → chunk-DPLCEMEC.js.map} +0 -0
- /package/dist/{chunk-XQZU3ULO.js.map → chunk-FBQBBAPZ.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../packages/cli/src/commands/init.ts"],"sourcesContent":["import { resolve, dirname } from \"path\";\nimport { existsSync, writeFileSync, mkdirSync, readFileSync, copyFileSync, realpathSync, chmodSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { fileURLToPath } from \"url\";\nimport { execSync } from \"child_process\";\nimport { SesameClient } from \"@sesamespace/sdk\";\nimport { getClaudeCodeOAuthToken } from \"@hivemind/runtime\";\nimport { homedir, arch, platform } from \"os\";\n\nconst HIVEMIND_DIR = resolve(process.env.HIVEMIND_HOME || resolve(homedir(), \"hivemind\"));\nconst CONFIG_DIR = resolve(HIVEMIND_DIR, \"config\");\nconst WORKSPACE_DIR = resolve(HIVEMIND_DIR, \"workspace\");\nconst BIN_DIR = resolve(HIVEMIND_DIR, \"bin\");\nconst DATA_DIR = resolve(HIVEMIND_DIR, \"data\");\nconst ENV_FILE = resolve(HIVEMIND_DIR, \".env\");\nconst LOCAL_TOML = resolve(CONFIG_DIR, \"local.toml\");\nconst MEMORY_BIN = resolve(BIN_DIR, \"hivemind-memory\");\n\nconst RELEASES_BASE_URL = \"https://sesame-hivemind-releases.s3.amazonaws.com\";\nconst EMBEDDING_MODEL = \"nomic-embed-text\";\n\nconst VAULT_CONFIG_NAME = \"hivemind-config\";\n\ninterface ProvisioningConfig {\n agentName: string;\n agentHandle: string;\n agentId: string;\n personality?: string;\n llmApiKey?: string;\n llmBaseUrl?: string;\n llmModel?: string;\n llmProvider?: 'openai' | 'anthropic';\n fleetRole?: string;\n channels: Array<{ id: string; name: string | null; kind: string }>;\n}\n\nasync function prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport async function runInitCommand(args: string[]): Promise<void> {\n const nonInteractive = args.includes(\"--yes\") || args.includes(\"-y\") || args.includes(\"--non-interactive\");\n const filteredArgs = args.filter((a) => ![\"--yes\", \"-y\", \"--non-interactive\", \"--help\", \"-h\"].includes(a));\n let sesameApiKey = filteredArgs[0];\n\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n printHelp();\n return;\n }\n\n console.log(`\n ╦ ╦╦╦ ╦╔═╗╔╦╗╦╔╗╔╔╦╗\n ╠═╣║╚╗╔╝║╣ ║║║║║║║ ║║\n ╩ ╩╩ ╚╝ ╚═╝╩ ╩╩╝╚╝═╩╝\n Agent Initialization\n`);\n\n // --- Step 1: Get Sesame API key ---\n // Check existing config if no key provided\n if (!sesameApiKey) {\n // Try .env file\n if (existsSync(ENV_FILE)) {\n try {\n const envContent = readFileSync(ENV_FILE, \"utf-8\");\n const match = envContent.match(/^SESAME_API_KEY=(.+)$/m);\n if (match && match[1].trim()) {\n sesameApiKey = match[1].trim();\n console.log(\" ✓ Found existing API key in .env\");\n }\n } catch {}\n }\n // Try local.toml\n if (!sesameApiKey && existsSync(LOCAL_TOML)) {\n try {\n const tomlContent = readFileSync(LOCAL_TOML, \"utf-8\");\n const match = tomlContent.match(/api_key\\s*=\\s*\"([^\"]+)\"/);\n if (match && match[1].trim()) {\n sesameApiKey = match[1].trim();\n console.log(\" ✓ Found existing API key in local.toml\");\n }\n } catch {}\n }\n // Try environment variable\n if (!sesameApiKey && process.env.SESAME_API_KEY) {\n sesameApiKey = process.env.SESAME_API_KEY;\n console.log(\" ✓ Using API key from SESAME_API_KEY env var\");\n }\n }\n if (!sesameApiKey) {\n sesameApiKey = await prompt(\" Sesame API key: \");\n }\n if (!sesameApiKey) {\n console.error(\"Error: Sesame API key is required\");\n process.exit(1);\n }\n\n // --- Step 2: Connect to Sesame and fetch manifest ---\n console.log(\"\\n→ Connecting to Sesame...\");\n const sdk = new SesameClient({\n apiUrl: \"https://api.sesame.space\",\n wsUrl: \"wss://ws.sesame.space\",\n apiKey: sesameApiKey,\n });\n\n let config: ProvisioningConfig;\n try {\n const manifest = await sdk.getManifest();\n console.log(` ✓ Authenticated as ${manifest.agent.handle} (${manifest.agent.id})`);\n console.log(` ✓ Workspace: ${manifest.workspace.name}`);\n console.log(` ✓ Channels: ${manifest.channels.length}`);\n for (const ch of manifest.channels) {\n console.log(` - ${ch.name || ch.id} (${ch.kind})`);\n }\n\n config = {\n agentName: manifest.agent.handle,\n agentHandle: manifest.agent.handle,\n agentId: manifest.agent.id,\n channels: manifest.channels.map((ch) => ({\n id: ch.id,\n name: ch.name,\n kind: ch.kind,\n })),\n };\n\n // --- Step 3: Check vault for config ---\n console.log(\"\\n→ Checking vault for provisioning config...\");\n try {\n const vaultResp = await sdk.listVaultItems() as any;\n const items = vaultResp.items || vaultResp.data || [];\n const configItem = items.find((i: any) => i.name === VAULT_CONFIG_NAME);\n\n if (configItem) {\n console.log(` ✓ Found ${VAULT_CONFIG_NAME} vault item`);\n const revealResp = await sdk.revealItem(configItem.id) as any;\n const fields = revealResp.data?.fields || revealResp.fields || revealResp.data || {};\n\n config.llmApiKey = fields.llm_api_key || fields.openrouter_api_key;\n config.llmBaseUrl = fields.llm_base_url;\n config.llmModel = fields.llm_model;\n config.personality = fields.agent_personality || fields.personality;\n config.fleetRole = fields.fleet_role;\n\n // Detect Anthropic API key from vault — sets provider + base_url automatically\n if (!config.llmApiKey && fields.anthropic_api_key) {\n config.llmApiKey = fields.anthropic_api_key;\n config.llmProvider = 'anthropic';\n if (!config.llmBaseUrl) config.llmBaseUrl = 'https://api.anthropic.com';\n }\n\n if (config.llmApiKey) console.log(` ✓ LLM API key loaded from vault${config.llmProvider === 'anthropic' ? ' (Anthropic)' : ''}`);\n if (config.llmModel) console.log(` ✓ LLM model: ${config.llmModel}`);\n if (config.personality) console.log(` ✓ Personality: ${config.personality.slice(0, 60)}...`);\n if (config.fleetRole) console.log(` ✓ Fleet role: ${config.fleetRole}`);\n } else {\n console.log(\" ! No hivemind-config vault item found\");\n console.log(\" ! Will prompt for LLM API key instead\");\n }\n } catch (err) {\n console.log(` ! Could not read vault: ${(err as Error).message}`);\n }\n } catch (err) {\n console.error(`\\n ✗ Failed to connect to Sesame: ${(err as Error).message}`);\n console.error(\" Check your API key and try again.\");\n process.exit(1);\n } finally {\n sdk.disconnect();\n }\n\n // --- Step 3.5: Try Claude Code OAuth if no API key from vault ---\n if (!config.llmApiKey) {\n const oauthToken = getClaudeCodeOAuthToken();\n if (oauthToken) {\n // Don't store the token — it expires. Configure provider so it's read from keychain at runtime.\n config.llmProvider = 'anthropic';\n config.llmBaseUrl = 'https://api.anthropic.com';\n if (!config.llmModel) config.llmModel = 'claude-sonnet-4-20250514';\n console.log(' ✓ Claude Max subscription detected (via Claude Code OAuth)');\n console.log(' ✓ Configuring provider=anthropic — token read from keychain at runtime');\n }\n }\n\n // --- Step 4: Prompt for anything missing ---\n if (!config.llmApiKey && !config.llmProvider) {\n console.log(\" ! No LLM API key found in vault — set LLM_API_KEY in .env after init\");\n }\n\n // --- Step 5: Write config files ---\n console.log(\"\\n→ Writing configuration...\");\n\n mkdirSync(CONFIG_DIR, { recursive: true });\n mkdirSync(WORKSPACE_DIR, { recursive: true });\n\n // Copy default.toml from installed package if not present\n const defaultToml = resolve(CONFIG_DIR, \"default.toml\");\n if (!existsSync(defaultToml)) {\n // Resolve from the hivemind binary location\n // process.argv[1] may be a symlink, so resolve it first\n const realBin = realpathSync(process.argv[1]);\n // realBin is <pkg>/dist/main.js, so ../config/ gets us to <pkg>/config/\n const packageConfigDir = resolve(dirname(realBin), \"..\", \"config\");\n const packageDefault = resolve(packageConfigDir, \"default.toml\");\n if (existsSync(packageDefault)) {\n copyFileSync(packageDefault, defaultToml);\n console.log(` ✓ ${defaultToml}`);\n // Also copy team charter if available\n const packageCharter = resolve(packageConfigDir, \"TEAM-CHARTER.md\");\n const localCharter = resolve(CONFIG_DIR, \"TEAM-CHARTER.md\");\n if (existsSync(packageCharter) && !existsSync(localCharter)) {\n copyFileSync(packageCharter, localCharter);\n console.log(` ✓ ${localCharter}`);\n }\n } else {\n console.log(` ! default.toml not found in package — you may need to copy it manually`);\n }\n }\n\n // Write workspace identity files\n const soulPath = resolve(WORKSPACE_DIR, \"SOUL.md\");\n if (!existsSync(soulPath)) {\n const personality = config.personality || \"A helpful, capable agent.\";\n writeFileSync(soulPath, `# SOUL.md — Who You Are\n\n${personality}\n\n---\n\n_This file defines your personality and values. Edit it to evolve who you are._\n`);\n console.log(` ✓ ${soulPath}`);\n }\n\n const identityPath = resolve(WORKSPACE_DIR, \"IDENTITY.md\");\n if (!existsSync(identityPath)) {\n writeFileSync(identityPath, `# IDENTITY.md\n\n- **Name:** ${config.agentName}\n- **Handle:** ${config.agentHandle}\n- **Agent ID:** ${config.agentId}\n`);\n console.log(` ✓ ${identityPath}`);\n }\n\n // Write local.toml (overrides)\n const llmLines: string[] = [];\n if (config.llmModel || config.llmProvider || config.llmBaseUrl) {\n llmLines.push('[llm]');\n if (config.llmProvider) llmLines.push(`provider = \"${config.llmProvider}\"`);\n if (config.llmBaseUrl) llmLines.push(`base_url = \"${config.llmBaseUrl}\"`);\n if (config.llmModel) llmLines.push(`model = \"${config.llmModel}\"`);\n } else {\n llmLines.push('# [llm] using defaults');\n }\n\n const localToml = `# Generated by hivemind init — ${new Date().toISOString()}\n# Overrides config/default.toml with agent-specific settings\n\n[agent]\nname = \"${config.agentName}\"\n${config.personality ? `personality = \"${config.personality.replace(/\"/g, '\\\\\"')}\"` : \"# personality = (using default)\"}\nworkspace = \"workspace\"\n\n${llmLines.join('\\n')}\n\n[sesame]\napi_key = \"${sesameApiKey}\"\n`;\n\n writeFileSync(LOCAL_TOML, localToml);\n console.log(` ✓ ${LOCAL_TOML}`);\n\n // Write .env\n const envLines = [\n `# Hivemind Agent — ${config.agentName}`,\n `# Generated by hivemind init — ${new Date().toISOString()}`,\n `SESAME_API_KEY=${sesameApiKey}`,\n ];\n if (config.llmProvider === 'anthropic') {\n envLines.push(`ANTHROPIC_API_KEY=${config.llmApiKey || \"\"}`);\n } else {\n envLines.push(`LLM_API_KEY=${config.llmApiKey || \"\"}`);\n }\n envLines.push(`AGENT_NAME=${config.agentName}`, '');\n const envContent = envLines.join('\\n');\n\n writeFileSync(ENV_FILE, envContent, { mode: 0o600 });\n console.log(` ✓ ${ENV_FILE} (chmod 600)`);\n\n // --- Step 6: Install memory infrastructure ---\n console.log(\"\\n→ Setting up memory system...\");\n mkdirSync(BIN_DIR, { recursive: true });\n mkdirSync(DATA_DIR, { recursive: true });\n\n await installOllama();\n await pullEmbeddingModel();\n await downloadMemoryDaemon();\n\n // --- Done ---\n console.log(`\n ✓ Hivemind initialized for ${config.agentName}!\n\n To start the agent:\n hivemind start\n\n To install as a service:\n hivemind service install\n\n Agent ID: ${config.agentId}\n Channels: ${config.channels.map((c) => c.name || c.id).join(\", \")}\n Fleet role: ${config.fleetRole || \"standalone\"}\n`);\n}\n\n// --- Memory infrastructure helpers ---\n\nasync function installOllama(): Promise<void> {\n try {\n execSync(\"which ollama\", { stdio: \"ignore\" });\n const version = execSync(\"ollama --version\", { encoding: \"utf-8\" }).trim();\n console.log(` ✓ Ollama already installed (${version})`);\n return;\n } catch {}\n\n console.log(\" → Installing Ollama...\");\n try {\n // Try Homebrew first (macOS)\n execSync(\"which brew\", { stdio: \"ignore\" });\n execSync(\"brew install ollama\", { stdio: \"inherit\" });\n console.log(\" ✓ Ollama installed via Homebrew\");\n } catch {\n // Fall back to official installer\n try {\n execSync(\"curl -fsSL https://ollama.com/install.sh | sh\", { stdio: \"inherit\" });\n console.log(\" ✓ Ollama installed via installer script\");\n } catch (err) {\n console.error(` ✗ Failed to install Ollama: ${(err as Error).message}`);\n console.error(\" ! Install manually: https://ollama.com/download\");\n console.error(\" ! Memory system will not work without Ollama\");\n }\n }\n}\n\nasync function pullEmbeddingModel(): Promise<void> {\n console.log(` → Pulling embedding model (${EMBEDDING_MODEL})...`);\n try {\n // Ensure ollama is running\n try {\n execSync(\"curl -sf http://localhost:11434/api/tags > /dev/null\", { stdio: \"ignore\" });\n } catch {\n // Start ollama serve in background\n console.log(\" → Starting Ollama server...\");\n execSync(\"ollama serve &\", { stdio: \"ignore\", shell: \"/bin/sh\" });\n // Wait for it to be ready\n for (let i = 0; i < 15; i++) {\n try {\n execSync(\"curl -sf http://localhost:11434/api/tags > /dev/null\", { stdio: \"ignore\" });\n break;\n } catch {\n execSync(\"sleep 1\");\n }\n }\n }\n\n execSync(`ollama pull ${EMBEDDING_MODEL}`, { stdio: \"inherit\" });\n console.log(` ✓ ${EMBEDDING_MODEL} model ready`);\n } catch (err) {\n console.error(` ✗ Failed to pull model: ${(err as Error).message}`);\n console.error(` ! Run manually: ollama pull ${EMBEDDING_MODEL}`);\n }\n}\n\nasync function downloadMemoryDaemon(): Promise<void> {\n if (existsSync(MEMORY_BIN)) {\n console.log(` ✓ Memory daemon already installed at ${MEMORY_BIN}`);\n return;\n }\n\n const osArch = arch();\n const osPlatform = platform();\n\n if (osPlatform !== \"darwin\") {\n console.log(` ! Memory daemon pre-built binaries only available for macOS currently`);\n console.log(` ! Build from source: cd packages/memory && cargo build --release`);\n return;\n }\n\n const artifactName = osArch === \"arm64\"\n ? \"hivemind-memory-darwin-arm64\"\n : \"hivemind-memory-darwin-x64\";\n\n console.log(` → Downloading memory daemon (${artifactName})...`);\n try {\n // Get latest version from S3\n const latestJson = execSync(\n `curl -sf \"${RELEASES_BASE_URL}/latest.json\"`,\n { encoding: \"utf-8\" },\n );\n const { version } = JSON.parse(latestJson);\n const url = `${RELEASES_BASE_URL}/v${version}/${artifactName}`;\n\n execSync(\n `curl -fSL -o \"${MEMORY_BIN}\" \"${url}\"`,\n { stdio: \"inherit\" },\n );\n chmodSync(MEMORY_BIN, 0o755);\n console.log(` ✓ Memory daemon installed at ${MEMORY_BIN} (v${version})`);\n } catch (err) {\n console.error(` ✗ Failed to download memory daemon: ${(err as Error).message}`);\n console.error(\" ! Build from source: cd packages/memory && cargo build --release\");\n console.error(` ! Then copy to: ${MEMORY_BIN}`);\n }\n}\n\nfunction printHelp(): void {\n console.log(`hivemind init — Initialize a Hivemind agent from Sesame\n\nUsage: hivemind init [sesame-api-key]\n\nThe API key can also be passed as the first argument.\n\nWhat it does:\n 1. Connects to Sesame and fetches agent identity\n 2. Reads provisioning config from Sesame vault (if available)\n 3. Writes config/local.toml and .env\n 4. Installs Ollama + embedding model for memory\n 5. Downloads pre-built memory daemon binary\n\nOptions:\n -h, --help Show this help\n`);\n}\n"],"mappings":"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","names":["resolve","envContent"]}
|
package/docs/TOOL-PARITY-PLAN.md
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
# Hivemind Tool Parity Plan
|
|
2
|
-
|
|
3
|
-
*Goal: Bring Hivemind tool capabilities to parity with OpenClaw/Pi, then beyond.*
|
|
4
|
-
|
|
5
|
-
*Created: 2026-03-01 | Last updated: 2026-03-01*
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Context
|
|
10
|
-
|
|
11
|
-
OpenClaw uses [Pi](https://github.com/badlogic/pi-mono/) as its underlying coding agent (see [Armin's article](https://lucumr.pocoo.org/2026/1/31/pi/)). Pi provides 4 core tools: `read`, `write`, `edit`, `bash`. OpenClaw layers orchestration on top: messaging, scheduling, sub-agents, browser control, vision, TTS, device control, and more.
|
|
12
|
-
|
|
13
|
-
Hivemind is a **headless messaging agent** (not a TUI coding agent like Pi), but it needs equivalent capabilities. Hivemind's competitive edge is its **3-layer semantic memory** (L2 episodic + L3 semantic), which neither Pi nor OpenClaw have.
|
|
14
|
-
|
|
15
|
-
**Principle: Build, don't integrate.** Study Pi's source for inspiration, write our own implementations. No external dependency risk, tailored to our headless/messaging paradigm.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## What's Already Implemented ✅
|
|
20
|
-
|
|
21
|
-
### Core Tools (shipped in v0.6.0-v0.7.2)
|
|
22
|
-
| Tool | Status | Notes |
|
|
23
|
-
|------|--------|-------|
|
|
24
|
-
| `shell` | ✅ Shipped | Workspace-scoped, configurable timeout |
|
|
25
|
-
| `read_file` | ✅ Shipped | With offset/limit for large files |
|
|
26
|
-
| `write_file` | ✅ Shipped | Auto-creates directories |
|
|
27
|
-
| `edit_file` | ✅ Shipped | Exact-match find-and-replace |
|
|
28
|
-
| `list_files` | ✅ Shipped | Directory listing |
|
|
29
|
-
| `web_search` | ✅ Shipped | Brave Search API |
|
|
30
|
-
| `web_fetch` | ✅ Shipped | URL → readable text |
|
|
31
|
-
|
|
32
|
-
### Memory Tools (shipped in v0.7.0)
|
|
33
|
-
| Tool | Status | Notes |
|
|
34
|
-
|------|--------|-------|
|
|
35
|
-
| `memory_search` | ✅ Shipped | L2 semantic search per context |
|
|
36
|
-
| `memory_contexts` | ✅ Shipped | List all contexts |
|
|
37
|
-
| `memory_l3` | ✅ Shipped | View promoted knowledge |
|
|
38
|
-
| `memory_cross_search` | ✅ Shipped | Search across all contexts |
|
|
39
|
-
|
|
40
|
-
### Infrastructure (shipped in v0.7.0)
|
|
41
|
-
| Feature | Status | Notes |
|
|
42
|
-
|---------|--------|-------|
|
|
43
|
-
| Agentic tool-use loop | ✅ Shipped | OpenAI-compatible function calling via OpenRouter, max 25 iterations |
|
|
44
|
-
| Tool registry | ✅ Shipped | Pluggable registration system |
|
|
45
|
-
| Session persistence | ✅ Shipped | JSONL per context, survives restarts |
|
|
46
|
-
| Lossless compaction | ✅ Shipped | Saves episodes to L2 before summarizing |
|
|
47
|
-
| MEMORY.md | ✅ Shipped | Global + per-context agent-managed memory files |
|
|
48
|
-
| Skills discovery | ✅ Shipped | Auto-scan workspace/skills/*/SKILL.md |
|
|
49
|
-
| Events system | ✅ Shipped | File-based immediate/one-shot/periodic scheduling |
|
|
50
|
-
| Token budget management | ✅ Shipped | Context limit + response reserve |
|
|
51
|
-
| Dashboard | ✅ Shipped | Request inspector, memory browser, context overview |
|
|
52
|
-
| Service install | ✅ Shipped | launchd services (agent + memory daemon + watchdog) |
|
|
53
|
-
| One-line installer | ✅ Shipped | `curl -sL api.sesame.space/api/v1/hivemind/install | bash -s -- <key>` |
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## What's Not Implemented Yet
|
|
58
|
-
|
|
59
|
-
### Tier 1 — Essential (Phase 1-2) ✅ COMPLETE
|
|
60
|
-
|
|
61
|
-
| # | Tool/Feature | Status | Tools Added |
|
|
62
|
-
|---|-------------|--------|------------|
|
|
63
|
-
| 1 | **Event/scheduling tools** | ✅ Shipped | `create_event`, `list_events`, `delete_event` |
|
|
64
|
-
| 2 | **Enhanced Sesame messaging** | ✅ Shipped | `send_message` |
|
|
65
|
-
| 3 | **Sub-agent spawning** | ✅ Shipped | `spawn_agent`, `list_agents`, `kill_agent` |
|
|
66
|
-
| 4 | **Web browsing** | ✅ Shipped | `browse` (extract/screenshot/click/type/evaluate) |
|
|
67
|
-
|
|
68
|
-
### Tier 2 — Important (Phase 3) ✅ COMPLETE
|
|
69
|
-
|
|
70
|
-
| # | Tool/Feature | Status | Tools Added |
|
|
71
|
-
|---|-------------|--------|------------|
|
|
72
|
-
| 5 | **Image/vision analysis** | ✅ Shipped | `analyze_image` |
|
|
73
|
-
| 6 | **Git operations** | ✅ Shipped | `git_status`, `git_diff`, `git_commit`, `git_log`, `git_push` |
|
|
74
|
-
| 7 | **Cross-context messaging** | ⬚ Deferred | (existing cross-context search covers most cases) |
|
|
75
|
-
|
|
76
|
-
### Tier 3 — System & Mac Capabilities ✅ COMPLETE
|
|
77
|
-
|
|
78
|
-
| # | Tool/Feature | Status | Tools Added |
|
|
79
|
-
|---|-------------|--------|------------|
|
|
80
|
-
| 8 | **System management** | ✅ Shipped | `system_info`, `process_list`, `process_kill`, `service_control`, `disk_usage`, `network_info` |
|
|
81
|
-
| 9 | **macOS automation** | ✅ Shipped | `run_applescript`, `notify`, `clipboard_read`, `clipboard_write`, `open_url`, `screenshot` |
|
|
82
|
-
| 10 | **Data handling** | ✅ Shipped | `sqlite_query`, `archive_create`, `archive_extract`, `pdf_extract` |
|
|
83
|
-
| 11 | **HTTP server/client** | ✅ Shipped | `http_serve`, `http_stop`, `http_request` |
|
|
84
|
-
| 12 | **File watching** | ✅ Shipped | `watch_start`, `watch_stop`, `watch_list` |
|
|
85
|
-
|
|
86
|
-
### Tier 4 — Future (not yet implemented)
|
|
87
|
-
|
|
88
|
-
| # | Tool/Feature | What It Does | Notes |
|
|
89
|
-
|---|-------------|-------------|-------|
|
|
90
|
-
| 13 | **Skills/extensions system** | Formalized hot-reloadable skills with tool registration | Inspired by Pi's extension system |
|
|
91
|
-
| 14 | **TTS** | Text-to-speech output via API | ElevenLabs API |
|
|
92
|
-
| 15 | **SSH** | Remote machine access | Could use shell + ssh CLI |
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## Implementation Plan
|
|
97
|
-
|
|
98
|
-
### Phase 1: Event Tools + Enhanced Messaging
|
|
99
|
-
**Estimate: 1-2 coding sessions**
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
packages/runtime/src/tools/
|
|
103
|
-
events.ts — NEW: create_event, list_events, delete_event
|
|
104
|
-
messaging.ts — NEW: send_message (to any Sesame channel/user)
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
**Event tools:** Wrap the existing `EventsWatcher` infrastructure. Agent can create one-shot (reminders) and periodic (cron-like) events. Events fire as messages processed by the agent.
|
|
108
|
-
|
|
109
|
-
**Messaging tools:** Use existing Sesame SDK to send messages to arbitrary channels. Agent can proactively reach out, not just reply to incoming messages.
|
|
110
|
-
|
|
111
|
-
**Dependencies:** None new. Uses existing EventsWatcher + Sesame SDK.
|
|
112
|
-
|
|
113
|
-
### Phase 2: Sub-agents + Web Browsing
|
|
114
|
-
**Estimate: 3-4 coding sessions**
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
packages/runtime/src/tools/
|
|
118
|
-
spawn.ts — NEW: spawn_agent, list_agents, kill_agent
|
|
119
|
-
browser.ts — NEW: browse_url, browser_action
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Sub-agents:** Fork a new agent process with `hivemind start --context <name> --task "<prompt>"`. Parent tracks child PIDs. Results reported back via Sesame message or shared file. Timeout and cleanup built in.
|
|
123
|
-
|
|
124
|
-
**Web browsing:** Headless Playwright for full web interaction. Agent can navigate, click, fill forms, extract content from JS-rendered pages. Single dependency (`playwright`), but it's the right tool for this — curl/fetch can't handle SPAs, authentication flows, or dynamic content.
|
|
125
|
-
|
|
126
|
-
**Why Playwright:** We considered avoiding it (heavy dep), but web browsing is a core capability for agents that need to "do anything a human can do on a computer." Pi/OpenClaw use it. The alternative (shell + curl) only handles static pages.
|
|
127
|
-
|
|
128
|
-
### Phase 3: Vision + Git
|
|
129
|
-
**Estimate: 1-2 coding sessions**
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
packages/runtime/src/tools/
|
|
133
|
-
vision.ts — NEW: analyze_image
|
|
134
|
-
git.ts — NEW: git_status, git_diff, git_commit, git_push
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
**Vision:** Single HTTP call to OpenRouter with vision-capable model. Accept image URL or base64.
|
|
138
|
-
|
|
139
|
-
**Git:** Thin wrappers around git CLI with structured output. Reduces token usage vs raw `shell` git output. Safety: confirmation before push.
|
|
140
|
-
|
|
141
|
-
### Phase 4: Skills/Extensions System
|
|
142
|
-
**Estimate: 2-3 coding sessions**
|
|
143
|
-
|
|
144
|
-
Formalize the existing skills discovery into a proper extension system:
|
|
145
|
-
- Skills can register new tools dynamically
|
|
146
|
-
- Hot-reload on file change (inspired by Pi's extension system)
|
|
147
|
-
- Agent can write and install its own skills
|
|
148
|
-
- Skills persist across restarts
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## Architecture Notes
|
|
153
|
-
|
|
154
|
-
### Tool Registration Pattern
|
|
155
|
-
All tools follow the existing registry pattern:
|
|
156
|
-
```typescript
|
|
157
|
-
// Each tool file exports a register function
|
|
158
|
-
export function registerEventTools(registry: ToolRegistry, dataDir: string): void {
|
|
159
|
-
registry.register("create_event", description, schema, executor);
|
|
160
|
-
// ...
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Security Model
|
|
165
|
-
- **Shell:** Workspace-scoped, configurable timeout (existing)
|
|
166
|
-
- **Files:** Scoped to workspace (existing)
|
|
167
|
-
- **Messaging:** Authenticated via existing Sesame connection
|
|
168
|
-
- **Sub-agents:** Inherit parent permissions, isolated context
|
|
169
|
-
- **Events:** File-based, local only
|
|
170
|
-
- **Browser:** Sandboxed Playwright instance, no persistent state
|
|
171
|
-
- **Git:** Confirmation before push
|
|
172
|
-
|
|
173
|
-
### What Hivemind Has That OpenClaw/Pi Don't
|
|
174
|
-
- **3-layer semantic memory** (L2 episodic + L3 semantic with automatic promotion)
|
|
175
|
-
- **Cross-context knowledge sharing** with isolation by default
|
|
176
|
-
- **Memory-augmented responses** (every LLM call enriched with relevant history)
|
|
177
|
-
- **Dashboard** for debugging LLM calls + memory state
|
|
178
|
-
- **Token budget management** with configurable limits
|
|
179
|
-
|
|
180
|
-
This isn't just parity — it's parity + memory, which is the competitive edge.
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## Superseded Documents
|
|
185
|
-
|
|
186
|
-
- `TOOL-USE-DESIGN.md` (root) — Original tool architecture design. **Fully implemented** in v0.6.0-v0.7.2. Kept for historical reference.
|
|
187
|
-
- `DASHBOARD-PLAN.md` (root) — Dashboard design. **Fully implemented**. Kept for reference.
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
*This is the authoritative plan for Hivemind tool development. Update this document as phases complete.*
|
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Integration - Exposes memory system state to the Hivemind dashboard
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { EventEmitter } from 'events';
|
|
6
|
-
import express from 'express';
|
|
7
|
-
import { MessageFlowIntegration } from './processors/message-flow-integration';
|
|
8
|
-
import { ResearchDigester } from './processors/research-digester';
|
|
9
|
-
import { CommandLearner } from './processors/command-learner';
|
|
10
|
-
import { AgentSync } from './processors/agent-sync';
|
|
11
|
-
|
|
12
|
-
export interface DashboardConfig {
|
|
13
|
-
port?: number;
|
|
14
|
-
messageFlow: MessageFlowIntegration;
|
|
15
|
-
researchDigester?: ResearchDigester;
|
|
16
|
-
commandLearner?: CommandLearner;
|
|
17
|
-
agentSync?: AgentSync;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class DashboardIntegration extends EventEmitter {
|
|
21
|
-
private app: express.Application;
|
|
22
|
-
private messageFlow: MessageFlowIntegration;
|
|
23
|
-
private researchDigester?: ResearchDigester;
|
|
24
|
-
private commandLearner?: CommandLearner;
|
|
25
|
-
private agentSync?: AgentSync;
|
|
26
|
-
|
|
27
|
-
constructor(config: DashboardConfig) {
|
|
28
|
-
super();
|
|
29
|
-
|
|
30
|
-
this.messageFlow = config.messageFlow;
|
|
31
|
-
this.researchDigester = config.researchDigester;
|
|
32
|
-
this.commandLearner = config.commandLearner;
|
|
33
|
-
this.agentSync = config.agentSync;
|
|
34
|
-
|
|
35
|
-
this.app = express();
|
|
36
|
-
this.setupRoutes();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
private setupRoutes(): void {
|
|
40
|
-
this.app.use(express.json());
|
|
41
|
-
|
|
42
|
-
// Memory system overview
|
|
43
|
-
this.app.get('/api/memory/overview', async (req, res) => {
|
|
44
|
-
try {
|
|
45
|
-
const state = await this.messageFlow.getState();
|
|
46
|
-
const overview = {
|
|
47
|
-
...state,
|
|
48
|
-
research: this.researchDigester ? {
|
|
49
|
-
entries: (await this.researchDigester['research']).size,
|
|
50
|
-
topics: Array.from(this.researchDigester['topicIndex'].keys())
|
|
51
|
-
} : null,
|
|
52
|
-
commands: this.commandLearner ? {
|
|
53
|
-
patterns: this.commandLearner['patterns'].size,
|
|
54
|
-
categories: Array.from(this.commandLearner['categoryIndex'].keys())
|
|
55
|
-
} : null,
|
|
56
|
-
agents: this.agentSync ? {
|
|
57
|
-
known: (await this.agentSync.getAgentKnowledge()).length,
|
|
58
|
-
sharedTasks: (await this.agentSync.getSharedTasks()).length
|
|
59
|
-
} : null
|
|
60
|
-
};
|
|
61
|
-
res.json(overview);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
res.status(500).json({ error: error.message });
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Working set - currently active code files
|
|
68
|
-
this.app.get('/api/memory/working-set', async (req, res) => {
|
|
69
|
-
try {
|
|
70
|
-
const state = await this.messageFlow.getState();
|
|
71
|
-
res.json({
|
|
72
|
-
files: state.workingSet,
|
|
73
|
-
totalFiles: state.workingSet.length
|
|
74
|
-
});
|
|
75
|
-
} catch (error) {
|
|
76
|
-
res.status(500).json({ error: error.message });
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Active tasks
|
|
81
|
-
this.app.get('/api/memory/tasks', async (req, res) => {
|
|
82
|
-
try {
|
|
83
|
-
const state = await this.messageFlow.getState();
|
|
84
|
-
const sharedTasks = this.agentSync ? await this.agentSync.getSharedTasks() : [];
|
|
85
|
-
|
|
86
|
-
res.json({
|
|
87
|
-
localTasks: state.tasks,
|
|
88
|
-
sharedTasks: sharedTasks,
|
|
89
|
-
total: state.tasks.length + sharedTasks.length
|
|
90
|
-
});
|
|
91
|
-
} catch (error) {
|
|
92
|
-
res.status(500).json({ error: error.message });
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Research entries
|
|
97
|
-
this.app.get('/api/memory/research', async (req, res) => {
|
|
98
|
-
if (!this.researchDigester) {
|
|
99
|
-
return res.json({ entries: [], topics: [] });
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const recent = await this.researchDigester.getRecent(20);
|
|
104
|
-
res.json({
|
|
105
|
-
entries: recent,
|
|
106
|
-
topics: Array.from(this.researchDigester['topicIndex'].keys())
|
|
107
|
-
});
|
|
108
|
-
} catch (error) {
|
|
109
|
-
res.status(500).json({ error: error.message });
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Search research
|
|
114
|
-
this.app.get('/api/memory/research/search', async (req, res) => {
|
|
115
|
-
if (!this.researchDigester) {
|
|
116
|
-
return res.json({ results: [] });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
const { q } = req.query;
|
|
121
|
-
const results = await this.researchDigester.search(q as string);
|
|
122
|
-
res.json({ results });
|
|
123
|
-
} catch (error) {
|
|
124
|
-
res.status(500).json({ error: error.message });
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Command patterns
|
|
129
|
-
this.app.get('/api/memory/commands', async (req, res) => {
|
|
130
|
-
if (!this.commandLearner) {
|
|
131
|
-
return res.json({ patterns: [], categories: [] });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
const patterns = Array.from(this.commandLearner['patterns'].values());
|
|
136
|
-
const categories = Array.from(this.commandLearner['categoryIndex'].keys());
|
|
137
|
-
|
|
138
|
-
res.json({
|
|
139
|
-
patterns: patterns.sort((a, b) => b.usageCount - a.usageCount),
|
|
140
|
-
categories
|
|
141
|
-
});
|
|
142
|
-
} catch (error) {
|
|
143
|
-
res.status(500).json({ error: error.message });
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// Command suggestions
|
|
148
|
-
this.app.get('/api/memory/commands/suggest', async (req, res) => {
|
|
149
|
-
if (!this.commandLearner) {
|
|
150
|
-
return res.json({ suggestions: [] });
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
try {
|
|
154
|
-
const { context, category } = req.query;
|
|
155
|
-
const suggestions = await this.commandLearner.getSuggestions(
|
|
156
|
-
context as string || '',
|
|
157
|
-
category as string
|
|
158
|
-
);
|
|
159
|
-
res.json({ suggestions });
|
|
160
|
-
} catch (error) {
|
|
161
|
-
res.status(500).json({ error: error.message });
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// Agent knowledge
|
|
166
|
-
this.app.get('/api/memory/agents', async (req, res) => {
|
|
167
|
-
if (!this.agentSync) {
|
|
168
|
-
return res.json({ agents: [] });
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
const agents = await this.agentSync.getAgentKnowledge();
|
|
173
|
-
res.json({ agents });
|
|
174
|
-
} catch (error) {
|
|
175
|
-
res.status(500).json({ error: error.message });
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Memory timeline - recent activity
|
|
180
|
-
this.app.get('/api/memory/timeline', async (req, res) => {
|
|
181
|
-
try {
|
|
182
|
-
const timeline = [];
|
|
183
|
-
|
|
184
|
-
// Add recent tasks
|
|
185
|
-
const state = await this.messageFlow.getState();
|
|
186
|
-
for (const task of state.tasks) {
|
|
187
|
-
timeline.push({
|
|
188
|
-
type: 'task',
|
|
189
|
-
timestamp: task.lastUpdate,
|
|
190
|
-
description: task.description,
|
|
191
|
-
metadata: { state: task.state }
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Add recent research
|
|
196
|
-
if (this.researchDigester) {
|
|
197
|
-
const research = await this.researchDigester.getRecent(5);
|
|
198
|
-
for (const entry of research) {
|
|
199
|
-
timeline.push({
|
|
200
|
-
type: 'research',
|
|
201
|
-
timestamp: entry.timestamp,
|
|
202
|
-
description: entry.title,
|
|
203
|
-
metadata: { url: entry.url, topics: entry.relatedTopics }
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Add recent commands
|
|
209
|
-
if (this.commandLearner) {
|
|
210
|
-
const patterns = Array.from(this.commandLearner['patterns'].values())
|
|
211
|
-
.sort((a, b) => b.lastUsed.getTime() - a.lastUsed.getTime())
|
|
212
|
-
.slice(0, 5);
|
|
213
|
-
|
|
214
|
-
for (const pattern of patterns) {
|
|
215
|
-
timeline.push({
|
|
216
|
-
type: 'command',
|
|
217
|
-
timestamp: pattern.lastUsed,
|
|
218
|
-
description: pattern.description,
|
|
219
|
-
metadata: { pattern: pattern.pattern, category: pattern.category }
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Sort by timestamp
|
|
225
|
-
timeline.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
226
|
-
|
|
227
|
-
res.json({ timeline: timeline.slice(0, 50) });
|
|
228
|
-
} catch (error) {
|
|
229
|
-
res.status(500).json({ error: error.message });
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Context preview - what would be included in next request
|
|
234
|
-
this.app.post('/api/memory/context-preview', async (req, res) => {
|
|
235
|
-
try {
|
|
236
|
-
const { message } = req.body;
|
|
237
|
-
const context = await this.messageFlow.processMessage({
|
|
238
|
-
role: 'user',
|
|
239
|
-
content: message,
|
|
240
|
-
timestamp: new Date()
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
res.json({
|
|
244
|
-
context,
|
|
245
|
-
length: context.length,
|
|
246
|
-
sections: this.analyzeContextSections(context)
|
|
247
|
-
});
|
|
248
|
-
} catch (error) {
|
|
249
|
-
res.status(500).json({ error: error.message });
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
private analyzeContextSections(context: string): any[] {
|
|
255
|
-
const sections = [];
|
|
256
|
-
const lines = context.split('\n');
|
|
257
|
-
let currentSection = null;
|
|
258
|
-
let currentContent = [];
|
|
259
|
-
|
|
260
|
-
for (const line of lines) {
|
|
261
|
-
if (line.startsWith('## ')) {
|
|
262
|
-
if (currentSection) {
|
|
263
|
-
sections.push({
|
|
264
|
-
title: currentSection,
|
|
265
|
-
lines: currentContent.length,
|
|
266
|
-
characters: currentContent.join('\n').length
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
currentSection = line.substring(3);
|
|
270
|
-
currentContent = [];
|
|
271
|
-
} else {
|
|
272
|
-
currentContent.push(line);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (currentSection) {
|
|
277
|
-
sections.push({
|
|
278
|
-
title: currentSection,
|
|
279
|
-
lines: currentContent.length,
|
|
280
|
-
characters: currentContent.join('\n').length
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return sections;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
async start(port: number = 9486): Promise<void> {
|
|
288
|
-
return new Promise((resolve) => {
|
|
289
|
-
this.app.listen(port, () => {
|
|
290
|
-
this.emit('started', { port });
|
|
291
|
-
resolve();
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
}
|