@rubytech/create-realagent 1.0.829 → 1.0.831
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/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/lib/oauth-llm/dist/index.d.ts +9 -2
- package/payload/platform/lib/oauth-llm/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/oauth-llm/dist/index.js +26 -1
- package/payload/platform/lib/oauth-llm/dist/index.js.map +1 -1
- package/payload/platform/lib/oauth-llm/src/index.ts +43 -4
- package/payload/platform/neo4j/migrations/007-conversation-archive-source.ts +116 -0
- package/payload/platform/neo4j/migrations/008-adminuser-accountid-backfill.ts +85 -0
- package/payload/platform/neo4j/schema.cypher +12 -3
- package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +54 -39
- package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +64 -26
- package/payload/platform/plugins/admin/mcp/dist/index.js +25 -3
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +29 -23
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +2 -1
- package/payload/platform/plugins/memory/bin/conversation-archive-ingest.mjs +564 -0
- package/payload/platform/plugins/memory/bin/conversation-archive-ingest.sh +106 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +30 -16
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +11 -6
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +30 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.d.ts +49 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.js +35 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +47 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +31 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js +155 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts +11 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js +20 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts +14 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +38 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts +16 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js +59 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts +9 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js +32 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js +29 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts +45 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js +125 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +34 -9
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +360 -35
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts +3 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js +46 -17
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js +73 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js +109 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +34 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +17 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +34 -13
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +18 -7
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +24 -8
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +2 -2
- package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +133 -0
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +5 -2
- package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
- package/payload/platform/scripts/seed-neo4j.sh +15 -15
- package/payload/platform/templates/specialists/agents/database-operator.md +8 -9
- package/payload/server/chunk-7BO5HDJC.js +10093 -0
- package/payload/server/chunk-BCFM2UPH.js +2305 -0
- package/payload/server/chunk-CV3HPX46.js +10097 -0
- package/payload/server/chunk-EL4DZ56X.js +1116 -0
- package/payload/server/chunk-J6YWEJBN.js +1116 -0
- package/payload/server/chunk-OCPJGZ6S.js +654 -0
- package/payload/server/chunk-QOJ2D26Z.js +654 -0
- package/payload/server/chunk-RC46ZYGT.js +2305 -0
- package/payload/server/client-pool-7NTEFNVQ.js +32 -0
- package/payload/server/client-pool-ZNGN66GN.js +32 -0
- package/payload/server/cloudflare-task-tracker-MHALDN54.js +19 -0
- package/payload/server/cloudflare-task-tracker-WE77WXSI.js +19 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/neo4j-migrations-4XPNJNM6.js +490 -0
- package/payload/server/neo4j-migrations-6RW423E2.js +530 -0
- package/payload/server/server.js +30 -19
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Regression test for archive-ingest-surface-gate.sh (Task 855
|
|
2
|
+
# Regression test for archive-ingest-surface-gate.sh (Task 855).
|
|
3
3
|
#
|
|
4
|
-
# Covers
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# - memory-archive-write archiveType='whatsapp-export' block (the enum value
|
|
22
|
-
# was dropped from memory-archive-write).
|
|
23
|
-
#
|
|
24
|
-
# A generic LinkedIn-shaped fixture stands in for the parse-error lifecycle —
|
|
25
|
-
# the gate's PostToolUse pattern matches `mcp__*__*-export-parse` /
|
|
26
|
-
# `mcp__*__*-import-parse`, so any plausible parser tool name exercises the
|
|
27
|
-
# flag-set / flag-clear path.
|
|
4
|
+
# Covers:
|
|
5
|
+
# Preserved-from-Task-846:
|
|
6
|
+
# 1. Edit on /platform/plugins/<x>/lib/* → BLOCKED
|
|
7
|
+
# 2. Edit on benign path → ALLOWED
|
|
8
|
+
# 3. Bash with `npx vitest`/`bun test`/`npm test` → BLOCKED
|
|
9
|
+
# 4. PostToolUse on whatsapp-export-parse with isError:true sets flag
|
|
10
|
+
# 5. Subsequent PreToolUse on ANY tool → BLOCKED
|
|
11
|
+
# 6. UserPromptSubmit clears flag → normal allow resumes
|
|
12
|
+
# 7. PostToolUse with isError:false → flag absent
|
|
13
|
+
# 8. Stale flag (>600s) auto-clears
|
|
14
|
+
# New (Task 855):
|
|
15
|
+
# A. PreToolUse mcp__memory__whatsapp-export-parse → BLOCKED
|
|
16
|
+
# B. PreToolUse mcp__memory__whatsapp-export-insight-write → BLOCKED
|
|
17
|
+
# C. PreToolUse mcp__memory__memory-archive-write w/ archiveType=whatsapp-export → BLOCKED
|
|
18
|
+
# D. PreToolUse mcp__memory__memory-archive-write w/ archiveType=linkedin-connections → ALLOWED
|
|
19
|
+
# E. PreToolUse Bash invoking conversation-archive-ingest.sh → ALLOWED
|
|
20
|
+
# F. Default-allow emits a [archive-ingest-gate] decision=allow log line
|
|
28
21
|
|
|
29
22
|
set -u
|
|
30
23
|
|
|
@@ -58,20 +51,18 @@ run_case() {
|
|
|
58
51
|
fi
|
|
59
52
|
}
|
|
60
53
|
|
|
61
|
-
#
|
|
54
|
+
# Preserved cases ---------------------------------------------------------
|
|
62
55
|
|
|
63
|
-
run_case "Edit on platform/plugins/
|
|
64
|
-
'{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/Users/x/repo/platform/plugins/
|
|
56
|
+
run_case "Edit on platform/plugins/memory/mcp/src/lib/conversation-normalisers/whatsapp-text.ts → BLOCKED" \
|
|
57
|
+
'{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/Users/x/repo/platform/plugins/memory/mcp/src/lib/conversation-normalisers/whatsapp-text.ts","old_string":"a","new_string":"b"}}' \
|
|
65
58
|
2
|
|
66
59
|
|
|
67
60
|
run_case "Edit on README.md → ALLOWED" \
|
|
68
61
|
'{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/Users/x/repo/README.md","old_string":"a","new_string":"b"}}' \
|
|
69
62
|
0
|
|
70
63
|
|
|
71
|
-
# Test-runner block (Bash) ------------------------------------------------
|
|
72
|
-
|
|
73
64
|
run_case "Bash 'npx vitest run' → BLOCKED" \
|
|
74
|
-
'{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npx vitest run
|
|
65
|
+
'{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npx vitest run parse-export.test.ts"}}' \
|
|
75
66
|
2
|
|
76
67
|
|
|
77
68
|
run_case "Bash 'ls -la' → ALLOWED" \
|
|
@@ -86,18 +77,45 @@ run_case "Bash 'npm test' → BLOCKED" \
|
|
|
86
77
|
'{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npm test"}}' \
|
|
87
78
|
2
|
|
88
79
|
|
|
89
|
-
#
|
|
80
|
+
# New (Task 855) cases ----------------------------------------------------
|
|
81
|
+
|
|
82
|
+
run_case "PreToolUse mcp__memory__whatsapp-export-parse → BLOCKED" \
|
|
83
|
+
'{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__whatsapp-export-parse","tool_input":{"filePath":"/tmp/_chat.txt","accountId":"acct1","timezone":"Europe/London"}}' \
|
|
84
|
+
2
|
|
85
|
+
|
|
86
|
+
run_case "PreToolUse mcp__memory__whatsapp-export-insight-write → BLOCKED" \
|
|
87
|
+
'{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__whatsapp-export-insight-write","tool_input":{"kind":"MENTIONS","name":"Joel"}}' \
|
|
88
|
+
2
|
|
89
|
+
|
|
90
|
+
run_case "PreToolUse memory-archive-write w/ archiveType=whatsapp-export → BLOCKED" \
|
|
91
|
+
'{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"archiveType":"whatsapp-export","ownerNodeId":"x","accountId":"a","rows":[]}}' \
|
|
92
|
+
2
|
|
90
93
|
|
|
91
94
|
run_case "PreToolUse memory-archive-write w/ archiveType=linkedin-connections → ALLOWED" \
|
|
92
95
|
'{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"archiveType":"linkedin-connections","ownerNodeId":"x","accountId":"a","rows":[]}}' \
|
|
93
96
|
0
|
|
94
97
|
|
|
98
|
+
# Bypass attempts (Task 855 code-review C1): nested archiveType in rows[0]
|
|
99
|
+
# or conversation must NOT defeat the block. The gate must read the
|
|
100
|
+
# top-level tool_input.archiveType, not the first textual occurrence.
|
|
101
|
+
run_case "BYPASS: nested rows[0].archiveType=linkedin + top-level archiveType=whatsapp-export → BLOCKED" \
|
|
102
|
+
'{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"rows":[{"archiveType":"linkedin-connections"}],"archiveType":"whatsapp-export","ownerNodeId":"x","accountId":"a"}}' \
|
|
103
|
+
2
|
|
104
|
+
|
|
105
|
+
run_case "BYPASS: conversation.archiveType=linkedin + top-level archiveType=whatsapp-export → BLOCKED" \
|
|
106
|
+
'{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"conversation":{"archiveType":"linkedin-connections","conversationId":"x"},"archiveType":"whatsapp-export","ownerNodeId":"x","accountId":"a","rows":[]}}' \
|
|
107
|
+
2
|
|
108
|
+
|
|
95
109
|
# Plugin-source-edit path block must read tool_input.file_path top-level,
|
|
96
110
|
# not a nested file_path in old_string/new_string.
|
|
97
111
|
run_case "BYPASS: nested file_path in old_string + top-level file_path in lib/* → BLOCKED" \
|
|
98
|
-
'{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/repo/platform/plugins/
|
|
112
|
+
'{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/repo/platform/plugins/memory/mcp/src/lib/conversation-normalisers/whatsapp-text.ts","old_string":"file_path:/safe/path","new_string":"x"}}' \
|
|
99
113
|
2
|
|
100
114
|
|
|
115
|
+
run_case "PreToolUse Bash invoking conversation-archive-ingest.sh → ALLOWED" \
|
|
116
|
+
'{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"bash platform/plugins/memory/bin/conversation-archive-ingest.sh /tmp/chat.zip --source whatsapp --owner-element-id 4:abc:1 --participant-person-ids 4:abc:2 --scope admin"}}' \
|
|
117
|
+
0
|
|
118
|
+
|
|
101
119
|
# Default-allow log-line check
|
|
102
120
|
LOG=$(printf '%s' '{"hook_event_name":"PreToolUse","tool_name":"Read","tool_input":{"file_path":"/tmp/foo"}}' | bash "$HOOK" 2>&1 1>/dev/null)
|
|
103
121
|
if printf '%s' "$LOG" | grep -q '\[archive-ingest-gate\] decision=allow tool=Read reason=default'; then
|
|
@@ -118,13 +136,10 @@ else
|
|
|
118
136
|
FAIL=$((FAIL + 1))
|
|
119
137
|
fi
|
|
120
138
|
|
|
121
|
-
# Parse-error flag lifecycle (preserved)
|
|
122
|
-
# `mcp__*__*-export-parse` / `mcp__*__*-import-parse` — exercise via the
|
|
123
|
-
# linkedin-import-parse name (synthetic — the linkedin importer currently
|
|
124
|
-
# uses memory-archive-write, but the gate matches by tool name shape).
|
|
139
|
+
# Parse-error flag lifecycle (preserved)
|
|
125
140
|
rm -f "$FLAG_FILE"
|
|
126
141
|
run_case "PostToolUse parse-error sets flag (exit 0)" \
|
|
127
|
-
'{"hook_event_name":"PostToolUse","tool_name":"
|
|
142
|
+
'{"hook_event_name":"PostToolUse","tool_name":"mcp__memory__whatsapp-export-parse","tool_input":{"filePath":"_chat.txt"},"tool_response":{"isError":true,"content":[{"type":"text","text":"parse-error file=_chat.txt line=1 reason=not-a-_chat.txt"}]}}' \
|
|
128
143
|
0
|
|
129
144
|
[[ -f "$FLAG_FILE" ]] && { echo "PASS: parse-error flag created"; PASS=$((PASS+1)); } \
|
|
130
145
|
|| { echo "FAIL: parse-error flag NOT created" >&2; FAIL=$((FAIL+1)); }
|
|
@@ -153,7 +168,7 @@ run_case "Stale flag auto-clears, PreToolUse Read → ALLOWED" \
|
|
|
153
168
|
# PostToolUse parse-success leaves flag absent
|
|
154
169
|
rm -f "$FLAG_FILE"
|
|
155
170
|
run_case "PostToolUse parse-success (isError:false) does NOT set flag" \
|
|
156
|
-
'{"hook_event_name":"PostToolUse","tool_name":"
|
|
171
|
+
'{"hook_event_name":"PostToolUse","tool_name":"mcp__memory__whatsapp-export-parse","tool_input":{"filePath":"_chat.txt"},"tool_response":{"isError":false,"content":[{"type":"text","text":"{\"parsedLines\":[]}"}]}}' \
|
|
157
172
|
0
|
|
158
173
|
[[ ! -f "$FLAG_FILE" ]] && { echo "PASS: parse-success leaves flag absent"; PASS=$((PASS+1)); } \
|
|
159
174
|
|| { echo "FAIL: parse-success incorrectly created flag" >&2; FAIL=$((FAIL+1)); }
|
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Archive-ingest surface gate (Task 855, updated by Task 891
|
|
2
|
+
# Archive-ingest surface gate (Task 855, updated by Task 891).
|
|
3
3
|
#
|
|
4
|
-
#
|
|
5
|
-
# Task 855
|
|
6
|
-
# archive ingestion
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# future flat-dataset archive types that ship per-source parsers.
|
|
4
|
+
# Five enforcements, one script — phase decided by `hook_event_name` on stdin.
|
|
5
|
+
# Task 855 narrows the database-operator subagent's effective surface during
|
|
6
|
+
# WhatsApp archive ingestion to exactly one Bash entry
|
|
7
|
+
# (`memory/bin/conversation-archive-ingest.sh`) plus read-only neighbours, by
|
|
8
|
+
# blocking the legacy MCP deviation tools mechanically. Task 891 retired the
|
|
9
|
+
# `whatsapp-export-insight-pass` tool entirely (Phase 2 enrichment moved to a
|
|
10
|
+
# separate follow-up task that will operate on :Section:Conversation chunks);
|
|
11
|
+
# the tool name is added to the BLOCK list so any agent that still references
|
|
12
|
+
# it from a stale skill or runbook gets a loud denial instead of MCP-not-found.
|
|
14
13
|
#
|
|
15
|
-
# 1.
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
14
|
+
# 1. PreToolUse on the four legacy WhatsApp MCP tools — BLOCK unconditionally.
|
|
15
|
+
# The single deterministic Bash entry is the only supported path for
|
|
16
|
+
# `archiveType=whatsapp-export`. Tool source for #1-#3 remains until cleanup;
|
|
17
|
+
# `whatsapp-export-insight-pass` source was deleted by Task 891 and the
|
|
18
|
+
# block here catches stale references.
|
|
19
|
+
# mcp__memory__whatsapp-export-parse
|
|
20
|
+
# mcp__memory__whatsapp-export-insight-write
|
|
21
|
+
# mcp__memory__whatsapp-export-insight-pass (Task 891 — deleted, retired)
|
|
22
|
+
# mcp__memory__memory-archive-write (only when `archiveType` is
|
|
23
|
+
# `whatsapp-export`; LinkedIn
|
|
24
|
+
# and other archiveTypes pass
|
|
25
|
+
# through unchanged.)
|
|
22
26
|
#
|
|
23
27
|
# 2. PreToolUse Edit/Write/NotebookEdit: deny writes under
|
|
24
28
|
# `*platform/plugins/*/lib/*` (parser/CSV-shape source for any *-import or
|
|
@@ -28,10 +32,18 @@
|
|
|
28
32
|
# 3. PreToolUse Bash: deny commands invoking JavaScript test runners
|
|
29
33
|
# (vitest|bun test|npm test|npx jest|node .*vitest). Preserved from Task 846.
|
|
30
34
|
#
|
|
31
|
-
# 4.
|
|
35
|
+
# 4. Parse-error gate: PostToolUse on any `mcp__*__*-export-parse` /
|
|
36
|
+
# `mcp__*__*-import-parse` tool whose `tool_response.isError == true`
|
|
37
|
+
# writes a flag file. Subsequent PreToolUse on ANY tool blocks until
|
|
38
|
+
# UserPromptSubmit clears the flag. A 600s TTL is the cross-session safety
|
|
39
|
+
# net. Preserved from Task 846 because LinkedIn and future per-source archive
|
|
40
|
+
# parsers still use the legacy MCP path until they migrate to their own
|
|
41
|
+
# deterministic Bash entries.
|
|
42
|
+
#
|
|
43
|
+
# 5. Logging: every PreToolUse decision emits one line in the format
|
|
32
44
|
# [archive-ingest-gate] decision=<allow|block> tool=<name> reason=<r> ...
|
|
33
45
|
# so the operator can grep the full decision trail for one ingest from
|
|
34
|
-
# server.log.
|
|
46
|
+
# server.log alongside the [whatsapp-ingest] script lines.
|
|
35
47
|
#
|
|
36
48
|
# Exit codes follow Claude Code hook protocol: 0 = allow, 2 = block (stderr
|
|
37
49
|
# message shown to the agent). Fail-closed on terminal stdin to match
|
|
@@ -128,12 +140,25 @@ if [ -f "$FLAG_FILE" ]; then
|
|
|
128
140
|
fi
|
|
129
141
|
fi
|
|
130
142
|
|
|
143
|
+
# --- Block 2: legacy WhatsApp MCP tools — defensive denial ----------------
|
|
144
|
+
# These tool sources were deleted by Task 894; the block stays as a stale-
|
|
145
|
+
# reference catch (skill markdown checked into older installs may still name
|
|
146
|
+
# them). The harness will return tool-not-found anyway, but a named block
|
|
147
|
+
# message guides the operator to the new entry.
|
|
148
|
+
case "$TOOL_NAME" in
|
|
149
|
+
mcp__memory__whatsapp-export-parse|mcp__memory__whatsapp-export-insight-write|mcp__memory__whatsapp-export-insight-pass|mcp__memory__whatsapp-export-preview)
|
|
150
|
+
emit_decision "block" "denied-mcp-legacy" \
|
|
151
|
+
"Blocked: ${TOOL_NAME} is a retired path. Task 894 generalised conversation-archive ingest — invoke 'bash platform/plugins/memory/bin/conversation-archive-ingest.sh <archive> --source whatsapp --owner-element-id <id> --participant-person-ids <csv> --scope <admin|public>' once. Normalise, sessionize, classify (mode=chat), and memory-ingest (parentLabel=ConversationArchive, source=<enum>) all run in-process."
|
|
152
|
+
;;
|
|
153
|
+
esac
|
|
154
|
+
|
|
131
155
|
# Helper: extract a top-level field from `tool_input` via python3 — never via
|
|
132
156
|
# grep+sed against the raw JSON, which would pick the first textual occurrence
|
|
133
|
-
# including nested-object matches (`rows[0].archiveType`,
|
|
134
|
-
#
|
|
135
|
-
# JSON-aware hook parsing
|
|
136
|
-
#
|
|
157
|
+
# including nested-object matches (`rows[0].archiveType`,
|
|
158
|
+
# `conversation.archiveType`, etc.) and let a malicious payload bypass the
|
|
159
|
+
# block. python3 is the project standard for JSON-aware hook parsing
|
|
160
|
+
# (mirrors lane-gate.sh:31-46). On parse failure return empty string —
|
|
161
|
+
# downstream block conditions skip cleanly.
|
|
137
162
|
extract_tool_input_field() {
|
|
138
163
|
local field="$1"
|
|
139
164
|
printf '%s' "$INPUT" | python3 -c "
|
|
@@ -146,7 +171,20 @@ except Exception:
|
|
|
146
171
|
" 2>/dev/null || echo ""
|
|
147
172
|
}
|
|
148
173
|
|
|
149
|
-
# --- Block
|
|
174
|
+
# --- Block 3: memory-archive-write conditional on conversation-shaped types
|
|
175
|
+
# LinkedIn-connections and future flat-dataset archiveTypes flow unchanged.
|
|
176
|
+
# `whatsapp-export` was the only conversation-shaped archiveType; Task 894
|
|
177
|
+
# deleted that handler entirely, so the type itself is now invalid input —
|
|
178
|
+
# the block stays defensive against operator-edited skills that still name it.
|
|
179
|
+
if [ "$TOOL_NAME" = "mcp__memory__memory-archive-write" ]; then
|
|
180
|
+
ARCHIVE_TYPE=$(extract_tool_input_field archiveType)
|
|
181
|
+
if [ "$ARCHIVE_TYPE" = "whatsapp-export" ]; then
|
|
182
|
+
emit_decision "block" "denied-mcp-legacy archiveType=whatsapp-export" \
|
|
183
|
+
"Blocked: memory-archive-write with archiveType='whatsapp-export' is a retired path. Task 894 routes conversation transcripts through 'bash platform/plugins/memory/bin/conversation-archive-ingest.sh <archive> --source whatsapp --owner-element-id <id> --participant-person-ids <csv> --scope <admin|public>'. Flat-dataset archiveTypes (linkedin-connections, …) flow through memory-archive-write unchanged."
|
|
184
|
+
fi
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# --- Block 4: plugin-source path block (Edit/Write/NotebookEdit) -----------
|
|
150
188
|
case "$TOOL_NAME" in
|
|
151
189
|
Edit|Write|NotebookEdit)
|
|
152
190
|
FILE_PATH=$(extract_tool_input_field file_path)
|
|
@@ -159,7 +197,7 @@ case "$TOOL_NAME" in
|
|
|
159
197
|
;;
|
|
160
198
|
esac
|
|
161
199
|
|
|
162
|
-
# --- Block
|
|
200
|
+
# --- Block 5: shell test-runner block (Bash) -------------------------------
|
|
163
201
|
COMMAND=""
|
|
164
202
|
if [ "$TOOL_NAME" = "Bash" ]; then
|
|
165
203
|
COMMAND=$(extract_tool_input_field command)
|
|
@@ -737,9 +737,19 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
|
|
|
737
737
|
const firstSpace = trimmedName.search(/\s/);
|
|
738
738
|
const givenName = firstSpace === -1 ? trimmedName : trimmedName.slice(0, firstSpace).trim();
|
|
739
739
|
const familyName = firstSpace === -1 ? null : (trimmedName.slice(firstSpace + 1).trim() || null);
|
|
740
|
+
// Task 897: stamp `accountId` on every AdminUser at MERGE time, both
|
|
741
|
+
// ON CREATE and ON MATCH (the latter via COALESCE so a pre-existing
|
|
742
|
+
// value isn't overwritten if it differs — which would itself be a
|
|
743
|
+
// graph-invariant violation worth surfacing). Pre-897 the missing
|
|
744
|
+
// accountId fingerprint produced :AdminUser nodes that migration 004
|
|
745
|
+
// pruned silently, costing the admin pin during onboarding.
|
|
740
746
|
const result = await session.run(`MERGE (au:AdminUser {userId: $userId})
|
|
741
|
-
ON CREATE SET au.
|
|
742
|
-
|
|
747
|
+
ON CREATE SET au.accountId = $accountId,
|
|
748
|
+
au.name = $name,
|
|
749
|
+
au.createdAt = $createdAt
|
|
750
|
+
ON MATCH SET au.accountId = COALESCE(au.accountId, $accountId),
|
|
751
|
+
au.name = $name,
|
|
752
|
+
au.updatedAt = $createdAt
|
|
743
753
|
WITH au
|
|
744
754
|
MATCH (b:LocalBusiness {accountId: $accountId})
|
|
745
755
|
MERGE (au)-[r:ADMIN_OF]->(b)
|
|
@@ -772,11 +782,23 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
|
|
|
772
782
|
if (result.records.length > 0) {
|
|
773
783
|
personReused = result.records[0].get("reused");
|
|
774
784
|
}
|
|
785
|
+
// Task 897 — post-write assertion mirroring Task 785 in neo4j-store.ts.
|
|
786
|
+
// MATCH back the AdminUser we just wrote and verify every required
|
|
787
|
+
// field landed. Loud-fail the tool call if accountId or name is null
|
|
788
|
+
// so a Cypher regression that drops the field is grep-detectable.
|
|
789
|
+
const verify = await session.run(`MATCH (au:AdminUser {userId: $userId})
|
|
790
|
+
RETURN coalesce(au.accountId, '') AS accountId,
|
|
791
|
+
coalesce(au.name, '') AS name`, { userId });
|
|
792
|
+
const verifiedAccountId = verify.records[0]?.get("accountId") || "";
|
|
793
|
+
const verifiedName = verify.records[0]?.get("name") || "";
|
|
794
|
+
if (!verifiedAccountId || !verifiedName) {
|
|
795
|
+
throw new Error(`post-write assertion failed: AdminUser userId=${userIdShort} accountId=${verifiedAccountId || "(null)"} name=${verifiedName || "(null)"} — required fields missing after MERGE`);
|
|
796
|
+
}
|
|
775
797
|
}
|
|
776
798
|
finally {
|
|
777
799
|
await session.close();
|
|
778
800
|
}
|
|
779
|
-
console.error(`[admin
|
|
801
|
+
console.error(`[admin] admin-add success userId=${userIdShort} accountId=${ACCOUNT_ID} name=${name.trim()} required-fields=ok personReused=${personReused}`);
|
|
780
802
|
}
|
|
781
803
|
catch (err) {
|
|
782
804
|
const errMsg = err instanceof Error ? err.message : String(err);
|