@geravant/sinain 1.0.18 → 1.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.
Files changed (89) hide show
  1. package/README.md +10 -1
  2. package/cli.js +176 -0
  3. package/index.ts +163 -1257
  4. package/install.js +12 -2
  5. package/launcher.js +622 -0
  6. package/openclaw.plugin.json +4 -0
  7. package/pack-prepare.js +48 -0
  8. package/package.json +26 -5
  9. package/sense_client/README.md +82 -0
  10. package/sense_client/__init__.py +1 -0
  11. package/sense_client/__main__.py +462 -0
  12. package/sense_client/app_detector.py +54 -0
  13. package/sense_client/app_detector_win.py +83 -0
  14. package/sense_client/capture.py +215 -0
  15. package/sense_client/capture_win.py +88 -0
  16. package/sense_client/change_detector.py +86 -0
  17. package/sense_client/config.py +64 -0
  18. package/sense_client/gate.py +145 -0
  19. package/sense_client/ocr.py +347 -0
  20. package/sense_client/privacy.py +65 -0
  21. package/sense_client/requirements.txt +13 -0
  22. package/sense_client/roi_extractor.py +84 -0
  23. package/sense_client/sender.py +173 -0
  24. package/sense_client/tests/__init__.py +0 -0
  25. package/sense_client/tests/test_stream1_optimizations.py +234 -0
  26. package/setup-overlay.js +82 -0
  27. package/sinain-agent/.env.example +17 -0
  28. package/sinain-agent/CLAUDE.md +80 -0
  29. package/sinain-agent/mcp-config.json +12 -0
  30. package/sinain-agent/run.sh +248 -0
  31. package/sinain-core/.env.example +93 -0
  32. package/sinain-core/package-lock.json +552 -0
  33. package/sinain-core/package.json +21 -0
  34. package/sinain-core/src/agent/analyzer.ts +366 -0
  35. package/sinain-core/src/agent/context-window.ts +172 -0
  36. package/sinain-core/src/agent/loop.ts +404 -0
  37. package/sinain-core/src/agent/situation-writer.ts +187 -0
  38. package/sinain-core/src/agent/traits.ts +520 -0
  39. package/sinain-core/src/audio/capture-spawner-macos.ts +44 -0
  40. package/sinain-core/src/audio/capture-spawner-win.ts +37 -0
  41. package/sinain-core/src/audio/capture-spawner.ts +14 -0
  42. package/sinain-core/src/audio/pipeline.ts +335 -0
  43. package/sinain-core/src/audio/transcription-local.ts +141 -0
  44. package/sinain-core/src/audio/transcription.ts +278 -0
  45. package/sinain-core/src/buffers/feed-buffer.ts +71 -0
  46. package/sinain-core/src/buffers/sense-buffer.ts +425 -0
  47. package/sinain-core/src/config.ts +245 -0
  48. package/sinain-core/src/escalation/escalation-slot.ts +136 -0
  49. package/sinain-core/src/escalation/escalator.ts +812 -0
  50. package/sinain-core/src/escalation/message-builder.ts +323 -0
  51. package/sinain-core/src/escalation/openclaw-ws.ts +726 -0
  52. package/sinain-core/src/escalation/scorer.ts +166 -0
  53. package/sinain-core/src/index.ts +507 -0
  54. package/sinain-core/src/learning/feedback-store.ts +253 -0
  55. package/sinain-core/src/learning/signal-collector.ts +218 -0
  56. package/sinain-core/src/log.ts +24 -0
  57. package/sinain-core/src/overlay/commands.ts +126 -0
  58. package/sinain-core/src/overlay/ws-handler.ts +267 -0
  59. package/sinain-core/src/privacy/index.ts +18 -0
  60. package/sinain-core/src/privacy/presets.ts +40 -0
  61. package/sinain-core/src/privacy/redact.ts +92 -0
  62. package/sinain-core/src/profiler.ts +181 -0
  63. package/sinain-core/src/recorder.ts +186 -0
  64. package/sinain-core/src/server.ts +417 -0
  65. package/sinain-core/src/trace/trace-store.ts +73 -0
  66. package/sinain-core/src/trace/tracer.ts +94 -0
  67. package/sinain-core/src/types.ts +427 -0
  68. package/sinain-core/src/util/dedup.ts +48 -0
  69. package/sinain-core/src/util/task-store.ts +84 -0
  70. package/sinain-core/tsconfig.json +18 -0
  71. package/sinain-knowledge/adapters/generic/adapter.ts +103 -0
  72. package/sinain-knowledge/adapters/interface.ts +72 -0
  73. package/sinain-knowledge/adapters/openclaw/adapter.ts +223 -0
  74. package/sinain-knowledge/curation/engine.ts +493 -0
  75. package/sinain-knowledge/curation/resilience.ts +336 -0
  76. package/sinain-knowledge/data/git-store.ts +312 -0
  77. package/sinain-knowledge/data/schema.ts +89 -0
  78. package/sinain-knowledge/data/snapshot.ts +226 -0
  79. package/sinain-knowledge/data/store.ts +488 -0
  80. package/sinain-knowledge/deploy/cli.ts +214 -0
  81. package/sinain-knowledge/deploy/manifest.ts +80 -0
  82. package/sinain-knowledge/protocol/bindings/generic.md +5 -0
  83. package/sinain-knowledge/protocol/bindings/openclaw.md +5 -0
  84. package/sinain-knowledge/protocol/heartbeat.md +62 -0
  85. package/sinain-knowledge/protocol/renderer.ts +56 -0
  86. package/sinain-knowledge/protocol/skill.md +335 -0
  87. package/sinain-mcp-server/index.ts +337 -0
  88. package/sinain-mcp-server/package.json +19 -0
  89. package/sinain-mcp-server/tsconfig.json +15 -0
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { execFile } from "node:child_process";
6
+ import { readFileSync, readdirSync, existsSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+ import os from "node:os";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Configuration
12
+ // ---------------------------------------------------------------------------
13
+
14
+ const SINAIN_CORE_URL = process.env.SINAIN_CORE_URL || "http://localhost:9500";
15
+ const WORKSPACE = (process.env.SINAIN_WORKSPACE || "~/.openclaw/workspace").replace(/^~/, os.homedir());
16
+ const MEMORY_DIR = resolve(WORKSPACE, "memory");
17
+ const MODULES_DIR = resolve(WORKSPACE, "modules");
18
+
19
+ const SCRIPTS_CANDIDATES = [
20
+ resolve(WORKSPACE, "sinain-memory"),
21
+ resolve(import.meta.dirname || ".", "..", "sinain-hud-plugin", "sinain-memory"),
22
+ ];
23
+ const SCRIPTS_DIR = SCRIPTS_CANDIDATES.find((d) => existsSync(d)) || SCRIPTS_CANDIDATES[0];
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Helpers
27
+ // ---------------------------------------------------------------------------
28
+
29
+ function stripPrivateTags(text: string): string {
30
+ return text.replace(/<private>[\s\S]*?<\/private>/g, "[REDACTED]");
31
+ }
32
+
33
+ async function coreRequest(method: string, path: string, body?: unknown): Promise<any> {
34
+ const url = `${SINAIN_CORE_URL}${path}`;
35
+ const opts: RequestInit = {
36
+ method,
37
+ headers: { "Content-Type": "application/json" },
38
+ };
39
+ if (body) opts.body = JSON.stringify(body);
40
+ const res = await fetch(url, opts);
41
+ const json = await res.json();
42
+ return json;
43
+ }
44
+
45
+ function runScript(args: string[], timeoutMs = 30_000): Promise<string> {
46
+ return new Promise((resolve, reject) => {
47
+ execFile(
48
+ "python3",
49
+ args,
50
+ {
51
+ timeout: timeoutMs,
52
+ maxBuffer: 10 * 1024 * 1024,
53
+ env: { ...process.env },
54
+ },
55
+ (err, stdout, stderr) => {
56
+ if (err) reject(new Error(`Script failed: ${err.message}\n${stderr}`));
57
+ else resolve(stdout);
58
+ },
59
+ );
60
+ });
61
+ }
62
+
63
+ function textResult(text: string) {
64
+ return { content: [{ type: "text" as const, text }] };
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Server
69
+ // ---------------------------------------------------------------------------
70
+
71
+ const server = new McpServer({
72
+ name: "sinain-mcp-server",
73
+ version: "0.1.0",
74
+ });
75
+
76
+ // 1. sinain_get_escalation
77
+ server.tool(
78
+ "sinain_get_escalation",
79
+ "Get the current pending escalation from sinain-core",
80
+ {},
81
+ async () => {
82
+ try {
83
+ const data = await coreRequest("GET", "/escalation/pending");
84
+ if (!data || (data.status && data.status === "none")) {
85
+ return textResult("No pending escalation");
86
+ }
87
+ return textResult(stripPrivateTags(JSON.stringify(data, null, 2)));
88
+ } catch (err: any) {
89
+ return textResult(`Error fetching escalation: ${err.message}`);
90
+ }
91
+ },
92
+ );
93
+
94
+ // 2. sinain_respond
95
+ server.tool(
96
+ "sinain_respond",
97
+ "Respond to a pending escalation",
98
+ { id: z.string(), response: z.string() },
99
+ async ({ id, response }) => {
100
+ try {
101
+ const data = await coreRequest("POST", "/escalation/respond", { id, response });
102
+ return textResult(JSON.stringify(data, null, 2));
103
+ } catch (err: any) {
104
+ return textResult(`Error responding to escalation: ${err.message}`);
105
+ }
106
+ },
107
+ );
108
+
109
+ // 3. sinain_get_context
110
+ server.tool(
111
+ "sinain_get_context",
112
+ "Get the current agent context window from sinain-core (screen + audio + feed)",
113
+ {},
114
+ async () => {
115
+ try {
116
+ const data = await coreRequest("GET", "/agent/context");
117
+ return textResult(stripPrivateTags(JSON.stringify(data, null, 2)));
118
+ } catch (err: any) {
119
+ return textResult(`Error fetching context: ${err.message}`);
120
+ }
121
+ },
122
+ );
123
+
124
+ // 4. sinain_get_digest
125
+ server.tool(
126
+ "sinain_get_digest",
127
+ "Get the latest agent digest from sinain-core",
128
+ {},
129
+ async () => {
130
+ try {
131
+ const data = await coreRequest("GET", "/agent/digest");
132
+ return textResult(JSON.stringify(data, null, 2));
133
+ } catch (err: any) {
134
+ return textResult(`Error fetching digest: ${err.message}`);
135
+ }
136
+ },
137
+ );
138
+
139
+ // 5. sinain_get_feedback
140
+ server.tool(
141
+ "sinain_get_feedback",
142
+ "Get recent learning feedback entries",
143
+ { limit: z.number().optional().default(20) },
144
+ async ({ limit }) => {
145
+ try {
146
+ const data = await coreRequest("GET", `/learning/feedback?limit=${limit}`);
147
+ return textResult(JSON.stringify(data, null, 2));
148
+ } catch (err: any) {
149
+ return textResult(`Error fetching feedback: ${err.message}`);
150
+ }
151
+ },
152
+ );
153
+
154
+ // 6. sinain_post_feed
155
+ server.tool(
156
+ "sinain_post_feed",
157
+ "Post a message to the sinain-core HUD feed",
158
+ {
159
+ text: z.string(),
160
+ priority: z.enum(["normal", "high", "urgent"]).optional().default("normal"),
161
+ },
162
+ async ({ text, priority }) => {
163
+ try {
164
+ const data = await coreRequest("POST", "/feed", { text, priority });
165
+ return textResult(JSON.stringify(data, null, 2));
166
+ } catch (err: any) {
167
+ return textResult(`Error posting to feed: ${err.message}`);
168
+ }
169
+ },
170
+ );
171
+
172
+ // 7. sinain_health
173
+ server.tool(
174
+ "sinain_health",
175
+ "Check sinain-core health status",
176
+ {},
177
+ async () => {
178
+ try {
179
+ const data = await coreRequest("GET", "/health");
180
+ return textResult(JSON.stringify(data, null, 2));
181
+ } catch (err: any) {
182
+ return textResult(`Error checking health: ${err.message}`);
183
+ }
184
+ },
185
+ );
186
+
187
+ // 8. sinain_knowledge_query
188
+ server.tool(
189
+ "sinain_knowledge_query",
190
+ "Query the knowledge graph / memory triples for relevant context",
191
+ {
192
+ context: z.string(),
193
+ max_chars: z.number().optional().default(1500),
194
+ },
195
+ async ({ context, max_chars }) => {
196
+ try {
197
+ const scriptPath = resolve(SCRIPTS_DIR, "triple_query.py");
198
+ const output = await runScript([
199
+ scriptPath,
200
+ "--memory-dir", MEMORY_DIR,
201
+ "--context", context,
202
+ "--max-chars", String(max_chars),
203
+ ]);
204
+ return textResult(stripPrivateTags(output));
205
+ } catch (err: any) {
206
+ return textResult(`Error querying knowledge: ${err.message}`);
207
+ }
208
+ },
209
+ );
210
+
211
+ // 9. sinain_heartbeat_tick
212
+ server.tool(
213
+ "sinain_heartbeat_tick",
214
+ "Run the full heartbeat knowledge pipeline (signal analysis, insight synthesis, memory mining, playbook curation)",
215
+ {
216
+ session_summary: z.string().optional().default("Bare agent heartbeat tick"),
217
+ },
218
+ async ({ session_summary }) => {
219
+ const results: string[] = [];
220
+ const now = new Date().toISOString();
221
+
222
+ // Step 1: git_backup.sh
223
+ const gitBackupPath = resolve(SCRIPTS_DIR, "git_backup.sh");
224
+ if (existsSync(gitBackupPath)) {
225
+ try {
226
+ const out = await new Promise<string>((res, rej) => {
227
+ execFile("bash", [gitBackupPath, MEMORY_DIR], { timeout: 30_000 }, (err, stdout, stderr) => {
228
+ if (err) rej(new Error(`git_backup failed: ${err.message}\n${stderr}`));
229
+ else res(stdout);
230
+ });
231
+ });
232
+ results.push(`[git_backup] ${out.trim() || "OK"}`);
233
+ } catch (err: any) {
234
+ results.push(`[git_backup] FAILED: ${err.message}`);
235
+ }
236
+ }
237
+
238
+ // Step 2: signal_analyzer.py
239
+ try {
240
+ const out = await runScript([
241
+ resolve(SCRIPTS_DIR, "signal_analyzer.py"),
242
+ "--memory-dir", MEMORY_DIR,
243
+ "--session-summary", session_summary,
244
+ "--current-time", now,
245
+ ]);
246
+ results.push(`[signal_analyzer] ${out.trim() || "OK"}`);
247
+ } catch (err: any) {
248
+ results.push(`[signal_analyzer] FAILED: ${err.message}`);
249
+ }
250
+
251
+ // Step 3: insight_synthesizer.py
252
+ try {
253
+ const out = await runScript([
254
+ resolve(SCRIPTS_DIR, "insight_synthesizer.py"),
255
+ "--memory-dir", MEMORY_DIR,
256
+ "--session-summary", session_summary,
257
+ ]);
258
+ results.push(`[insight_synthesizer] ${out.trim() || "OK"}`);
259
+ } catch (err: any) {
260
+ results.push(`[insight_synthesizer] FAILED: ${err.message}`);
261
+ }
262
+
263
+ // Step 4: memory_miner.py
264
+ try {
265
+ const out = await runScript([
266
+ resolve(SCRIPTS_DIR, "memory_miner.py"),
267
+ "--memory-dir", MEMORY_DIR,
268
+ ]);
269
+ results.push(`[memory_miner] ${out.trim() || "OK"}`);
270
+ } catch (err: any) {
271
+ results.push(`[memory_miner] FAILED: ${err.message}`);
272
+ }
273
+
274
+ // Step 5: playbook_curator.py
275
+ try {
276
+ const out = await runScript([
277
+ resolve(SCRIPTS_DIR, "playbook_curator.py"),
278
+ "--memory-dir", MEMORY_DIR,
279
+ "--session-summary", session_summary,
280
+ ]);
281
+ results.push(`[playbook_curator] ${out.trim() || "OK"}`);
282
+ } catch (err: any) {
283
+ results.push(`[playbook_curator] FAILED: ${err.message}`);
284
+ }
285
+
286
+ return textResult(stripPrivateTags(results.join("\n\n")));
287
+ },
288
+ );
289
+
290
+ // 10. sinain_module_guidance
291
+ server.tool(
292
+ "sinain_module_guidance",
293
+ "Read guidance from all active modules in the workspace",
294
+ {},
295
+ async () => {
296
+ try {
297
+ const registryPath = resolve(MODULES_DIR, "module-registry.json");
298
+ if (!existsSync(registryPath)) {
299
+ return textResult("No modules configured");
300
+ }
301
+
302
+ const registry = JSON.parse(readFileSync(registryPath, "utf-8"));
303
+ const modules: Array<{ name: string; active?: boolean }> = Array.isArray(registry)
304
+ ? registry
305
+ : registry.modules || [];
306
+
307
+ const parts: string[] = [];
308
+ for (const mod of modules) {
309
+ if (mod.active === false) continue;
310
+ const guidancePath = resolve(MODULES_DIR, mod.name, "guidance.md");
311
+ if (existsSync(guidancePath)) {
312
+ const content = readFileSync(guidancePath, "utf-8");
313
+ parts.push(`## ${mod.name}\n\n${content}`);
314
+ }
315
+ }
316
+
317
+ if (parts.length === 0) {
318
+ return textResult("No module guidance files found");
319
+ }
320
+ return textResult(stripPrivateTags(parts.join("\n\n---\n\n")));
321
+ } catch (err: any) {
322
+ return textResult(`Error reading module guidance: ${err.message}`);
323
+ }
324
+ },
325
+ );
326
+
327
+ // ---------------------------------------------------------------------------
328
+ // Startup
329
+ // ---------------------------------------------------------------------------
330
+
331
+ async function main() {
332
+ const transport = new StdioServerTransport();
333
+ await server.connect(transport);
334
+ console.error(`sinain-mcp-server started (core=${SINAIN_CORE_URL}, workspace=${WORKSPACE})`);
335
+ }
336
+
337
+ main().catch(console.error);
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "sinain-mcp-server",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "MCP server for sinain-hud bare agent integration",
6
+ "main": "index.ts",
7
+ "scripts": {
8
+ "start": "npx tsx index.ts",
9
+ "build": "tsc"
10
+ },
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "^1.12.1"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^22.19.7",
16
+ "tsx": "^4.21.0",
17
+ "typescript": "^5.9.3"
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "node16",
5
+ "moduleResolution": "node16",
6
+ "outDir": "dist",
7
+ "rootDir": ".",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true
12
+ },
13
+ "include": ["*.ts"],
14
+ "exclude": ["dist"]
15
+ }