@schift-io/memory 0.1.0 → 0.1.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.
@@ -18,7 +18,7 @@ ENDJSON
18
18
  fi
19
19
 
20
20
  # Validate key is not empty/expired
21
- api_key=$(python3 -c "import json; print(json.load(open('${AUTH_FILE}'))['api_key'])" 2>/dev/null || echo "")
21
+ api_key=$(node -e "try{const d=JSON.parse(require('fs').readFileSync('${AUTH_FILE}','utf-8'));process.stdout.write(d.api_key||'')}catch{}" 2>/dev/null || echo "")
22
22
  if [ -z "$api_key" ]; then
23
23
  cat <<ENDJSON
24
24
  {
package/mcp-server.js CHANGED
@@ -92,7 +92,9 @@ const TOOLS = [
92
92
 
93
93
  async function handleToolCall(name, args) {
94
94
  switch (name) {
95
- case 'save_url':
95
+ case 'save_url': {
96
+ try { new URL(args.url); } catch { throw new Error(`Invalid URL: ${args.url}`); }
97
+ if (!/^https?:$/.test(new URL(args.url).protocol)) throw new Error('Only http/https URLs are supported');
96
98
  return apiCall('/v1/memory/ingest-url', {
97
99
  url: args.url,
98
100
  domain: args.domain || 'ops',
@@ -100,7 +102,7 @@ async function handleToolCall(name, args) {
100
102
  summary: args.summary,
101
103
  context: args.context,
102
104
  findings: args.findings,
103
- });
105
+ });}
104
106
 
105
107
  case 'save_note':
106
108
  return apiCall('/v1/memory/compact', {
@@ -122,7 +124,9 @@ async function handleToolCall(name, args) {
122
124
  const auth = loadAuth();
123
125
  if (!auth) return { status: 'not_authenticated', message: 'Run: npx @schift-io/memory login' };
124
126
  try {
125
- const resp = await fetch(`${auth.url}/health`);
127
+ const resp = await fetch(`${auth.url}/v1/organizations/me`, {
128
+ headers: { 'Authorization': `Bearer ${auth.key}` },
129
+ });
126
130
  return { status: 'connected', cloud_url: auth.url, healthy: resp.ok };
127
131
  } catch (e) {
128
132
  return { status: 'error', message: e.message };
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@schift-io/memory",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Second brain for Claude Code - saves conversations and web content to Schift Cloud",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
+ "engines": {
8
+ "node": ">=18"
9
+ },
7
10
  "bin": {
8
11
  "schift-memory-mcp": "./mcp-server.js"
9
12
  },
@@ -1,22 +1,30 @@
1
1
  #!/usr/bin/env bash
2
- # Post-WebFetch hook: detects URLs from tool output and offers to save
3
- # This runs async after WebFetch calls - it queues the URL for next prompt
2
+ # Post-WebFetch hook: queues URLs for save prompt
4
3
  set -euo pipefail
5
4
 
6
- SCHIFT_API="${SCHIFT_API_URL:-http://localhost:8787}"
7
- SCHIFT_KEY="${SCHIFT_API_KEY:-local}"
8
5
  QUEUE_FILE="$HOME/.schift/memory/queue/pending-urls.jsonl"
9
6
 
10
7
  # Read tool input from stdin (Claude Code passes hook context)
11
8
  input=$(cat 2>/dev/null || echo "{}")
12
- url=$(echo "$input" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('url',''))" 2>/dev/null || echo "")
13
9
 
14
- if [ -z "$url" ] || [ "$url" = "None" ]; then
10
+ # Use node (guaranteed in Claude Code) instead of python3
11
+ url=$(node -e "
12
+ try {
13
+ const d = JSON.parse(process.argv[1]);
14
+ const u = (d.tool_input || {}).url || '';
15
+ if (u) process.stdout.write(u);
16
+ } catch {}
17
+ " "$input" 2>/dev/null || echo "")
18
+
19
+ if [ -z "$url" ]; then
15
20
  exit 0
16
21
  fi
17
22
 
18
- # Queue the URL for the assistant to ask about
23
+ # Safe JSON serialization via node
19
24
  mkdir -p "$(dirname "$QUEUE_FILE")"
20
- echo "{\"url\": \"${url}\", \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" >> "$QUEUE_FILE"
25
+ node -e "
26
+ const line = JSON.stringify({ url: process.argv[1], timestamp: new Date().toISOString() });
27
+ process.stdout.write(line + '\n');
28
+ " "$url" >> "$QUEUE_FILE"
21
29
 
22
30
  exit 0
package/scripts/init.sh CHANGED
@@ -21,7 +21,7 @@ if [ ! -f "$AUTH_FILE" ]; then
21
21
  exit 1
22
22
  fi
23
23
 
24
- api_key=$(python3 -c "import json; print(json.load(open('${AUTH_FILE}'))['api_key'])" 2>/dev/null || echo "")
24
+ api_key=$(node -e "try{process.stdout.write(JSON.parse(require('fs').readFileSync('${AUTH_FILE}','utf-8')).api_key||'')}catch{}" 2>/dev/null || echo "")
25
25
  if [ -z "$api_key" ]; then
26
26
  echo " Auth file exists but API key is missing."
27
27
  echo " Run: npx @schift-io/memory login"
@@ -30,10 +30,10 @@ fi
30
30
 
31
31
  # --- Step 2: Validate key against Schift Cloud ---
32
32
  echo " Validating Schift account..."
33
- cloud_url=$(python3 -c "import json; print(json.load(open('${AUTH_FILE}')).get('cloud_url','${SCHIFT_CLOUD}'))" 2>/dev/null || echo "${SCHIFT_CLOUD}")
33
+ cloud_url=$(node -e "try{process.stdout.write(JSON.parse(require('fs').readFileSync('${AUTH_FILE}','utf-8')).cloud_url||'${SCHIFT_CLOUD}')}catch{process.stdout.write('${SCHIFT_CLOUD}')}" 2>/dev/null || echo "${SCHIFT_CLOUD}")
34
34
  validate=$(curl -sf -o /dev/null -w "%{http_code}" \
35
35
  -H "Authorization: Bearer ${api_key}" \
36
- "${cloud_url}/v1/me" 2>/dev/null || echo "000")
36
+ "${cloud_url}/v1/organizations/me" 2>/dev/null || echo "000")
37
37
 
38
38
  if [ "$validate" != "200" ]; then
39
39
  echo " API key is invalid or expired."
@@ -49,7 +49,7 @@ mkdir -p "$HOME/.schift/memory"/{config,sources/web,compact/session,compact/topi
49
49
 
50
50
  # --- Step 4: Bootstrap bucket on Schift Cloud ---
51
51
  echo " Creating knowledge bucket on Schift Cloud..."
52
- curl -sf -X POST "${cloud_url}/v1/local-memory/bootstrap" \
52
+ curl -sf -X POST "${cloud_url}/v1/memory/bootstrap" \
53
53
  -H "Content-Type: application/json" \
54
54
  -H "Authorization: Bearer ${api_key}" > /dev/null 2>&1 || true
55
55
 
package/scripts/login.sh CHANGED
@@ -13,11 +13,11 @@ echo ""
13
13
 
14
14
  # Check if already logged in
15
15
  if [ -f "$AUTH_FILE" ]; then
16
- existing_key=$(python3 -c "import json; print(json.load(open('${AUTH_FILE}'))['api_key'])" 2>/dev/null || echo "")
16
+ existing_key=$(node -e "try{process.stdout.write(JSON.parse(require('fs').readFileSync('${AUTH_FILE}','utf-8')).api_key||'')}catch{}" 2>/dev/null || echo "")
17
17
  if [ -n "$existing_key" ]; then
18
18
  validate=$(curl -sf -o /dev/null -w "%{http_code}" \
19
19
  -H "Authorization: Bearer ${existing_key}" \
20
- "${SCHIFT_CLOUD}/v1/me" 2>/dev/null || echo "000")
20
+ "${SCHIFT_CLOUD}/v1/organizations/me" 2>/dev/null || echo "000")
21
21
  if [ "$validate" = "200" ]; then
22
22
  echo " Already logged in. Account is valid."
23
23
  echo " To re-login, delete: ${AUTH_FILE}"
@@ -41,7 +41,7 @@ fi
41
41
  echo " Validating..."
42
42
  validate=$(curl -sf -o /dev/null -w "%{http_code}" \
43
43
  -H "Authorization: Bearer ${api_key}" \
44
- "${SCHIFT_CLOUD}/v1/me" 2>/dev/null || echo "000")
44
+ "${SCHIFT_CLOUD}/v1/organizations/me" 2>/dev/null || echo "000")
45
45
 
46
46
  if [ "$validate" != "200" ]; then
47
47
  echo " Invalid API key. Check your key and try again."