@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,248 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+
6
+ # Load .env if present (does not override existing env vars)
7
+ if [ -f "$SCRIPT_DIR/.env" ]; then
8
+ set -a
9
+ # shellcheck source=/dev/null
10
+ . "$SCRIPT_DIR/.env"
11
+ set +a
12
+ fi
13
+
14
+ MCP_CONFIG="${MCP_CONFIG:-$SCRIPT_DIR/mcp-config.json}"
15
+ CORE_URL="${SINAIN_CORE_URL:-http://localhost:9500}"
16
+ POLL_INTERVAL="${SINAIN_POLL_INTERVAL:-5}"
17
+ HEARTBEAT_INTERVAL="${SINAIN_HEARTBEAT_INTERVAL:-900}" # 15 minutes
18
+ AGENT="${SINAIN_AGENT:-claude}"
19
+ WORKSPACE="${SINAIN_WORKSPACE:-$HOME/.openclaw/workspace}"
20
+
21
+ # --- Agent profiles ---
22
+
23
+ # Returns 0 if the selected agent supports MCP tools natively.
24
+ # Junie support is detected at startup (JUNIE_HAS_MCP flag).
25
+ JUNIE_HAS_MCP=false # set during startup checks
26
+ agent_has_mcp() {
27
+ case "$AGENT" in
28
+ claude|codex|goose) return 0 ;;
29
+ junie) $JUNIE_HAS_MCP ;;
30
+ *) return 1 ;;
31
+ esac
32
+ }
33
+
34
+ # Invoke the selected agent with a prompt. MCP-capable agents get the config
35
+ # so they can call sinain tools directly. Returns text on stdout.
36
+ # Exit code 1 means "agent doesn't support MCP — use pipe mode instead".
37
+ invoke_agent() {
38
+ local prompt="$1"
39
+ case "$AGENT" in
40
+ claude)
41
+ claude --dangerously-skip-permissions \
42
+ --mcp-config "$MCP_CONFIG" \
43
+ --max-turns 5 --output-format text \
44
+ -p "$prompt" 2>/dev/null
45
+ ;;
46
+ codex)
47
+ codex exec -s danger-full-access \
48
+ "$prompt" 2>/dev/null
49
+ ;;
50
+ junie)
51
+ if $JUNIE_HAS_MCP; then
52
+ junie --output-format text \
53
+ --mcp-location "$JUNIE_MCP_DIR" \
54
+ --task "$prompt" 2>/dev/null
55
+ else
56
+ return 1
57
+ fi
58
+ ;;
59
+ goose)
60
+ goose run --text "$prompt" \
61
+ --output-format text \
62
+ --max-turns 10 2>/dev/null
63
+ ;;
64
+ aider)
65
+ # No MCP support — signal pipe mode
66
+ return 1
67
+ ;;
68
+ *)
69
+ # Generic pipe mode — treat AGENT value as a command
70
+ return 1
71
+ ;;
72
+ esac
73
+ }
74
+
75
+ # --- Pipe-mode helpers (for agents without MCP) ---
76
+
77
+ # JSON-encode stdin for use in curl payloads
78
+ json_encode() {
79
+ python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))'
80
+ }
81
+
82
+ # Post an escalation response via HTTP (used in pipe mode)
83
+ post_response() {
84
+ local esc_id="$1" response="$2"
85
+ curl -sf -X POST "$CORE_URL/escalation/respond" \
86
+ -H 'Content-Type: application/json' \
87
+ -d "{\"id\":\"$esc_id\",\"response\":$(echo "$response" | json_encode)}" >/dev/null
88
+ }
89
+
90
+ # Invoke a pipe-mode agent with escalation message text.
91
+ # Some agents take the message as an argument, others via stdin.
92
+ invoke_pipe() {
93
+ local msg="$1"
94
+ case "$AGENT" in
95
+ junie)
96
+ junie --output-format text --task "$msg" 2>/dev/null
97
+ ;;
98
+ aider)
99
+ aider --yes -m "$msg" 2>/dev/null
100
+ ;;
101
+ *)
102
+ # Generic: pipe message to stdin
103
+ echo "$msg" | $AGENT 2>/dev/null
104
+ ;;
105
+ esac
106
+ }
107
+
108
+ # --- Startup checks ---
109
+
110
+ # Verify sinain-core is running
111
+ if ! curl -sf "$CORE_URL/health" > /dev/null 2>&1; then
112
+ echo "ERROR: sinain-core is not running at $CORE_URL"
113
+ echo "Start it first: cd sinain-core && npm run dev"
114
+ exit 1
115
+ fi
116
+
117
+ # Junie: detect --mcp-location support (must run before agent_has_mcp calls)
118
+ JUNIE_MCP_DIR="$SCRIPT_DIR/.junie-mcp"
119
+ if [ "$AGENT" = "junie" ]; then
120
+ if junie --help 2>&1 | grep -q "mcp-location"; then
121
+ JUNIE_HAS_MCP=true
122
+ mkdir -p "$JUNIE_MCP_DIR"
123
+ cp "$MCP_CONFIG" "$JUNIE_MCP_DIR/mcp.json"
124
+ else
125
+ echo "NOTE: junie $(junie --version 2>&1 | grep -oE '[0-9.]+' | head -1) lacks --mcp-location, using pipe mode"
126
+ echo " Upgrade junie for MCP support: brew upgrade junie"
127
+ fi
128
+ fi
129
+
130
+ # Verify MCP server dependencies (only needed for MCP agents)
131
+ if agent_has_mcp && [ ! -d "$SCRIPT_DIR/../sinain-mcp-server/node_modules" ]; then
132
+ echo "Installing sinain-mcp-server dependencies..."
133
+ (cd "$SCRIPT_DIR/../sinain-mcp-server" && npm install)
134
+ fi
135
+
136
+ # Codex: auto-register sinain MCP server if not already configured
137
+ if [ "$AGENT" = "codex" ]; then
138
+ TSX_BIN="$SCRIPT_DIR/../sinain-core/node_modules/.bin/tsx"
139
+ MCP_ENTRY="$SCRIPT_DIR/../sinain-mcp-server/index.ts"
140
+ if ! codex mcp get sinain >/dev/null 2>&1; then
141
+ echo "Registering sinain MCP server with codex..."
142
+ codex mcp add sinain \
143
+ --env "SINAIN_CORE_URL=$CORE_URL" \
144
+ --env "SINAIN_WORKSPACE=$WORKSPACE" \
145
+ -- "$TSX_BIN" "$MCP_ENTRY"
146
+ fi
147
+ fi
148
+
149
+ # Agent mode label
150
+ if agent_has_mcp; then
151
+ AGENT_MODE="MCP"
152
+ else
153
+ AGENT_MODE="pipe"
154
+ fi
155
+
156
+ echo "sinain bare agent started"
157
+ echo " Agent: $AGENT ($AGENT_MODE)"
158
+ echo " Core: $CORE_URL"
159
+ echo " Poll: every ${POLL_INTERVAL}s"
160
+ echo " Heartbeat: every ${HEARTBEAT_INTERVAL}s"
161
+ echo " Press Ctrl+C to stop"
162
+ echo ""
163
+
164
+ LAST_HEARTBEAT=$(date +%s)
165
+ ESCALATION_COUNT=0
166
+
167
+ cleanup() {
168
+ echo ""
169
+ echo "Agent stopped. Escalations handled: $ESCALATION_COUNT"
170
+ exit 0
171
+ }
172
+ trap cleanup INT TERM
173
+
174
+ # --- Prompt templates ---
175
+
176
+ ESC_PROMPT_TEMPLATE='You are the sinain HUD agent. An escalation is pending with ID=%s.
177
+
178
+ Call sinain_get_escalation to see the full context, then call sinain_respond with the ID and your response.
179
+
180
+ Response guidelines: 5-10 sentences, address errors first, reference specific screen/audio context, never NO_REPLY. Max 4000 chars for coding context, 3000 otherwise.'
181
+
182
+ HEARTBEAT_PROMPT='You are the sinain HUD agent. Run the heartbeat cycle:
183
+ 1. Call sinain_heartbeat_tick with a brief session summary
184
+ 2. If the result contains a suggestion, post it to HUD via sinain_post_feed
185
+ 3. Call sinain_get_feedback to review recent scores'
186
+
187
+ # --- Main loop ---
188
+
189
+ while true; do
190
+ # Poll for pending escalation
191
+ ESC=$(curl -sf "$CORE_URL/escalation/pending" 2>/dev/null || echo '{"ok":false}')
192
+ ESC_ID=$(echo "$ESC" | python3 -c "import sys,json; d=json.load(sys.stdin); e=d.get('escalation'); print(e['id'] if e else '')" 2>/dev/null || true)
193
+
194
+ if [ -n "$ESC_ID" ]; then
195
+ ESC_MSG=$(echo "$ESC" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['escalation']['message'])" 2>/dev/null)
196
+ ESC_SCORE=$(echo "$ESC" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['escalation'].get('score','?'))" 2>/dev/null)
197
+ ESC_CODING=$(echo "$ESC" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['escalation'].get('codingContext',False))" 2>/dev/null)
198
+
199
+ echo "[$(date +%H:%M:%S)] Escalation $ESC_ID (score=$ESC_SCORE, coding=$ESC_CODING)"
200
+
201
+ if agent_has_mcp; then
202
+ # MCP path: agent calls sinain tools directly
203
+ PROMPT=$(printf "$ESC_PROMPT_TEMPLATE" "$ESC_ID")
204
+ RESPONSE=$(invoke_agent "$PROMPT" || echo "ERROR: $AGENT invocation failed")
205
+ else
206
+ # Pipe path: bash handles HTTP, agent just generates text
207
+ RESPONSE=$(invoke_pipe "$ESC_MSG" || true)
208
+ if [ -n "$RESPONSE" ]; then
209
+ post_response "$ESC_ID" "$RESPONSE"
210
+ else
211
+ echo "[$(date +%H:%M:%S)] WARNING: $AGENT returned empty response"
212
+ fi
213
+ fi
214
+
215
+ ESCALATION_COUNT=$((ESCALATION_COUNT + 1))
216
+ echo "[$(date +%H:%M:%S)] Responded ($ESCALATION_COUNT total): ${RESPONSE:0:120}..."
217
+ echo ""
218
+ fi
219
+
220
+ # Heartbeat check
221
+ NOW=$(date +%s)
222
+ ELAPSED=$((NOW - LAST_HEARTBEAT))
223
+ if [ "$ELAPSED" -ge "$HEARTBEAT_INTERVAL" ]; then
224
+ echo "[$(date +%H:%M:%S)] Running heartbeat tick..."
225
+
226
+ if agent_has_mcp; then
227
+ # MCP path: agent runs heartbeat tools
228
+ invoke_agent "$HEARTBEAT_PROMPT" || true
229
+ else
230
+ # Pipe path: run curation scripts directly
231
+ SCRIPTS_DIR="$WORKSPACE/sinain-memory"
232
+ MEMORY_DIR="$WORKSPACE/memory"
233
+ if [ -d "$SCRIPTS_DIR" ]; then
234
+ python3 "$SCRIPTS_DIR/signal_analyzer.py" --memory-dir "$MEMORY_DIR" 2>/dev/null || true
235
+ python3 "$SCRIPTS_DIR/playbook_curator.py" --memory-dir "$MEMORY_DIR" 2>/dev/null || true
236
+ echo "[$(date +%H:%M:%S)] Heartbeat: ran signal_analyzer + playbook_curator"
237
+ else
238
+ echo "[$(date +%H:%M:%S)] Heartbeat: skipped (no scripts at $SCRIPTS_DIR)"
239
+ fi
240
+ fi
241
+
242
+ LAST_HEARTBEAT=$NOW
243
+ echo "[$(date +%H:%M:%S)] Heartbeat complete"
244
+ echo ""
245
+ fi
246
+
247
+ sleep "$POLL_INTERVAL"
248
+ done
@@ -0,0 +1,93 @@
1
+ # sinain-core configuration
2
+ # Copy to .env and fill in your values: cp .env.example .env
3
+
4
+ # ── Server ──
5
+ PORT=9500
6
+
7
+ # ── System Audio ──
8
+ # Default: ScreenCaptureKit (zero-setup, macOS 13+). Fallback: ffmpeg + BlackHole.
9
+ AUDIO_CAPTURE_CMD=screencapturekit # screencapturekit | sox | ffmpeg
10
+ AUDIO_DEVICE=BlackHole 2ch # macOS audio device (only used by sox/ffmpeg)
11
+ AUDIO_SAMPLE_RATE=16000
12
+ AUDIO_CHUNK_MS=5000
13
+ AUDIO_VAD_ENABLED=true
14
+ AUDIO_VAD_THRESHOLD=0.003
15
+ AUDIO_AUTO_START=true
16
+ AUDIO_GAIN_DB=20
17
+ # AUDIO_ALT_DEVICE= # alternate device for switch_device command
18
+
19
+ # ── Microphone (opt-in for privacy) ──
20
+ MIC_ENABLED=false # set true to capture user's microphone
21
+ MIC_DEVICE=default # "default" = system mic. For specific device: use exact CoreAudio name
22
+ MIC_CAPTURE_CMD=sox # sox or ffmpeg (mic uses sox by default)
23
+ MIC_SAMPLE_RATE=16000
24
+ MIC_CHUNK_MS=5000
25
+ MIC_VAD_ENABLED=true
26
+ MIC_VAD_THRESHOLD=0.008 # higher threshold (ambient noise)
27
+ MIC_AUTO_START=false
28
+ MIC_GAIN_DB=0
29
+
30
+ # ── Transcription ──
31
+ OPENROUTER_API_KEY= # required (unless TRANSCRIPTION_BACKEND=local)
32
+ TRANSCRIPTION_BACKEND=openrouter # openrouter | local (local = whisper.cpp on-device)
33
+ TRANSCRIPTION_MODEL=google/gemini-2.5-flash
34
+ TRANSCRIPTION_LANGUAGE=en-US
35
+
36
+ # ── Local Transcription (only when TRANSCRIPTION_BACKEND=local) ──
37
+ # Install: brew install whisper-cpp
38
+ # Models: https://huggingface.co/ggerganov/whisper.cpp/tree/main
39
+ # LOCAL_WHISPER_BIN=whisper-cli
40
+ # LOCAL_WHISPER_MODEL=~/models/ggml-large-v3-turbo.bin
41
+ # LOCAL_WHISPER_TIMEOUT_MS=15000
42
+
43
+ # ── Agent ──
44
+ AGENT_ENABLED=true
45
+ AGENT_MODEL=google/gemini-2.5-flash-lite
46
+ # AGENT_FALLBACK_MODELS=google/gemini-2.5-flash,anthropic/claude-3.5-haiku
47
+ AGENT_MAX_TOKENS=300
48
+ AGENT_TEMPERATURE=0.3
49
+ AGENT_PUSH_TO_FEED=true
50
+ AGENT_DEBOUNCE_MS=3000
51
+ AGENT_MAX_INTERVAL_MS=30000
52
+ AGENT_COOLDOWN_MS=10000
53
+ AGENT_MAX_AGE_MS=120000 # context window lookback (2 min)
54
+
55
+ # ── Escalation ──
56
+ ESCALATION_MODE=selective # off | selective | focus | rich
57
+ ESCALATION_COOLDOWN_MS=30000
58
+ # ESCALATION_TRANSPORT=auto # ws | http | auto — use http for bare agent (no gateway)
59
+ # auto = WS when gateway connected, HTTP fallback
60
+ # http = skip gateway entirely, poll via GET /escalation/pending
61
+ # See docs/INSTALL-BARE-AGENT.md for bare agent setup
62
+
63
+ # ── OpenClaw / NemoClaw Gateway ─────────────────────────────────────────────
64
+ # Run ./setup-nemoclaw.sh to fill these in interactively (recommended).
65
+ #
66
+ # NemoClaw (NVIDIA Brev) quick-start:
67
+ # 1. In Brev dashboard: Expose Port(s) → enter 18789 → TCP → note the IP
68
+ # 2. In Code-Server terminal: npx sinain (installs plugin, prints token)
69
+ # 3. On Mac: ./setup-nemoclaw.sh (interactive wizard)
70
+ #
71
+ # URL: ws://YOUR-IP:18789 (use the IP shown after exposing port 18789)
72
+ # Token: printed by `npx sinain` / visible in Brev dashboard → Gateway Token
73
+ OPENCLAW_WS_URL=ws://localhost:18789
74
+ OPENCLAW_WS_TOKEN= # 48-char hex — from gateway config or `npx sinain` output
75
+ OPENCLAW_HTTP_URL=http://localhost:18789/hooks/agent
76
+ OPENCLAW_HTTP_TOKEN= # same token as WS_TOKEN
77
+ OPENCLAW_SESSION_KEY=agent:main:sinain # MUST be agent:main:sinain — see README § Session Key
78
+ # OPENCLAW_PHASE1_TIMEOUT_MS=10000 # Phase 1 (delivery) timeout — circuit trips on failure
79
+ # OPENCLAW_PHASE2_TIMEOUT_MS=120000 # Phase 2 (agent response) timeout — no circuit trip
80
+ # OPENCLAW_QUEUE_TTL_MS=300000 # Outbound queue message TTL (5 min)
81
+ # OPENCLAW_QUEUE_MAX_SIZE=10 # Max queued escalations (oldest dropped on overflow)
82
+ # OPENCLAW_PING_INTERVAL_MS=30000 # WS ping keepalive interval
83
+
84
+ # ── SITUATION.md ──
85
+ SITUATION_MD_PATH=~/.openclaw/workspace/SITUATION.md
86
+ # OPENCLAW_WORKSPACE_DIR=~/.openclaw/workspace
87
+
88
+ # ── Debug ──
89
+ # DEBUG=true # verbose logging (every tick, every chunk)
90
+
91
+ # ── Tracing ──
92
+ TRACE_ENABLED=true
93
+ TRACE_DIR=~/.sinain-core/traces