@hyperspell/openclaw-hyperspell 0.12.0 → 0.13.1

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 (50) hide show
  1. package/README.md +37 -1
  2. package/dist/client.js +341 -0
  3. package/dist/commands/setup.js +568 -0
  4. package/dist/commands/slash.js +159 -0
  5. package/dist/config.js +349 -0
  6. package/{graph/cron.ts → dist/graph/cron.js} +11 -15
  7. package/dist/graph/index.js +4 -0
  8. package/dist/graph/ops.js +221 -0
  9. package/dist/graph/state.js +68 -0
  10. package/dist/graph/tools.js +87 -0
  11. package/dist/hooks/auto-context.js +199 -0
  12. package/dist/hooks/auto-trace.js +143 -0
  13. package/dist/hooks/emotional-state.js +155 -0
  14. package/dist/hooks/memory-sync.js +54 -0
  15. package/dist/hooks/startup-orientation.js +236 -0
  16. package/dist/index.js +132 -0
  17. package/dist/lib/browser.js +29 -0
  18. package/dist/lib/sender.js +173 -0
  19. package/dist/lib/voice-id.js +22 -0
  20. package/dist/logger.js +32 -0
  21. package/dist/sync/markdown.js +151 -0
  22. package/dist/tools/remember.js +97 -0
  23. package/dist/tools/search.js +87 -0
  24. package/openclaw.plugin.json +25 -1
  25. package/package.json +7 -12
  26. package/client.ts +0 -566
  27. package/commands/setup.ts +0 -673
  28. package/commands/slash.ts +0 -198
  29. package/config.test.ts +0 -202
  30. package/config.ts +0 -497
  31. package/graph/index.ts +0 -5
  32. package/graph/ops.ts +0 -259
  33. package/graph/state.ts +0 -79
  34. package/graph/tools.ts +0 -117
  35. package/hooks/auto-context.ts +0 -272
  36. package/hooks/auto-trace.test.ts +0 -81
  37. package/hooks/auto-trace.ts +0 -197
  38. package/hooks/emotional-state.test.ts +0 -160
  39. package/hooks/emotional-state.ts +0 -179
  40. package/hooks/memory-sync.ts +0 -65
  41. package/index.ts +0 -152
  42. package/lib/browser.ts +0 -31
  43. package/lib/sender.test.ts +0 -234
  44. package/lib/sender.ts +0 -234
  45. package/lib/voice-id.ts +0 -39
  46. package/logger.ts +0 -41
  47. package/sync/markdown.ts +0 -186
  48. package/tools/remember.ts +0 -132
  49. package/tools/search.ts +0 -131
  50. package/types/openclaw.d.ts +0 -76
@@ -0,0 +1,87 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { buildScopeFilter, getCanReadScopes, resolveUser } from "../lib/sender.js";
3
+ import { log } from "../logger.js";
4
+ export function createSearchToolFactory(client, cfg) {
5
+ const scopingEnabled = !!cfg.multiUser?.scoping;
6
+ const availableScopes = cfg.multiUser?.scoping?.scopes ?? [];
7
+ const scopeDescription = scopingEnabled
8
+ ? `Narrow search to a single privacy scope. Available: ${availableScopes.join(", ")}. Omit to search all scopes visible to the caller's role.`
9
+ : "Privacy scope (only used when scoping is enabled in config).";
10
+ return (ctx) => ({
11
+ name: "hyperspell_search",
12
+ label: "Memory Search",
13
+ description: "Search through the user's connected sources (Notion, Slack, Gmail, Google Drive, etc.) for relevant information.",
14
+ parameters: Type.Object({
15
+ query: Type.String({ description: "Search query" }),
16
+ limit: Type.Optional(Type.Number({ description: "Max results (default: 5)" })),
17
+ after: Type.Optional(Type.String({ description: "Only return memories created on or after this date (ISO 8601 or YYYY-MM-DD)" })),
18
+ before: Type.Optional(Type.String({ description: "Only return memories created before this date (ISO 8601 or YYYY-MM-DD)" })),
19
+ userId: Type.Optional(Type.String({
20
+ description: "Search as a specific user (e.g. 'ben', 'shared'). Omit to search as current sender.",
21
+ })),
22
+ scope: Type.Optional(Type.String({ description: scopeDescription })),
23
+ }),
24
+ async execute(_toolCallId, params) {
25
+ const limit = params.limit ?? 5;
26
+ const resolved = resolveUser(ctx, cfg);
27
+ const userId = params.userId ?? resolved?.userId;
28
+ // Build scope filter: intersect requested scope (if any) with caller's canRead
29
+ let filter;
30
+ if (scopingEnabled) {
31
+ const canRead = getCanReadScopes(resolved, cfg);
32
+ const allowed = params.scope
33
+ ? canRead.includes("*")
34
+ ? [params.scope]
35
+ : canRead.includes(params.scope)
36
+ ? [params.scope]
37
+ : [] // requested scope not allowed → match nothing
38
+ : canRead;
39
+ filter = buildScopeFilter(allowed, resolved?.userId ?? "");
40
+ }
41
+ log.debug(`search tool: query="${params.query}" limit=${limit} after=${params.after ?? "none"} before=${params.before ?? "none"} userId=${userId} scope=${params.scope ?? "any"}`);
42
+ try {
43
+ const response = await client.searchRaw(params.query, {
44
+ limit,
45
+ after: params.after,
46
+ before: params.before,
47
+ userId,
48
+ filter,
49
+ });
50
+ const documents = (response.documents ?? []);
51
+ if (documents.length === 0) {
52
+ return {
53
+ content: [
54
+ { type: "text", text: "No relevant memories found." },
55
+ ],
56
+ };
57
+ }
58
+ const formattedDocs = documents
59
+ .map((doc, i) => {
60
+ const relevance = doc.score
61
+ ? `${Math.round(doc.score * 100)}%`
62
+ : "N/A";
63
+ const title = doc.title || "(untitled)";
64
+ const summary = doc.summary || "(no summary)";
65
+ return `${i + 1}. Source: ${doc.source}\n Title: ${title}\n Summary: ${summary}\n Relevance: ${relevance}`;
66
+ })
67
+ .join("\n\n");
68
+ const text = `Found ${documents.length} memories:\n\n${formattedDocs}`;
69
+ return {
70
+ content: [{ type: "text", text }],
71
+ details: { count: documents.length, documents },
72
+ };
73
+ }
74
+ catch (err) {
75
+ log.error("search tool failed", err);
76
+ return {
77
+ content: [
78
+ {
79
+ type: "text",
80
+ text: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
81
+ },
82
+ ],
83
+ };
84
+ }
85
+ },
86
+ });
87
+ }
@@ -2,8 +2,17 @@
2
2
  "id": "openclaw-hyperspell",
3
3
  "name": "Hyperspell",
4
4
  "description": "Context and memory for your AI agents — search across Notion, Slack, Google Drive, and more",
5
- "version": "0.12.0",
5
+ "version": "0.13.0",
6
6
  "kind": "memory",
7
+ "contracts": {
8
+ "tools": [
9
+ "hyperspell_search",
10
+ "hyperspell_remember",
11
+ "hyperspell_network_scan",
12
+ "hyperspell_network_write",
13
+ "hyperspell_network_complete"
14
+ ]
15
+ },
7
16
  "uiHints": {
8
17
  "apiKey": {
9
18
  "label": "Hyperspell API Key",
@@ -32,6 +41,11 @@
32
41
  "help": "Maintain emotional continuity across sessions — remembers not just what happened, but how it felt",
33
42
  "advanced": true
34
43
  },
44
+ "startupOrientation": {
45
+ "label": "Startup Orientation",
46
+ "help": "Inject recent-interactions and unfinished-loops blocks once per session at startup. Costs two extra calls + ~500–800 tokens of injection per session; off by default.",
47
+ "advanced": true
48
+ },
35
49
  "relationshipId": {
36
50
  "label": "Relationship ID",
37
51
  "placeholder": "partner-anna",
@@ -108,6 +122,16 @@
108
122
  "relationshipId": {
109
123
  "type": "string"
110
124
  },
125
+ "startupOrientation": {
126
+ "type": "object",
127
+ "properties": {
128
+ "enabled": { "type": "boolean" },
129
+ "recentDays": { "type": "number", "minimum": 1, "maximum": 90 },
130
+ "recentLimit": { "type": "number", "minimum": 1, "maximum": 20 },
131
+ "loopsLimit": { "type": "number", "minimum": 1, "maximum": 20 },
132
+ "loopsQuery": { "type": "string" }
133
+ }
134
+ },
111
135
  "sources": {
112
136
  "type": "string"
113
137
  },
package/package.json CHANGED
@@ -1,19 +1,12 @@
1
1
  {
2
2
  "name": "@hyperspell/openclaw-hyperspell",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "type": "module",
5
5
  "description": "OpenClaw Hyperspell memory plugin",
6
6
  "license": "MIT",
7
- "main": "./index.ts",
7
+ "main": "./dist/index.js",
8
8
  "files": [
9
- "*.ts",
10
- "commands/",
11
- "hooks/",
12
- "tools/",
13
- "sync/",
14
- "graph/",
15
- "lib/",
16
- "types/",
9
+ "dist/",
17
10
  "openclaw.plugin.json",
18
11
  "README.md"
19
12
  ],
@@ -40,14 +33,16 @@
40
33
  "openclaw": ">=2026.1.29"
41
34
  },
42
35
  "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "prepublishOnly": "npm run build",
43
38
  "check-types": "tsc --noEmit",
44
39
  "lint": "bunx @biomejs/biome ci .",
45
40
  "lint:fix": "bunx @biomejs/biome check --write .",
46
- "test": "node --test --experimental-strip-types lib/sender.test.ts config.test.ts hooks/auto-trace.test.ts hooks/emotional-state.test.ts"
41
+ "test": "node --test --experimental-strip-types lib/sender.test.ts config.test.ts hooks/auto-trace.test.ts hooks/emotional-state.test.ts hooks/startup-orientation.test.ts"
47
42
  },
48
43
  "openclaw": {
49
44
  "extensions": [
50
- "./index.ts"
45
+ "./dist/index.js"
51
46
  ],
52
47
  "hooks": [],
53
48
  "compat": {