@rubytech/create-maxy-code 0.1.44 → 0.1.47

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 (155) hide show
  1. package/dist/index.js +8 -16
  2. package/package.json +1 -1
  3. package/payload/platform/lib/admins-write/dist/index.d.ts +0 -1
  4. package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
  5. package/payload/platform/lib/admins-write/dist/index.js +2 -5
  6. package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
  7. package/payload/platform/lib/admins-write/src/index.ts +2 -8
  8. package/payload/platform/lib/graph-mcp/dist/index.js +1 -4
  9. package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
  10. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +7 -6
  11. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -1
  12. package/payload/platform/lib/graph-mcp/dist/schema-cache.js +7 -6
  13. package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -1
  14. package/payload/platform/lib/graph-mcp/src/index.ts +1 -4
  15. package/payload/platform/lib/graph-mcp/src/schema-cache.ts +7 -6
  16. package/payload/platform/lib/graph-search/dist/index.d.ts +5 -5
  17. package/payload/platform/lib/graph-search/dist/index.js +4 -4
  18. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +6 -7
  19. package/payload/platform/lib/graph-search/src/index.ts +5 -5
  20. package/payload/platform/lib/graph-trash/dist/index.d.ts +8 -12
  21. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
  22. package/payload/platform/lib/graph-trash/dist/index.js +8 -12
  23. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  24. package/payload/platform/lib/graph-trash/src/index.ts +8 -12
  25. package/payload/platform/lib/graph-write/dist/index.d.ts +8 -9
  26. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  27. package/payload/platform/lib/graph-write/dist/index.js +9 -10
  28. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  29. package/payload/platform/lib/graph-write/src/index.ts +9 -10
  30. package/payload/platform/lib/mcp-eager/dist/index.d.ts +4 -4
  31. package/payload/platform/lib/mcp-eager/dist/index.js +4 -4
  32. package/payload/platform/lib/mcp-eager/src/index.ts +4 -4
  33. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  34. package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +138 -18
  35. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +31 -67
  36. package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +2 -2
  37. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +7 -9
  38. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +10 -12
  39. package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +3 -3
  40. package/payload/platform/plugins/docs/references/deployment.md +0 -14
  41. package/payload/platform/plugins/docs/references/platform.md +6 -4
  42. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  43. package/payload/platform/plugins/docs/references/troubleshooting.md +5 -5
  44. package/payload/platform/plugins/loop/PLUGIN.md +67 -12
  45. package/payload/platform/plugins/loop/mcp/dist/index.js +42 -16
  46. package/payload/platform/plugins/loop/mcp/dist/index.js.map +1 -1
  47. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
  48. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
  49. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
  50. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
  51. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
  52. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
  53. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
  54. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
  55. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
  56. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
  57. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
  58. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
  59. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
  60. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
  61. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
  62. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
  63. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
  64. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
  65. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
  66. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
  67. package/payload/platform/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
  68. package/payload/platform/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
  69. package/payload/platform/plugins/loop/mcp/src/index.ts +68 -17
  70. package/payload/platform/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
  71. package/payload/platform/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
  72. package/payload/platform/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
  73. package/payload/platform/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
  74. package/payload/platform/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
  75. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
  76. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
  77. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
  78. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +7 -12
  79. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
  80. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +2 -2
  81. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +4 -4
  82. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -1
  83. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.d.ts.map +1 -1
  84. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js +8 -9
  85. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
  86. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +2 -2
  87. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +2 -2
  88. package/payload/platform/scripts/admin-persist-audit.ts +4 -10
  89. package/payload/platform/scripts/conversation-id-allowlist.txt +0 -1
  90. package/payload/platform/scripts/lib/resolve-account-dir.sh +0 -2
  91. package/payload/platform/scripts/resume-tunnel.sh +2 -9
  92. package/payload/platform/scripts/seed-neo4j.sh +26 -104
  93. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  94. package/payload/platform/services/claude-session-manager/dist/http-server.js +67 -5
  95. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  96. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -0
  98. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  99. package/payload/platform/templates/agents/admin/IDENTITY.md +12 -12
  100. package/payload/platform/templates/agents/admin/SOUL.md +23 -1
  101. package/payload/premium-plugins/real-agent/agents/buyer-enquiry/SOUL.md +10 -0
  102. package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
  103. package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
  104. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  105. package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +67 -12
  106. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js +42 -16
  107. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js.map +1 -1
  108. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
  109. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
  110. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
  111. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
  112. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
  113. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
  114. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
  115. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
  116. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
  117. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
  118. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
  119. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
  120. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
  121. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
  122. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
  123. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
  124. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
  125. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
  126. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
  127. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
  128. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
  129. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
  130. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/index.ts +68 -17
  131. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
  132. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
  133. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
  134. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
  135. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
  136. package/payload/server/public/assets/admin-SyUHjvNs.js +216 -0
  137. package/payload/server/public/assets/{data-CU9uH2JJ.js → data-DwQ7ZEyy.js} +1 -1
  138. package/payload/server/public/assets/{graph-BI7yVwmT.js → graph-CwZkD6GX.js} +1 -1
  139. package/payload/server/public/assets/graph-labels-CVkmOHhw.js +1 -0
  140. package/payload/server/public/assets/page-CQ7ELqGs.js +1 -0
  141. package/payload/server/public/assets/page-SOCqJGlV.js +50 -0
  142. package/payload/server/public/data.html +3 -3
  143. package/payload/server/public/graph.html +3 -3
  144. package/payload/server/public/index.html +4 -4
  145. package/payload/server/server.js +9 -46
  146. package/payload/platform/plugins/docs/references/migration-guide.md +0 -90
  147. package/payload/platform/plugins/loop/mcp/src/tools/property-request.ts +0 -42
  148. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +0 -214
  149. package/payload/platform/scripts/migrate-import.sh +0 -437
  150. package/payload/platform/scripts/taskmaster-export.sh +0 -388
  151. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-request.ts +0 -42
  152. package/payload/server/public/assets/admin-GOZURixP.js +0 -216
  153. package/payload/server/public/assets/graph-labels-bI0uSt_-.js +0 -1
  154. package/payload/server/public/assets/page-BaRMnC96.js +0 -1
  155. package/payload/server/public/assets/page-DKdUMAhI.js +0 -50
@@ -1,388 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ============================================================
3
- # taskmaster-export.sh — Export Taskmaster data to migration bundle
4
- #
5
- # Reads a Taskmaster installation and produces a standardised
6
- # migration bundle directory that migrate-import.sh can consume.
7
- #
8
- # Usage:
9
- # bash taskmaster-export.sh <config-dir> <workspace-dir> <output-dir>
10
- #
11
- # Arguments:
12
- # config-dir — Taskmaster config directory (e.g., ~/.taskmaster)
13
- # workspace-dir — Taskmaster workspace directory (e.g., ~/taskmaster)
14
- # output-dir — Output directory for the migration bundle
15
- #
16
- # Example (run on the Taskmaster Pi via SSH):
17
- # ssh admin@muvin.local
18
- # bash /path/to/taskmaster-export.sh ~/.taskmaster ~/taskmaster ~/bundle
19
- # ============================================================
20
-
21
- set -euo pipefail
22
-
23
- # ------------------------------------------------------------------
24
- # Arguments
25
- # ------------------------------------------------------------------
26
- if [ $# -lt 3 ]; then
27
- echo "[export] ERROR: Usage: taskmaster-export.sh <config-dir> <workspace-dir> <output-dir>"
28
- exit 2
29
- fi
30
-
31
- CONFIG_DIR="$1"
32
- WORKSPACE_DIR="$2"
33
- OUTPUT_DIR="$3"
34
-
35
- TASKMASTER_JSON="$CONFIG_DIR/taskmaster.json"
36
-
37
- if [ ! -f "$TASKMASTER_JSON" ]; then
38
- echo "[export] ERROR: taskmaster.json not found at $TASKMASTER_JSON"
39
- echo "[export] ERROR: Is $CONFIG_DIR a Taskmaster config directory?"
40
- exit 1
41
- fi
42
-
43
- if [ ! -d "$WORKSPACE_DIR" ]; then
44
- echo "[export] ERROR: Workspace directory not found at $WORKSPACE_DIR"
45
- exit 1
46
- fi
47
-
48
- echo "[export] Source config: $CONFIG_DIR"
49
- echo "[export] Source workspace: $WORKSPACE_DIR"
50
- echo "[export] Output bundle: $OUTPUT_DIR"
51
-
52
- # ------------------------------------------------------------------
53
- # Create bundle directory structure
54
- # ------------------------------------------------------------------
55
- mkdir -p "$OUTPUT_DIR"/{identity,contacts,memory/shared,memory/admin,conversations/admin,conversations/users,conversations/groups,media/admin,media/public,automations}
56
-
57
- # ------------------------------------------------------------------
58
- # 1. Manifest
59
- # ------------------------------------------------------------------
60
- HOSTNAME_VAL=$(hostname 2>/dev/null || echo "unknown")
61
- VERSION=$(python3 -c "import json; print(json.load(open('$TASKMASTER_JSON'))['meta']['lastTouchedVersion'])" 2>/dev/null || echo "unknown")
62
- EXPORT_TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
63
-
64
- # Extract customer name from USER.md if it exists
65
- USER_MD="$WORKSPACE_DIR/agents/admin/USER.md"
66
- CUSTOMER_NAME="unknown"
67
- if [ -f "$USER_MD" ]; then
68
- # Parse "**Name:** Adam Mackay" from USER.md
69
- CUSTOMER_NAME=$(grep -oP '\*\*Name:\*\*\s*\K.*' "$USER_MD" 2>/dev/null || \
70
- sed -n 's/.*\*\*Name:\*\* *//p' "$USER_MD" | head -1)
71
- [ -z "$CUSTOMER_NAME" ] && CUSTOMER_NAME="unknown"
72
- fi
73
-
74
- cat > "$OUTPUT_DIR/manifest.json" << MANIFEST_EOF
75
- {
76
- "source": "taskmaster",
77
- "version": "$VERSION",
78
- "hostname": "$HOSTNAME_VAL",
79
- "customer": "$CUSTOMER_NAME",
80
- "exportedAt": "$EXPORT_TS"
81
- }
82
- MANIFEST_EOF
83
- echo "[export] manifest.json written (version=$VERSION, customer=$CUSTOMER_NAME)"
84
-
85
- # ------------------------------------------------------------------
86
- # 2. Identity — owner, agents, PINs
87
- # ------------------------------------------------------------------
88
-
89
- # Owner identity from USER.md
90
- if [ -f "$USER_MD" ]; then
91
- # Parse structured fields from USER.md markdown
92
- OWNER_NAME="$CUSTOMER_NAME"
93
- OWNER_PHONE=$(sed -n 's/.*\*\*Phone:\*\* *//p' "$USER_MD" | head -1)
94
- OWNER_BUSINESS=$(sed -n 's/.*\*\*Business:\*\* *//p' "$USER_MD" | head -1)
95
- OWNER_LOCATION=$(sed -n 's/.*\*\*Location:\*\* *//p' "$USER_MD" | head -1)
96
- OWNER_HOURS=$(sed -n 's/.*\*\*Working hours:\*\* *//p' "$USER_MD" | head -1)
97
-
98
- python3 - "$OWNER_NAME" "$OWNER_PHONE" "$OWNER_BUSINESS" "$OWNER_LOCATION" "$OWNER_HOURS" "$OUTPUT_DIR" <<'PYEOF'
99
- import json, sys
100
- name, phone, business, location, hours, out = sys.argv[1:7]
101
- d = {}
102
- for k, v in [('name',name),('phone',phone),('business',business),('location',location),('hours',hours)]:
103
- if v: d[k] = v
104
- json.dump(d, open(f'{out}/identity/owner.json','w'), indent=2)
105
- print(f'[export] identity/owner.json written ({d.get("name","unknown")})')
106
- PYEOF
107
- else
108
- echo "[export] WARN: USER.md not found at $USER_MD — owner identity skipped"
109
- fi
110
-
111
- # Agent names from IDENTITY.md files
112
- ADMIN_IDENTITY="$WORKSPACE_DIR/agents/admin/IDENTITY.md"
113
- PUBLIC_IDENTITY="$WORKSPACE_DIR/agents/public/IDENTITY.md"
114
- ADMIN_NAME=$(sed -n 's/.*\*\*Name:\*\* *//p' "$ADMIN_IDENTITY" 2>/dev/null | head -1 || echo "")
115
- PUBLIC_NAME=$(sed -n 's/.*\*\*Name:\*\* *//p' "$PUBLIC_IDENTITY" 2>/dev/null | head -1 || echo "")
116
-
117
- python3 -c "
118
- import json
119
- d = {'admin': '${ADMIN_NAME:-unknown}', 'public': '${PUBLIC_NAME:-unknown}'}
120
- json.dump(d, open('$OUTPUT_DIR/identity/agents.json','w'), indent=2)
121
- print(f'[export] identity/agents.json written (admin={d[\"admin\"]}, public={d[\"public\"]})')
122
- "
123
-
124
- # PINs from taskmaster.json access section
125
- python3 -c "
126
- import json
127
- try:
128
- d = json.load(open('$TASKMASTER_JSON'))
129
- access = d.get('access', {})
130
- pins = {
131
- 'masterPin': access.get('masterPin'),
132
- 'workspacePins': access.get('pins', {})
133
- }
134
- # Only write if there are actual PINs
135
- if pins['masterPin'] or pins['workspacePins']:
136
- json.dump(pins, open('$OUTPUT_DIR/identity/pins.json','w'), indent=2)
137
- print(f'[export] identity/pins.json written (masterPin={\"set\" if pins[\"masterPin\"] else \"none\"})')
138
- else:
139
- print('[export] identity/pins.json skipped (no PINs configured)')
140
- except Exception as e:
141
- print(f'[export] WARN: could not extract PINs: {e}')
142
- "
143
-
144
- # ------------------------------------------------------------------
145
- # 3. Contacts — from memory/users/{phone}/ directories
146
- # ------------------------------------------------------------------
147
- USERS_DIR="$WORKSPACE_DIR/memory/users"
148
- CONTACT_COUNT=0
149
- ANON_SKIP_COUNT=0
150
-
151
- if [ -d "$USERS_DIR" ]; then
152
- for USER_DIR in "$USERS_DIR"/*/; do
153
- [ -d "$USER_DIR" ] || continue
154
- USER_KEY=$(basename "$USER_DIR")
155
-
156
- # Skip anonymous users — no phone number, no useful identity
157
- if [[ "$USER_KEY" == anon-* ]]; then
158
- ANON_SKIP_COUNT=$((ANON_SKIP_COUNT + 1))
159
- continue
160
- fi
161
-
162
- PROFILE="$USER_DIR/profile.md"
163
- if [ -f "$PROFILE" ]; then
164
- # Extract name from first markdown heading or first bold field
165
- python3 -c "
166
- import json, re, sys
167
-
168
- profile_path = '$PROFILE'
169
- user_key = '$USER_KEY'
170
-
171
- with open(profile_path, 'r') as f:
172
- content = f.read()
173
-
174
- # Extract givenName from first heading (# Name)
175
- heading = re.search(r'^#\s+(.+)', content, re.MULTILINE)
176
- given_name = heading.group(1).strip() if heading else None
177
-
178
- # If heading is generic like 'Customer Profile', try **Name:** field
179
- if given_name and given_name.lower() in ('customer profile', 'profile', 'user profile'):
180
- name_field = re.search(r'\*\*(?:Name|First name):\*\*\s*(.+)', content)
181
- given_name = name_field.group(1).strip() if name_field else None
182
-
183
- # Extract phone from profile or use directory name
184
- phone_field = re.search(r'\*\*Phone:\*\*\s*(.+)', content)
185
- phone = phone_field.group(1).strip() if phone_field else user_key
186
-
187
- # Extract role
188
- role_field = re.search(r'\*\*Role:\*\*\s*(.+)', content)
189
- role = role_field.group(1).strip() if role_field else None
190
-
191
- # Extract location
192
- loc_field = re.search(r'\*\*Location:\*\*\s*(.+)', content)
193
- location = loc_field.group(1).strip() if loc_field else None
194
-
195
- contact = {
196
- 'telephone': phone,
197
- 'source': 'taskmaster-migration'
198
- }
199
-
200
- if given_name and given_name != 'Customer Profile':
201
- # Split name into given/family if it contains a space
202
- parts = given_name.split(' ', 1)
203
- contact['givenName'] = parts[0]
204
- if len(parts) > 1:
205
- contact['familyName'] = parts[1]
206
- else:
207
- # No name — use phone as identifier, skip givenName
208
- # (import will skip contacts without givenName)
209
- pass
210
-
211
- if role:
212
- contact['jobTitle'] = role
213
- if location:
214
- contact['location'] = location
215
-
216
- # Include raw profile for reference
217
- contact['_profileContent'] = content
218
-
219
- # Write contact JSON
220
- safe_key = user_key.replace('+', 'plus-')
221
- json.dump(contact, open(f'$OUTPUT_DIR/contacts/{safe_key}.json', 'w'), indent=2)
222
- has_name = 'givenName' in contact
223
- print(f'[export] contact: {user_key} ({contact.get(\"givenName\", \"NO NAME\")})', file=sys.stderr)
224
- sys.exit(0 if has_name else 0)
225
- " 2>&1
226
- else
227
- # No profile.md — create minimal contact from directory name
228
- python3 -c "
229
- import json
230
- contact = {'telephone': '$USER_KEY', 'source': 'taskmaster-migration'}
231
- safe_key = '$USER_KEY'.replace('+', 'plus-')
232
- json.dump(contact, open(f'$OUTPUT_DIR/contacts/{safe_key}.json', 'w'), indent=2)
233
- print(f'[export] contact: $USER_KEY (no profile.md — phone only)')
234
- "
235
- fi
236
- CONTACT_COUNT=$((CONTACT_COUNT + 1))
237
- done
238
- fi
239
- echo "[export] contacts: $CONTACT_COUNT exported, $ANON_SKIP_COUNT anonymous skipped"
240
-
241
- # ------------------------------------------------------------------
242
- # 4. Memory — shared and admin knowledge files
243
- # ------------------------------------------------------------------
244
- SHARED_DIR="$WORKSPACE_DIR/memory/shared"
245
- SHARED_COUNT=0
246
- if [ -d "$SHARED_DIR" ]; then
247
- # Copy all files except cron-activity and media (media goes to media/public)
248
- find "$SHARED_DIR" -maxdepth 1 -type f | while read -r f; do
249
- cp "$f" "$OUTPUT_DIR/memory/shared/"
250
- echo "[export] memory/shared: $(basename "$f")"
251
- done
252
- SHARED_COUNT=$(find "$OUTPUT_DIR/memory/shared" -type f | wc -l | tr -d ' ')
253
- fi
254
- echo "[export] memory/shared: $SHARED_COUNT files"
255
-
256
- ADMIN_MEMORY="$WORKSPACE_DIR/agents/admin/memory/admin"
257
- ADMIN_MEM_COUNT=0
258
- if [ -d "$ADMIN_MEMORY" ]; then
259
- # Copy recursively, excluding cron-activity (Loop diary logs) and media (goes to media/)
260
- rsync -a --exclude='cron-activity' --exclude='media' "$ADMIN_MEMORY/" "$OUTPUT_DIR/memory/admin/" 2>/dev/null || \
261
- find "$ADMIN_MEMORY" -type f -not -path '*/cron-activity/*' -not -path '*/media/*' | while read -r f; do
262
- REL="${f#$ADMIN_MEMORY/}"
263
- mkdir -p "$OUTPUT_DIR/memory/admin/$(dirname "$REL")"
264
- cp "$f" "$OUTPUT_DIR/memory/admin/$REL"
265
- done
266
- ADMIN_MEM_COUNT=$(find "$OUTPUT_DIR/memory/admin" -type f 2>/dev/null | wc -l | tr -d ' ')
267
- fi
268
- echo "[export] memory/admin: $ADMIN_MEM_COUNT files"
269
-
270
- # Public agent memory
271
- PUBLIC_MEMORY="$WORKSPACE_DIR/agents/admin/memory/public"
272
- if [ -d "$PUBLIC_MEMORY" ]; then
273
- mkdir -p "$OUTPUT_DIR/memory/public"
274
- cp -r "$PUBLIC_MEMORY"/* "$OUTPUT_DIR/memory/public/" 2>/dev/null || true
275
- PUB_COUNT=$(find "$OUTPUT_DIR/memory/public" -type f 2>/dev/null | wc -l | tr -d ' ')
276
- echo "[export] memory/public: $PUB_COUNT files"
277
- fi
278
-
279
- # ------------------------------------------------------------------
280
- # 5. Conversations — admin, per-user, per-group
281
- # ------------------------------------------------------------------
282
-
283
- # Admin conversations
284
- ADMIN_CONVOS="$ADMIN_MEMORY/conversations"
285
- ADMIN_CONVO_COUNT=0
286
- if [ -d "$ADMIN_CONVOS" ]; then
287
- cp "$ADMIN_CONVOS"/*.md "$OUTPUT_DIR/conversations/admin/" 2>/dev/null || true
288
- ADMIN_CONVO_COUNT=$(find "$OUTPUT_DIR/conversations/admin" -type f 2>/dev/null | wc -l | tr -d ' ')
289
- fi
290
- echo "[export] conversations/admin: $ADMIN_CONVO_COUNT files"
291
-
292
- # Per-user conversations
293
- USER_CONVO_COUNT=0
294
- if [ -d "$USERS_DIR" ]; then
295
- for USER_DIR in "$USERS_DIR"/*/; do
296
- [ -d "$USER_DIR" ] || continue
297
- USER_KEY=$(basename "$USER_DIR")
298
- CONVO_DIR="$USER_DIR/conversations"
299
- if [ -d "$CONVO_DIR" ] && [ "$(ls -A "$CONVO_DIR" 2>/dev/null)" ]; then
300
- SAFE_KEY=$(echo "$USER_KEY" | sed 's/+/plus-/g')
301
- mkdir -p "$OUTPUT_DIR/conversations/users/$SAFE_KEY"
302
- cp "$CONVO_DIR"/*.md "$OUTPUT_DIR/conversations/users/$SAFE_KEY/" 2>/dev/null || true
303
- USER_CONVO_COUNT=$((USER_CONVO_COUNT + 1))
304
- fi
305
- done
306
- fi
307
- echo "[export] conversations/users: $USER_CONVO_COUNT directories"
308
-
309
- # Group conversations
310
- GROUP_DIR="$WORKSPACE_DIR/memory/groups"
311
- GROUP_CONVO_COUNT=0
312
- if [ -d "$GROUP_DIR" ]; then
313
- for GRP in "$GROUP_DIR"/*/; do
314
- [ -d "$GRP" ] || continue
315
- GRP_ID=$(basename "$GRP")
316
- CONVO_DIR="$GRP/conversations"
317
- if [ -d "$CONVO_DIR" ] && [ "$(ls -A "$CONVO_DIR" 2>/dev/null)" ]; then
318
- mkdir -p "$OUTPUT_DIR/conversations/groups/$GRP_ID"
319
- cp "$CONVO_DIR"/*.md "$OUTPUT_DIR/conversations/groups/$GRP_ID/" 2>/dev/null || true
320
- GROUP_CONVO_COUNT=$((GROUP_CONVO_COUNT + 1))
321
- fi
322
- # Group member files
323
- MEMBERS_DIR="$GRP/members"
324
- if [ -d "$MEMBERS_DIR" ] && [ "$(ls -A "$MEMBERS_DIR" 2>/dev/null)" ]; then
325
- mkdir -p "$OUTPUT_DIR/conversations/groups/$GRP_ID/members"
326
- cp "$MEMBERS_DIR"/* "$OUTPUT_DIR/conversations/groups/$GRP_ID/members/" 2>/dev/null || true
327
- fi
328
- done
329
- fi
330
- echo "[export] conversations/groups: $GROUP_CONVO_COUNT directories"
331
-
332
- # ------------------------------------------------------------------
333
- # 6. Media — admin uploads and shared media
334
- # ------------------------------------------------------------------
335
- ADMIN_UPLOADS="$WORKSPACE_DIR/agents/admin/uploads"
336
- ADMIN_MEDIA_COUNT=0
337
- if [ -d "$ADMIN_UPLOADS" ] && [ "$(ls -A "$ADMIN_UPLOADS" 2>/dev/null)" ]; then
338
- cp "$ADMIN_UPLOADS"/* "$OUTPUT_DIR/media/admin/" 2>/dev/null || true
339
- ADMIN_MEDIA_COUNT=$(find "$OUTPUT_DIR/media/admin" -type f 2>/dev/null | wc -l | tr -d ' ')
340
- fi
341
- echo "[export] media/admin: $ADMIN_MEDIA_COUNT files"
342
-
343
- # Shared media (e.g., PDFs in memory/shared/media/)
344
- SHARED_MEDIA="$WORKSPACE_DIR/memory/shared/media"
345
- PUBLIC_MEDIA_COUNT=0
346
- if [ -d "$SHARED_MEDIA" ] && [ "$(ls -A "$SHARED_MEDIA" 2>/dev/null)" ]; then
347
- cp "$SHARED_MEDIA"/* "$OUTPUT_DIR/media/public/" 2>/dev/null || true
348
- PUBLIC_MEDIA_COUNT=$(find "$OUTPUT_DIR/media/public" -type f 2>/dev/null | wc -l | tr -d ' ')
349
- fi
350
- echo "[export] media/public: $PUBLIC_MEDIA_COUNT files"
351
-
352
- # Admin memory media
353
- ADMIN_MEDIA_DIR="$ADMIN_MEMORY/media"
354
- if [ -d "$ADMIN_MEDIA_DIR" ] && [ "$(ls -A "$ADMIN_MEDIA_DIR" 2>/dev/null)" ]; then
355
- cp "$ADMIN_MEDIA_DIR"/* "$OUTPUT_DIR/media/admin/" 2>/dev/null || true
356
- # Recount after adding
357
- ADMIN_MEDIA_COUNT=$(find "$OUTPUT_DIR/media/admin" -type f 2>/dev/null | wc -l | tr -d ' ')
358
- echo "[export] media/admin (updated with memory/admin/media): $ADMIN_MEDIA_COUNT files"
359
- fi
360
-
361
- # ------------------------------------------------------------------
362
- # 7. Automations — workflow definitions (not cron-activity logs)
363
- # ------------------------------------------------------------------
364
- WORKFLOWS_DIR="$ADMIN_MEMORY/workflows"
365
- AUTOMATION_COUNT=0
366
- if [ -d "$WORKFLOWS_DIR" ] && [ "$(ls -A "$WORKFLOWS_DIR" 2>/dev/null)" ]; then
367
- cp "$WORKFLOWS_DIR"/* "$OUTPUT_DIR/automations/" 2>/dev/null || true
368
- AUTOMATION_COUNT=$(find "$OUTPUT_DIR/automations" -type f 2>/dev/null | wc -l | tr -d ' ')
369
- fi
370
- echo "[export] automations: $AUTOMATION_COUNT workflow definitions"
371
-
372
- # ------------------------------------------------------------------
373
- # Summary
374
- # ------------------------------------------------------------------
375
- TOTAL_CONTACTS=$CONTACT_COUNT
376
- TOTAL_MEMORY=$((SHARED_COUNT + ADMIN_MEM_COUNT))
377
- TOTAL_MEDIA=$((ADMIN_MEDIA_COUNT + PUBLIC_MEDIA_COUNT))
378
- TOTAL_CONVOS=$((ADMIN_CONVO_COUNT + USER_CONVO_COUNT + GROUP_CONVO_COUNT))
379
-
380
- echo ""
381
- echo "[export] =================================================="
382
- echo "[export] Bundle complete: $OUTPUT_DIR"
383
- echo "[export] Contacts: $TOTAL_CONTACTS (+ $ANON_SKIP_COUNT anonymous skipped)"
384
- echo "[export] Memory files: $TOTAL_MEMORY"
385
- echo "[export] Media files: $TOTAL_MEDIA"
386
- echo "[export] Conversations: $TOTAL_CONVOS directories"
387
- echo "[export] Automations: $AUTOMATION_COUNT"
388
- echo "[export] =================================================="
@@ -1,42 +0,0 @@
1
- import { loopPost, withTeamKey } from "../lib/loop-api.js";
2
-
3
- type Department = "sales" | "lettings";
4
- type RequestAction = "viewing" | "call-back" | "information";
5
-
6
- // ─── Loop API V2: POST /property/residential/{dept}/{id}/{action}
7
- // Actions: viewing, call-back, information
8
- // Request body: { name?, email?, phone?, message? }
9
- // Response: boolean success
10
- // ────────────────────────────────────────────────────────────────
11
- interface LoopBooleanResponse {
12
- success?: boolean;
13
- [key: string]: unknown;
14
- }
15
-
16
- export async function propertyRequest(params: {
17
- accountId: string;
18
- teamName: string;
19
- propertyId: number;
20
- department: Department;
21
- action: RequestAction;
22
- name?: string;
23
- email?: string;
24
- phone?: string;
25
- message?: string;
26
- }): Promise<string> {
27
- const { accountId, teamName, propertyId, department, action, ...body } = params;
28
-
29
- const result = await withTeamKey<LoopBooleanResponse>(
30
- accountId,
31
- teamName,
32
- "properties",
33
- "loop-property-request",
34
- async (apiKey) => {
35
- const path = `/property/residential/${department}/${propertyId}/${action}`;
36
- return loopPost<LoopBooleanResponse>(apiKey, path, body, "loop-property-request", teamName);
37
- }
38
- );
39
-
40
- const actionLabel = action === "call-back" ? "callback" : action;
41
- return `${actionLabel} request submitted for property ${propertyId} (${department}) via team "${teamName}".`;
42
- }