getmosaic 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.
- package/README.md +62 -0
- package/bin/mosaic.sh +38 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/src/config.d.ts +9 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +11 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/hyperspell.d.ts +3 -0
- package/dist/src/hyperspell.d.ts.map +1 -0
- package/dist/src/hyperspell.js +7 -0
- package/dist/src/hyperspell.js.map +1 -0
- package/dist/src/tools/generate-report.d.ts +15 -0
- package/dist/src/tools/generate-report.d.ts.map +1 -0
- package/dist/src/tools/generate-report.js +115 -0
- package/dist/src/tools/generate-report.js.map +1 -0
- package/dist/src/tools/registry.d.ts +48 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +21 -0
- package/dist/src/tools/registry.js.map +1 -0
- package/dist/src/tools/remember-insight.d.ts +15 -0
- package/dist/src/tools/remember-insight.d.ts.map +1 -0
- package/dist/src/tools/remember-insight.js +27 -0
- package/dist/src/tools/remember-insight.js.map +1 -0
- package/dist/src/tools/search-memories.d.ts +15 -0
- package/dist/src/tools/search-memories.d.ts.map +1 -0
- package/dist/src/tools/search-memories.js +74 -0
- package/dist/src/tools/search-memories.js.map +1 -0
- package/dist/src/tools/web-search.d.ts +15 -0
- package/dist/src/tools/web-search.d.ts.map +1 -0
- package/dist/src/tools/web-search.js +48 -0
- package/dist/src/tools/web-search.js.map +1 -0
- package/install.sh +196 -0
- package/openclaw.plugin.json +50 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Mosaic
|
|
2
|
+
|
|
3
|
+
Mosaic is an opinionated intelligence agent that reads your team's internal streams — Slack, email, docs, CRM — scans market trends, and delivers sharp insights to drive product decisions and strategy.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
curl -fsSL https://raw.githubusercontent.com/agg111/mosaic/main/install.sh | sh
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
That's it. The installer sets up everything and walks you through connecting your sources.
|
|
12
|
+
|
|
13
|
+
## Start
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
mosaic start
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Connect your sources
|
|
20
|
+
|
|
21
|
+
Sign up at [hyperspell.com](https://hyperspell.com) and connect your team's tools:
|
|
22
|
+
|
|
23
|
+
- Slack
|
|
24
|
+
- Gmail
|
|
25
|
+
- Notion / Google Drive
|
|
26
|
+
- HubSpot / Salesforce (coming soon)
|
|
27
|
+
|
|
28
|
+
Mosaic searches across all of them automatically.
|
|
29
|
+
|
|
30
|
+
## What Mosaic can do
|
|
31
|
+
|
|
32
|
+
| Ask Mosaic... | It will... |
|
|
33
|
+
|---|---|
|
|
34
|
+
| Generate a market report on X | Search internal knowledge + web, synthesize, save insights |
|
|
35
|
+
| What do we know about our churn? | Search across Slack, email, docs |
|
|
36
|
+
| Research our competitors | Pull live web data + internal context |
|
|
37
|
+
| Remember that X is happening | Save it to memory for future reports |
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
mosaic start # Start Mosaic
|
|
43
|
+
mosaic stop # Stop Mosaic
|
|
44
|
+
mosaic status # Show connected channels
|
|
45
|
+
mosaic setup # Re-run setup wizard
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Adding new capabilities
|
|
49
|
+
|
|
50
|
+
To add a new tool:
|
|
51
|
+
|
|
52
|
+
1. Create `src/tools/your-tool.ts`
|
|
53
|
+
2. Add it to `src/tools/registry.ts`
|
|
54
|
+
3. Rebuild: `npm run build`
|
|
55
|
+
|
|
56
|
+
No other changes needed.
|
|
57
|
+
|
|
58
|
+
## Requirements
|
|
59
|
+
|
|
60
|
+
- Node.js 20+
|
|
61
|
+
- [Hyperspell](https://hyperspell.com) account
|
|
62
|
+
- [Anthropic](https://console.anthropic.com) API key
|
package/bin/mosaic.sh
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Mosaic CLI wrapper
|
|
3
|
+
|
|
4
|
+
COMMAND="${1:-help}"
|
|
5
|
+
|
|
6
|
+
case "$COMMAND" in
|
|
7
|
+
start)
|
|
8
|
+
echo "Starting Mosaic..."
|
|
9
|
+
openclaw gateway run
|
|
10
|
+
;;
|
|
11
|
+
stop)
|
|
12
|
+
openclaw gateway stop 2>/dev/null || pkill -f "openclaw gateway" 2>/dev/null || true
|
|
13
|
+
echo "Mosaic stopped."
|
|
14
|
+
;;
|
|
15
|
+
status)
|
|
16
|
+
openclaw channels status
|
|
17
|
+
;;
|
|
18
|
+
setup)
|
|
19
|
+
sh "$(dirname "$0")/../install.sh"
|
|
20
|
+
;;
|
|
21
|
+
plugins)
|
|
22
|
+
openclaw plugins list
|
|
23
|
+
;;
|
|
24
|
+
*)
|
|
25
|
+
echo ""
|
|
26
|
+
echo " Mosaic — market intelligence for your team"
|
|
27
|
+
echo ""
|
|
28
|
+
echo " Usage: mosaic <command>"
|
|
29
|
+
echo ""
|
|
30
|
+
echo " Commands:"
|
|
31
|
+
echo " start Start Mosaic"
|
|
32
|
+
echo " stop Stop Mosaic"
|
|
33
|
+
echo " status Show connected channels and status"
|
|
34
|
+
echo " setup Re-run setup wizard"
|
|
35
|
+
echo " plugins List installed plugins"
|
|
36
|
+
echo ""
|
|
37
|
+
;;
|
|
38
|
+
esac
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type OpenClawPluginApi = {
|
|
2
|
+
registerTool: (tool: unknown) => void;
|
|
3
|
+
};
|
|
4
|
+
declare const plugin: {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
register(api: OpenClawPluginApi, configValues?: Record<string, string>): void;
|
|
9
|
+
};
|
|
10
|
+
export default plugin;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAGA,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,QAAA,MAAM,MAAM;;;;kBAMI,iBAAiB,iBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAgBtE,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MOSAIC_TOOLS } from "./src/tools/registry.js";
|
|
2
|
+
import { setConfig } from "./src/config.js";
|
|
3
|
+
const plugin = {
|
|
4
|
+
id: "mosaic",
|
|
5
|
+
name: "Mosaic",
|
|
6
|
+
description: "Market intelligence agent — distills signals from internal knowledge and the web into strategic reports",
|
|
7
|
+
register(api, configValues = {}) {
|
|
8
|
+
setConfig({
|
|
9
|
+
hyperspellApiKey: configValues.hyperspellApiKey ?? process.env.HYPERSPELL_API_KEY ?? "",
|
|
10
|
+
hyperspellUserId: configValues.hyperspellUserId ?? process.env.HYPERSPELL_USER_ID ?? "",
|
|
11
|
+
tavilyApiKey: configValues.tavilyApiKey ?? process.env.TAVILY_API_KEY,
|
|
12
|
+
anthropicApiKey: configValues.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY,
|
|
13
|
+
});
|
|
14
|
+
for (const tool of MOSAIC_TOOLS) {
|
|
15
|
+
api.registerTool(tool);
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export default plugin;
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAM5C,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,yGAAyG;IAE3G,QAAQ,CAAC,GAAsB,EAAE,eAAuC,EAAE;QACxE,SAAS,CAAC;YACR,gBAAgB,EACd,YAAY,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE;YACvE,gBAAgB,EACd,YAAY,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE;YACvE,YAAY,EACV,YAAY,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;YACzD,eAAe,EACb,YAAY,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;SAChE,CAAC,CAAC;QAEH,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface MosaicConfig {
|
|
2
|
+
hyperspellApiKey: string;
|
|
3
|
+
hyperspellUserId: string;
|
|
4
|
+
tavilyApiKey?: string;
|
|
5
|
+
anthropicApiKey?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function setConfig(config: MosaicConfig): void;
|
|
8
|
+
export declare function getConfig(): MosaicConfig;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED,wBAAgB,SAAS,IAAI,YAAY,CAKxC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
let _config = null;
|
|
2
|
+
export function setConfig(config) {
|
|
3
|
+
_config = config;
|
|
4
|
+
}
|
|
5
|
+
export function getConfig() {
|
|
6
|
+
if (!_config) {
|
|
7
|
+
throw new Error("Mosaic: plugin not initialized. Ensure it is registered via OpenClaw.");
|
|
8
|
+
}
|
|
9
|
+
return _config;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAOA,IAAI,OAAO,GAAwB,IAAI,CAAC;AAExC,MAAM,UAAU,SAAS,CAAC,MAAoB;IAC5C,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyperspell.d.ts","sourceRoot":"","sources":["../../src/hyperspell.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AAGpC,wBAAgB,SAAS,IAAI,UAAU,CAGtC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Hyperspell from "hyperspell";
|
|
2
|
+
import { getConfig } from "./config.js";
|
|
3
|
+
export function getClient() {
|
|
4
|
+
const { hyperspellApiKey, hyperspellUserId } = getConfig();
|
|
5
|
+
return new Hyperspell({ apiKey: hyperspellApiKey, userID: hyperspellUserId });
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=hyperspell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hyperspell.js","sourceRoot":"","sources":["../../src/hyperspell.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,UAAU,SAAS;IACvB,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAAE,CAAC;IAC3D,OAAO,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const generateReportTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
6
|
+
topic: import("@sinclair/typebox").TString;
|
|
7
|
+
}>;
|
|
8
|
+
execute(_id: string, params: unknown): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=generate-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-report.d.ts","sourceRoot":"","sources":["../../../src/tools/generate-report.ts"],"names":[],"mappings":"AA0DA,eAAO,MAAM,kBAAkB;;;;;;;iBAQV,MAAM,UAAU,OAAO;;;;;;CA2D3C,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
3
|
+
import { getConfig } from "../config.js";
|
|
4
|
+
import { searchMemoriesTool } from "./search-memories.js";
|
|
5
|
+
import { webSearchTool } from "./web-search.js";
|
|
6
|
+
import { rememberInsightTool } from "./remember-insight.js";
|
|
7
|
+
const SYSTEM_PROMPT = `You are Mosaic, an opinionated market intelligence agent. Your job is to cut through noise and deliver sharp strategic insight by combining your team's internal knowledge with current market signals.
|
|
8
|
+
|
|
9
|
+
When generating a report, always:
|
|
10
|
+
- Run 2-3 targeted mosaic_search_memories queries to surface internal context
|
|
11
|
+
- Run 2-3 mosaic_web_search queries to capture market trends and competitor moves
|
|
12
|
+
- Save 2-3 key non-obvious insights with mosaic_remember_insight so future reports are smarter
|
|
13
|
+
- Synthesize both into a structured, opinionated report
|
|
14
|
+
|
|
15
|
+
Output in this exact format:
|
|
16
|
+
|
|
17
|
+
# Market Report: [Topic]
|
|
18
|
+
_Generated by Mosaic_
|
|
19
|
+
|
|
20
|
+
## Executive Summary
|
|
21
|
+
2-3 sentences capturing the single most important insight.
|
|
22
|
+
|
|
23
|
+
## Market Trends
|
|
24
|
+
Current dynamics, growth signals, and emerging patterns from the web.
|
|
25
|
+
|
|
26
|
+
## Internal Context
|
|
27
|
+
What the team already knows — signals from Slack, emails, docs.
|
|
28
|
+
|
|
29
|
+
## Competitive Landscape
|
|
30
|
+
Key players, recent moves, differentiation opportunities.
|
|
31
|
+
|
|
32
|
+
## Recommendations
|
|
33
|
+
3 concrete, actionable next steps.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
_Sources: [list sources used]_
|
|
37
|
+
|
|
38
|
+
Be specific, not generic. Surface the non-obvious. Skip filler. Do not add disclaimers about missing data.`;
|
|
39
|
+
// Internal tools used by the report generation loop
|
|
40
|
+
const INTERNAL_TOOLS = [searchMemoriesTool, webSearchTool, rememberInsightTool];
|
|
41
|
+
const ANTHROPIC_TOOL_DEFS = INTERNAL_TOOLS.map((t) => ({
|
|
42
|
+
name: t.name,
|
|
43
|
+
description: t.description,
|
|
44
|
+
input_schema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: Object.fromEntries(Object.entries(t.parameters.properties ?? {}).map(([k, v]) => [
|
|
47
|
+
k,
|
|
48
|
+
{ type: v.type, description: v.description },
|
|
49
|
+
])),
|
|
50
|
+
required: Object.keys(t.parameters.properties ?? {}),
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
export const generateReportTool = {
|
|
54
|
+
name: "mosaic_generate_report",
|
|
55
|
+
label: "Generate Market Report",
|
|
56
|
+
description: "Generate a full market intelligence report on a topic. Searches internal knowledge and the web, synthesizes findings, and saves key insights back to memory.",
|
|
57
|
+
parameters: Type.Object({
|
|
58
|
+
topic: Type.String({ description: "The topic, market, or product area to report on." }),
|
|
59
|
+
}),
|
|
60
|
+
async execute(_id, params) {
|
|
61
|
+
const { topic } = params;
|
|
62
|
+
const config = getConfig();
|
|
63
|
+
const apiKey = config.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
64
|
+
if (!apiKey) {
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: "Anthropic API key not configured. Set it in plugin config or ANTHROPIC_API_KEY env var.",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const anthropic = new Anthropic({ apiKey });
|
|
75
|
+
const messages = [
|
|
76
|
+
{ role: "user", content: `Generate a market report on: ${topic}` },
|
|
77
|
+
];
|
|
78
|
+
try {
|
|
79
|
+
while (true) {
|
|
80
|
+
const response = await anthropic.messages.create({
|
|
81
|
+
model: "claude-opus-4-6",
|
|
82
|
+
max_tokens: 4096,
|
|
83
|
+
system: SYSTEM_PROMPT,
|
|
84
|
+
tools: ANTHROPIC_TOOL_DEFS,
|
|
85
|
+
messages,
|
|
86
|
+
});
|
|
87
|
+
if (response.stop_reason === "end_turn") {
|
|
88
|
+
const textBlock = response.content.find((b) => b.type === "text");
|
|
89
|
+
const text = textBlock ? textBlock.text : "No report generated.";
|
|
90
|
+
return { content: [{ type: "text", text }] };
|
|
91
|
+
}
|
|
92
|
+
messages.push({ role: "assistant", content: response.content });
|
|
93
|
+
const toolResults = [];
|
|
94
|
+
for (const block of response.content) {
|
|
95
|
+
if (block.type !== "tool_use")
|
|
96
|
+
continue;
|
|
97
|
+
const tool = INTERNAL_TOOLS.find((t) => t.name === block.name);
|
|
98
|
+
let resultText = "Tool not found.";
|
|
99
|
+
if (tool) {
|
|
100
|
+
const res = await tool.execute(block.id, block.input);
|
|
101
|
+
resultText = res.content[0]?.text ?? "";
|
|
102
|
+
}
|
|
103
|
+
toolResults.push({ type: "tool_result", tool_use_id: block.id, content: resultText });
|
|
104
|
+
}
|
|
105
|
+
messages.push({ role: "user", content: toolResults });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: "text", text: `Report generation failed: ${e.message}` }],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=generate-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-report.js","sourceRoot":"","sources":["../../../src/tools/generate-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registry — add new tools here and they are automatically registered with OpenClaw.
|
|
3
|
+
*
|
|
4
|
+
* To add a tool:
|
|
5
|
+
* 1. Create src/tools/your-tool.ts following the existing pattern
|
|
6
|
+
* 2. Import it below and add to MOSAIC_TOOLS
|
|
7
|
+
*/
|
|
8
|
+
export declare const MOSAIC_TOOLS: ({
|
|
9
|
+
name: string;
|
|
10
|
+
label: string;
|
|
11
|
+
description: string;
|
|
12
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
13
|
+
query: import("@sinclair/typebox").TString;
|
|
14
|
+
}>;
|
|
15
|
+
execute(_id: string, params: unknown): Promise<{
|
|
16
|
+
content: {
|
|
17
|
+
type: "text";
|
|
18
|
+
text: any;
|
|
19
|
+
}[];
|
|
20
|
+
}>;
|
|
21
|
+
} | {
|
|
22
|
+
name: string;
|
|
23
|
+
label: string;
|
|
24
|
+
description: string;
|
|
25
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
26
|
+
text: import("@sinclair/typebox").TString;
|
|
27
|
+
}>;
|
|
28
|
+
execute(_id: string, params: unknown): Promise<{
|
|
29
|
+
content: {
|
|
30
|
+
type: "text";
|
|
31
|
+
text: string;
|
|
32
|
+
}[];
|
|
33
|
+
}>;
|
|
34
|
+
} | {
|
|
35
|
+
name: string;
|
|
36
|
+
label: string;
|
|
37
|
+
description: string;
|
|
38
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
39
|
+
topic: import("@sinclair/typebox").TString;
|
|
40
|
+
}>;
|
|
41
|
+
execute(_id: string, params: unknown): Promise<{
|
|
42
|
+
content: {
|
|
43
|
+
type: "text";
|
|
44
|
+
text: string;
|
|
45
|
+
}[];
|
|
46
|
+
}>;
|
|
47
|
+
})[];
|
|
48
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAUxB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registry — add new tools here and they are automatically registered with OpenClaw.
|
|
3
|
+
*
|
|
4
|
+
* To add a tool:
|
|
5
|
+
* 1. Create src/tools/your-tool.ts following the existing pattern
|
|
6
|
+
* 2. Import it below and add to MOSAIC_TOOLS
|
|
7
|
+
*/
|
|
8
|
+
import { searchMemoriesTool } from "./search-memories.js";
|
|
9
|
+
import { webSearchTool } from "./web-search.js";
|
|
10
|
+
import { rememberInsightTool } from "./remember-insight.js";
|
|
11
|
+
import { generateReportTool } from "./generate-report.js";
|
|
12
|
+
export const MOSAIC_TOOLS = [
|
|
13
|
+
// Memory & knowledge
|
|
14
|
+
searchMemoriesTool,
|
|
15
|
+
rememberInsightTool,
|
|
16
|
+
// Web research
|
|
17
|
+
webSearchTool,
|
|
18
|
+
// Orchestrated workflows
|
|
19
|
+
generateReportTool,
|
|
20
|
+
];
|
|
21
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,qBAAqB;IACrB,kBAAkB;IAClB,mBAAmB;IAEnB,eAAe;IACf,aAAa;IAEb,yBAAyB;IACzB,kBAAkB;CACnB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const rememberInsightTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
6
|
+
text: import("@sinclair/typebox").TString;
|
|
7
|
+
}>;
|
|
8
|
+
execute(_id: string, params: unknown): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=remember-insight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remember-insight.d.ts","sourceRoot":"","sources":["../../../src/tools/remember-insight.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB;;;;;;;iBAWX,MAAM,UAAU,OAAO;;;;;;CAY3C,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { getClient } from "../hyperspell.js";
|
|
3
|
+
export const rememberInsightTool = {
|
|
4
|
+
name: "mosaic_remember_insight",
|
|
5
|
+
label: "Remember Insight",
|
|
6
|
+
description: "Save a key insight or finding to memory so future reports can reference it. " +
|
|
7
|
+
"Use when you discover something non-obvious — a competitor move, pricing signal, customer pattern, or market trend.",
|
|
8
|
+
parameters: Type.Object({
|
|
9
|
+
text: Type.String({
|
|
10
|
+
description: "The insight to save, written as a clear self-contained fact.",
|
|
11
|
+
}),
|
|
12
|
+
}),
|
|
13
|
+
async execute(_id, params) {
|
|
14
|
+
const { text } = params;
|
|
15
|
+
try {
|
|
16
|
+
const client = getClient();
|
|
17
|
+
await client.memories.add({ text, metadata: { source: "mosaic" } });
|
|
18
|
+
return { content: [{ type: "text", text: "Insight saved." }] };
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: "text", text: `Failed to save insight: ${e.message}` }],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=remember-insight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remember-insight.js","sourceRoot":"","sources":["../../../src/tools/remember-insight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,8EAA8E;QAC9E,qHAAqH;IACvH,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;QACtB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;YAChB,WAAW,EAAE,8DAA8D;SAC5E,CAAC;KACH,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,MAAe;QACxC,MAAM,EAAE,IAAI,EAAE,GAAG,MAA0B,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACpE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;QAC1E,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,2BAA2B,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;aACnF,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const searchMemoriesTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
6
|
+
query: import("@sinclair/typebox").TString;
|
|
7
|
+
}>;
|
|
8
|
+
execute(_id: string, params: unknown): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: any;
|
|
12
|
+
}[];
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=search-memories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-memories.d.ts","sourceRoot":"","sources":["../../../src/tools/search-memories.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,kBAAkB;;;;;;;iBASV,MAAM,UAAU,OAAO;;;;;;CA8C3C,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { getClient } from "../hyperspell.js";
|
|
3
|
+
async function fetchAllWithContent(client) {
|
|
4
|
+
const items = [];
|
|
5
|
+
let cursor;
|
|
6
|
+
do {
|
|
7
|
+
const r = await client.memories.list({ limit: 100, cursor });
|
|
8
|
+
const page = r.body?.items ?? r.items ?? [];
|
|
9
|
+
for (const item of page) {
|
|
10
|
+
try {
|
|
11
|
+
const full = await client.memories.get(item.resource_id, { source: item.source });
|
|
12
|
+
const text = (full.data ?? []).map((d) => d.text ?? "").join("\n").trim();
|
|
13
|
+
const memory = (full.memories ?? []).join(" ").trim();
|
|
14
|
+
items.push({ source: item.source, title: item.title, text: text || memory });
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
items.push({ source: item.source, title: item.title, text: "" });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
cursor = r.body?.next_cursor ?? r.next_cursor;
|
|
21
|
+
if (!cursor || page.length === 0)
|
|
22
|
+
break;
|
|
23
|
+
} while (true);
|
|
24
|
+
return items;
|
|
25
|
+
}
|
|
26
|
+
export const searchMemoriesTool = {
|
|
27
|
+
name: "mosaic_search_memories",
|
|
28
|
+
label: "Search Internal Knowledge",
|
|
29
|
+
description: "Search your team's connected sources (Slack, Gmail, Notion, Drive) for internal context. " +
|
|
30
|
+
"Use to find what the team already knows — past discussions, decisions, emails, docs.",
|
|
31
|
+
parameters: Type.Object({
|
|
32
|
+
query: Type.String({ description: "Search query for internal knowledge" }),
|
|
33
|
+
}),
|
|
34
|
+
async execute(_id, params) {
|
|
35
|
+
const { query } = params;
|
|
36
|
+
try {
|
|
37
|
+
const client = getClient();
|
|
38
|
+
// Try semantic search first
|
|
39
|
+
const result = await client.memories.search({ query, answer: false });
|
|
40
|
+
const documents = result.documents ?? result.results ?? [];
|
|
41
|
+
if (documents.length > 0) {
|
|
42
|
+
const text = documents
|
|
43
|
+
.map((m) => {
|
|
44
|
+
const src = m.source ?? "unknown";
|
|
45
|
+
const title = m.title ? `${m.title}\n` : "";
|
|
46
|
+
const snippet = (m.text ?? m.content ?? "").slice(0, 400);
|
|
47
|
+
return `[${src}] ${title}${snippet}`;
|
|
48
|
+
})
|
|
49
|
+
.join("\n\n---\n\n");
|
|
50
|
+
return { content: [{ type: "text", text }] };
|
|
51
|
+
}
|
|
52
|
+
// Fallback: fetch all memories and do keyword match
|
|
53
|
+
console.log(`[mosaic] search API returned 0 results for "${query}", falling back to full fetch`);
|
|
54
|
+
const allItems = await fetchAllWithContent(client);
|
|
55
|
+
if (allItems.length === 0) {
|
|
56
|
+
return { content: [{ type: "text", text: "No internal sources connected yet." }] };
|
|
57
|
+
}
|
|
58
|
+
const q = query.toLowerCase();
|
|
59
|
+
const matched = allItems.filter((m) => m.title?.toLowerCase().includes(q) || m.text?.toLowerCase().includes(q));
|
|
60
|
+
const results = matched.length > 0 ? matched : allItems; // if no keyword match, return all
|
|
61
|
+
const text = results
|
|
62
|
+
.map((m) => {
|
|
63
|
+
const snippet = (m.text ?? "").slice(0, 600);
|
|
64
|
+
return `[${m.source}] ${m.title}\n${snippet}`;
|
|
65
|
+
})
|
|
66
|
+
.join("\n\n---\n\n");
|
|
67
|
+
return { content: [{ type: "text", text }] };
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
return { content: [{ type: "text", text: `Memory search failed: ${e.message}` }] };
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=search-memories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-memories.js","sourceRoot":"","sources":["../../../src/tools/search-memories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const webSearchTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
6
|
+
query: import("@sinclair/typebox").TString;
|
|
7
|
+
}>;
|
|
8
|
+
execute(_id: string, params: unknown): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=web-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../../src/tools/web-search.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa;;;;;;;iBAQL,MAAM,UAAU,OAAO;;;;;;CAqC3C,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { getConfig } from "../config.js";
|
|
3
|
+
export const webSearchTool = {
|
|
4
|
+
name: "mosaic_web_search",
|
|
5
|
+
label: "Web Search",
|
|
6
|
+
description: "Search the web for current market trends, competitor news, industry data, and recent developments.",
|
|
7
|
+
parameters: Type.Object({
|
|
8
|
+
query: Type.String({ description: "Web search query for market trends and news" }),
|
|
9
|
+
}),
|
|
10
|
+
async execute(_id, params) {
|
|
11
|
+
const { query } = params;
|
|
12
|
+
const { tavilyApiKey } = getConfig();
|
|
13
|
+
if (!tavilyApiKey) {
|
|
14
|
+
return {
|
|
15
|
+
content: [
|
|
16
|
+
{
|
|
17
|
+
type: "text",
|
|
18
|
+
text: "Web search is not configured. Add a Tavily API key to enable it.",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch("https://api.tavily.com/search", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
api_key: tavilyApiKey,
|
|
29
|
+
query,
|
|
30
|
+
max_results: 5,
|
|
31
|
+
include_answer: true,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
const data = (await res.json());
|
|
35
|
+
const lines = [];
|
|
36
|
+
if (data.answer)
|
|
37
|
+
lines.push(`${data.answer}\n`);
|
|
38
|
+
for (const r of data.results ?? []) {
|
|
39
|
+
lines.push(`• ${r.title}\n ${r.url}\n ${(r.content ?? "").slice(0, 250)}`);
|
|
40
|
+
}
|
|
41
|
+
return { content: [{ type: "text", text: lines.join("\n\n") || "No results." }] };
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
return { content: [{ type: "text", text: `Web search failed: ${e.message}` }] };
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=web-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../../src/tools/web-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,YAAY;IACnB,WAAW,EACT,oGAAoG;IACtG,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;QACtB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;KACnF,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,GAAW,EAAE,MAAe;QACxC,MAAM,EAAE,KAAK,EAAE,GAAG,MAA2B,CAAC;QAC9C,MAAM,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAAC;QAErC,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,kEAAkE;qBACzE;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,+BAA+B,EAAE;gBACvD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,OAAO,EAAE,YAAY;oBACrB,KAAK;oBACL,WAAW,EAAE,CAAC;oBACd,cAAc,EAAE,IAAI;iBACrB,CAAC;aACH,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAQ,CAAC;YACvC,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YAChD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACnC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,EAAE,CAAC;QAC7F,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,sBAAsB,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QAC3F,CAAC;IACH,CAAC;CACF,CAAC"}
|
package/install.sh
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Colors
|
|
5
|
+
BOLD='\033[1m'
|
|
6
|
+
GREEN='\033[0;32m'
|
|
7
|
+
YELLOW='\033[0;33m'
|
|
8
|
+
RED='\033[0;31m'
|
|
9
|
+
DIM='\033[2m'
|
|
10
|
+
NC='\033[0m'
|
|
11
|
+
|
|
12
|
+
print() { printf "${BOLD}%s${NC}\n" "$1"; }
|
|
13
|
+
success() { printf "${GREEN}✓${NC} %s\n" "$1"; }
|
|
14
|
+
warn() { printf "${YELLOW}!${NC} %s\n" "$1"; }
|
|
15
|
+
err() { printf "${RED}✗${NC} %s\n" "$1"; exit 1; }
|
|
16
|
+
dim() { printf "${DIM}%s${NC}\n" "$1"; }
|
|
17
|
+
skip() { printf "${DIM}– %s (already set up)${NC}\n" "$1"; }
|
|
18
|
+
|
|
19
|
+
echo ""
|
|
20
|
+
echo " ╔════════════════════════════════════════╗"
|
|
21
|
+
echo " ║ Mosaic ║"
|
|
22
|
+
echo " ║ Market intelligence for your team ║"
|
|
23
|
+
echo " ╚════════════════════════════════════════╝"
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
# ── 1. Check Node.js ──────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
29
|
+
err "Node.js is required. Install it from https://nodejs.org (v20+) and re-run."
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
NODE_MAJOR=$(node -e "console.log(process.versions.node.split('.')[0])")
|
|
33
|
+
if [ "$NODE_MAJOR" -lt 20 ]; then
|
|
34
|
+
err "Node.js v20+ required. Found: $(node --version). Upgrade at https://nodejs.org"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
success "Node.js $(node --version)"
|
|
38
|
+
|
|
39
|
+
# ── 2. Install OpenClaw ───────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
if command -v openclaw >/dev/null 2>&1; then
|
|
42
|
+
skip "OpenClaw"
|
|
43
|
+
else
|
|
44
|
+
print "\nInstalling OpenClaw..."
|
|
45
|
+
npm install -g openclaw --silent 2>/dev/null || npm install -g openclaw --ignore-scripts --silent
|
|
46
|
+
success "OpenClaw installed"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# ── 3. Install Mosaic ─────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
if command -v mosaic >/dev/null 2>&1 && openclaw plugins list 2>/dev/null | grep -q "mosaic"; then
|
|
52
|
+
skip "Mosaic"
|
|
53
|
+
else
|
|
54
|
+
print "\nInstalling Mosaic..."
|
|
55
|
+
npm install -g mosaic --silent 2>/dev/null || npm install -g mosaic --ignore-scripts --silent
|
|
56
|
+
PLUGIN_PATH="$(npm root -g)/mosaic"
|
|
57
|
+
openclaw plugins install "$PLUGIN_PATH" 2>/dev/null || true
|
|
58
|
+
success "Mosaic installed"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# ── 4. API Keys ───────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
ENV_FILE="$HOME/.openclaw/.env"
|
|
64
|
+
mkdir -p "$HOME/.openclaw"
|
|
65
|
+
|
|
66
|
+
if [ -f "$ENV_FILE" ] && grep -q "HYPERSPELL_API_KEY" "$ENV_FILE"; then
|
|
67
|
+
skip "API keys"
|
|
68
|
+
else
|
|
69
|
+
echo ""
|
|
70
|
+
print "Connect your sources"
|
|
71
|
+
echo ""
|
|
72
|
+
dim " Hyperspell connects your Slack, Notion, Gmail, and Drive."
|
|
73
|
+
dim " Sign up free at https://hyperspell.com, then grab your API key."
|
|
74
|
+
echo ""
|
|
75
|
+
|
|
76
|
+
printf " Hyperspell API Key: "
|
|
77
|
+
read -r HYPERSPELL_API_KEY
|
|
78
|
+
[ -z "$HYPERSPELL_API_KEY" ] && err "Hyperspell API key is required."
|
|
79
|
+
|
|
80
|
+
printf " Hyperspell User ID: "
|
|
81
|
+
read -r HYPERSPELL_USER_ID
|
|
82
|
+
[ -z "$HYPERSPELL_USER_ID" ] && err "Hyperspell User ID is required."
|
|
83
|
+
|
|
84
|
+
echo ""
|
|
85
|
+
dim " Anthropic API key — https://console.anthropic.com"
|
|
86
|
+
echo ""
|
|
87
|
+
printf " Anthropic API Key: "
|
|
88
|
+
read -r ANTHROPIC_API_KEY
|
|
89
|
+
[ -z "$ANTHROPIC_API_KEY" ] && err "Anthropic API key is required."
|
|
90
|
+
|
|
91
|
+
echo ""
|
|
92
|
+
dim " (Optional) Tavily for web search — https://tavily.com"
|
|
93
|
+
echo ""
|
|
94
|
+
printf " Tavily API Key (enter to skip): "
|
|
95
|
+
read -r TAVILY_API_KEY
|
|
96
|
+
|
|
97
|
+
cat > "$ENV_FILE" << EOF
|
|
98
|
+
HYPERSPELL_API_KEY=$HYPERSPELL_API_KEY
|
|
99
|
+
HYPERSPELL_USER_ID=$HYPERSPELL_USER_ID
|
|
100
|
+
ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY
|
|
101
|
+
EOF
|
|
102
|
+
[ -n "$TAVILY_API_KEY" ] && echo "TAVILY_API_KEY=$TAVILY_API_KEY" >> "$ENV_FILE"
|
|
103
|
+
success "API keys saved"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# ── 5. Slack ──────────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
if [ -f "$ENV_FILE" ] && grep -q "SLACK_BOT_TOKEN" "$ENV_FILE"; then
|
|
109
|
+
skip "Slack"
|
|
110
|
+
else
|
|
111
|
+
echo ""
|
|
112
|
+
print "Connect Slack"
|
|
113
|
+
echo ""
|
|
114
|
+
dim " Create a Slack app at https://api.slack.com/apps"
|
|
115
|
+
dim " Need: Bot Token (xoxb-...) and App-Level Token (xapp-...)"
|
|
116
|
+
dim " See setup guide: https://github.com/agg111/mosaic#slack-setup"
|
|
117
|
+
echo ""
|
|
118
|
+
|
|
119
|
+
printf " Slack Bot Token (xoxb-...): "
|
|
120
|
+
read -r SLACK_BOT_TOKEN
|
|
121
|
+
[ -z "$SLACK_BOT_TOKEN" ] && err "Slack bot token is required."
|
|
122
|
+
|
|
123
|
+
printf " Slack App Token (xapp-...): "
|
|
124
|
+
read -r SLACK_APP_TOKEN
|
|
125
|
+
[ -z "$SLACK_APP_TOKEN" ] && err "Slack app token is required."
|
|
126
|
+
|
|
127
|
+
cat >> "$ENV_FILE" << EOF
|
|
128
|
+
SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN
|
|
129
|
+
SLACK_APP_TOKEN=$SLACK_APP_TOKEN
|
|
130
|
+
EOF
|
|
131
|
+
success "Slack tokens saved"
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# ── 6. Write openclaw.json ────────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
CONFIG_FILE="$HOME/.openclaw/openclaw.json"
|
|
137
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
138
|
+
skip "OpenClaw config"
|
|
139
|
+
else
|
|
140
|
+
cat > "$CONFIG_FILE" << 'EOF'
|
|
141
|
+
{
|
|
142
|
+
"channels": {
|
|
143
|
+
"slack": {
|
|
144
|
+
"mode": "socket",
|
|
145
|
+
"enabled": true,
|
|
146
|
+
"botToken": "${SLACK_BOT_TOKEN}",
|
|
147
|
+
"appToken": "${SLACK_APP_TOKEN}",
|
|
148
|
+
"groupPolicy": "open",
|
|
149
|
+
"dmPolicy": "open",
|
|
150
|
+
"allowFrom": ["*"],
|
|
151
|
+
"nativeStreaming": true,
|
|
152
|
+
"streaming": "partial"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"plugins": {
|
|
156
|
+
"allow": ["mosaic"],
|
|
157
|
+
"entries": {
|
|
158
|
+
"mosaic": {
|
|
159
|
+
"enabled": true,
|
|
160
|
+
"config": {
|
|
161
|
+
"hyperspellApiKey": "${HYPERSPELL_API_KEY}",
|
|
162
|
+
"hyperspellUserId": "${HYPERSPELL_USER_ID}",
|
|
163
|
+
"anthropicApiKey": "${ANTHROPIC_API_KEY}",
|
|
164
|
+
"tavilyApiKey": "${TAVILY_API_KEY}"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"gateway": {
|
|
170
|
+
"mode": "local"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
EOF
|
|
174
|
+
success "OpenClaw config written"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
openclaw config set gateway.mode local >/dev/null 2>&1 || true
|
|
178
|
+
|
|
179
|
+
# ── 7. Done ───────────────────────────────────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
echo ""
|
|
182
|
+
echo " ╔════════════════════════════════════════╗"
|
|
183
|
+
echo " ║ Mosaic is ready! ║"
|
|
184
|
+
echo " ╚════════════════════════════════════════╝"
|
|
185
|
+
echo ""
|
|
186
|
+
echo " Next steps:"
|
|
187
|
+
echo ""
|
|
188
|
+
echo " 1. Connect your sources at https://hyperspell.com"
|
|
189
|
+
echo " (Slack, Notion, Gmail, Google Drive)"
|
|
190
|
+
echo ""
|
|
191
|
+
echo " 2. Start Mosaic:"
|
|
192
|
+
echo ""
|
|
193
|
+
echo " mosaic start"
|
|
194
|
+
echo ""
|
|
195
|
+
echo " Then @mention Mosaic in any Slack channel."
|
|
196
|
+
echo ""
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mosaic",
|
|
3
|
+
"name": "Mosaic",
|
|
4
|
+
"description": "Market intelligence agent — search internal knowledge and the web to generate strategy reports",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"hyperspellApiKey": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Hyperspell API key for memory search"
|
|
13
|
+
},
|
|
14
|
+
"hyperspellUserId": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Your Hyperspell user ID"
|
|
17
|
+
},
|
|
18
|
+
"tavilyApiKey": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Tavily API key for web search (optional — disables web search if omitted)"
|
|
21
|
+
},
|
|
22
|
+
"anthropicApiKey": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Anthropic API key for report generation (falls back to ANTHROPIC_API_KEY env var)"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": ["hyperspellApiKey", "hyperspellUserId"]
|
|
28
|
+
},
|
|
29
|
+
"uiHints": {
|
|
30
|
+
"hyperspellApiKey": {
|
|
31
|
+
"label": "Hyperspell API Key",
|
|
32
|
+
"sensitive": true,
|
|
33
|
+
"placeholder": "hs-..."
|
|
34
|
+
},
|
|
35
|
+
"hyperspellUserId": {
|
|
36
|
+
"label": "Hyperspell User ID",
|
|
37
|
+
"placeholder": "your-username"
|
|
38
|
+
},
|
|
39
|
+
"tavilyApiKey": {
|
|
40
|
+
"label": "Tavily API Key (web search)",
|
|
41
|
+
"sensitive": true,
|
|
42
|
+
"placeholder": "tvly-..."
|
|
43
|
+
},
|
|
44
|
+
"anthropicApiKey": {
|
|
45
|
+
"label": "Anthropic API Key",
|
|
46
|
+
"sensitive": true,
|
|
47
|
+
"placeholder": "sk-ant-..."
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "getmosaic",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Market intelligence agent — distills signals from your team and the market into strategic clarity",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"mosaic": "./bin/mosaic.sh"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"bin",
|
|
14
|
+
"install.sh",
|
|
15
|
+
"openclaw.plugin.json",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"dev": "tsc --watch",
|
|
21
|
+
"prepare": "tsc"
|
|
22
|
+
},
|
|
23
|
+
"openclaw": {
|
|
24
|
+
"extensions": ["./dist/index.js"]
|
|
25
|
+
},
|
|
26
|
+
"keywords": ["openclaw", "plugin", "market-intelligence", "hyperspell", "ai-agent"],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@anthropic-ai/sdk": "^0.80.0",
|
|
29
|
+
"@sinclair/typebox": "^0.34.0",
|
|
30
|
+
"hyperspell": "^0.35.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"openclaw": "*"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^22.0.0",
|
|
37
|
+
"typescript": "^5.5.0"
|
|
38
|
+
}
|
|
39
|
+
}
|